mirror of
https://github.com/filoghost/HolographicDisplays.git
synced 2024-11-22 10:25:41 +01:00
Add support for Minecraft 1.20
This commit is contained in:
parent
2fa71ad3e0
commit
a3c82bfddf
@ -109,6 +109,11 @@
|
||||
<artifactId>holographicdisplays-nms-v1_19_r3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>holographicdisplays-nms-v1_20_r1</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
|
@ -40,7 +40,7 @@ public class HolographicDisplaysCore {
|
||||
try {
|
||||
nmsManager = NMSVersion.getCurrent().createNMSManager(errorCollector);
|
||||
} catch (UnknownVersionException e) {
|
||||
throw new PluginEnableException("Holographic Displays only supports Spigot from 1.8 to 1.19.3.");
|
||||
throw new PluginEnableException("Holographic Displays only supports Spigot from 1.8 to 1.20.");
|
||||
} catch (OutdatedVersionException e) {
|
||||
throw new PluginEnableException("Holographic Displays only supports " + e.getMinimumSupportedVersion() + " and above.");
|
||||
} catch (Throwable t) {
|
||||
|
@ -40,7 +40,8 @@ public enum NMSVersion {
|
||||
/* 1.18.2 */ v1_18_R2(errorCollector -> new me.filoghost.holographicdisplays.nms.v1_18_R2.VersionNMSManager(errorCollector)),
|
||||
/* 1.19 - 1.19.2 */ v1_19_R1(errorCollector -> new me.filoghost.holographicdisplays.nms.v1_19_R1.VersionNMSManager(errorCollector)),
|
||||
/* 1.19.3 */ v1_19_R2(errorCollector -> new me.filoghost.holographicdisplays.nms.v1_19_R2.VersionNMSManager(errorCollector)),
|
||||
/* 1.19.4 - ? */ v1_19_R3(errorCollector -> new me.filoghost.holographicdisplays.nms.v1_19_R3.VersionNMSManager(errorCollector)),
|
||||
/* 1.19.4 */ v1_19_R3(errorCollector -> new me.filoghost.holographicdisplays.nms.v1_19_R3.VersionNMSManager(errorCollector)),
|
||||
/* 1.20 - ? */ v1_20_R1(errorCollector -> new me.filoghost.holographicdisplays.nms.v1_20_R1.VersionNMSManager(errorCollector)),
|
||||
/* Other versions */ UNKNOWN(NMSManagerFactory.unknownVersion());
|
||||
|
||||
private static final NMSVersion CURRENT_VERSION = detectCurrentVersion();
|
||||
|
@ -30,6 +30,7 @@
|
||||
<module>v1_19_r1</module>
|
||||
<module>v1_19_r2</module>
|
||||
<module>v1_19_r3</module>
|
||||
<module>v1_20_r1</module>
|
||||
</modules>
|
||||
|
||||
<dependencies>
|
||||
|
36
nms/v1_20_r1/pom.xml
Normal file
36
nms/v1_20_r1/pom.xml
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>me.filoghost.holographicdisplays</groupId>
|
||||
<artifactId>holographicdisplays-nms</artifactId>
|
||||
<version>3.0.3-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>holographicdisplays-nms-v1_20_r1</artifactId>
|
||||
<name>HolographicDisplays NMS v1_20_R1</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>holographicdisplays-nms-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.20-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.joml</groupId>
|
||||
<artifactId>joml</artifactId>
|
||||
<version>1.10.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) filoghost and contributors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package me.filoghost.holographicdisplays.nms.v1_20_R1;
|
||||
|
||||
import io.netty.handler.codec.EncoderException;
|
||||
import net.minecraft.network.chat.IChatBaseComponent;
|
||||
import net.minecraft.network.syncher.DataWatcherRegistry;
|
||||
import net.minecraft.network.syncher.DataWatcherSerializer;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
class DataWatcherKey<T> {
|
||||
|
||||
private static final DataWatcherSerializer<Byte> BYTE_SERIALIZER = DataWatcherRegistry.a;
|
||||
private static final DataWatcherSerializer<Integer> INT_SERIALIZER = DataWatcherRegistry.b;
|
||||
private static final DataWatcherSerializer<Boolean> BOOLEAN_SERIALIZER = DataWatcherRegistry.k;
|
||||
private static final DataWatcherSerializer<ItemStack> ITEM_STACK_SERIALIZER = DataWatcherRegistry.h;
|
||||
private static final DataWatcherSerializer<Optional<IChatBaseComponent>> OPTIONAL_CHAT_COMPONENT_SERIALIZER = DataWatcherRegistry.g;
|
||||
|
||||
static final DataWatcherKey<Byte> ENTITY_STATUS = new DataWatcherKey<>(0, BYTE_SERIALIZER);
|
||||
static final DataWatcherKey<Optional<IChatBaseComponent>> CUSTOM_NAME = new DataWatcherKey<>(2, OPTIONAL_CHAT_COMPONENT_SERIALIZER);
|
||||
static final DataWatcherKey<Boolean> CUSTOM_NAME_VISIBILITY = new DataWatcherKey<>(3, BOOLEAN_SERIALIZER);
|
||||
static final DataWatcherKey<ItemStack> ITEM_STACK = new DataWatcherKey<>(8, ITEM_STACK_SERIALIZER);
|
||||
static final DataWatcherKey<Byte> ARMOR_STAND_STATUS = new DataWatcherKey<>(15, BYTE_SERIALIZER);
|
||||
static final DataWatcherKey<Integer> SLIME_SIZE = new DataWatcherKey<>(16, INT_SERIALIZER);
|
||||
|
||||
private final int index;
|
||||
private final DataWatcherSerializer<T> serializer;
|
||||
private final int serializerTypeID;
|
||||
|
||||
private DataWatcherKey(int index, DataWatcherSerializer<T> serializer) {
|
||||
this.index = index;
|
||||
this.serializer = serializer;
|
||||
this.serializerTypeID = DataWatcherRegistry.b(serializer);
|
||||
if (serializerTypeID < 0) {
|
||||
throw new EncoderException("Could not find serializer ID of " + serializer);
|
||||
}
|
||||
}
|
||||
|
||||
int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
DataWatcherSerializer<T> getSerializer() {
|
||||
return serializer;
|
||||
}
|
||||
|
||||
int getSerializerTypeID() {
|
||||
return serializerTypeID;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) filoghost and contributors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package me.filoghost.holographicdisplays.nms.v1_20_R1;
|
||||
|
||||
import me.filoghost.fcommons.Strings;
|
||||
import net.minecraft.network.chat.IChatBaseComponent;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.util.CraftChatMessage;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
abstract class DataWatcherPacketBuilder<T> {
|
||||
|
||||
private static final int MAX_CUSTOM_NAME_LENGTH = 5000;
|
||||
|
||||
private final PacketByteBuffer packetByteBuffer;
|
||||
|
||||
DataWatcherPacketBuilder(PacketByteBuffer packetByteBuffer) {
|
||||
this.packetByteBuffer = packetByteBuffer;
|
||||
}
|
||||
|
||||
DataWatcherPacketBuilder<T> setInvisible() {
|
||||
packetByteBuffer.writeDataWatcherEntry(DataWatcherKey.ENTITY_STATUS, (byte) 0x20); // Invisible
|
||||
return this;
|
||||
}
|
||||
|
||||
DataWatcherPacketBuilder<T> setArmorStandMarker() {
|
||||
setInvisible();
|
||||
packetByteBuffer.writeDataWatcherEntry(
|
||||
DataWatcherKey.ARMOR_STAND_STATUS, (byte) (0x01 | 0x02 | 0x08 | 0x10)); // Small, no gravity, no base plate, marker
|
||||
return this;
|
||||
}
|
||||
|
||||
DataWatcherPacketBuilder<T> setCustomName(String customName) {
|
||||
packetByteBuffer.writeDataWatcherEntry(DataWatcherKey.CUSTOM_NAME, getCustomNameDataWatcherValue(customName));
|
||||
packetByteBuffer.writeDataWatcherEntry(DataWatcherKey.CUSTOM_NAME_VISIBILITY, !Strings.isEmpty(customName));
|
||||
return this;
|
||||
}
|
||||
|
||||
private Optional<IChatBaseComponent> getCustomNameDataWatcherValue(String customName) {
|
||||
customName = Strings.truncate(customName, MAX_CUSTOM_NAME_LENGTH);
|
||||
if (!Strings.isEmpty(customName)) {
|
||||
return Optional.of(CraftChatMessage.fromString(customName, false, true)[0]);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
DataWatcherPacketBuilder<T> setItemStack(ItemStack itemStack) {
|
||||
packetByteBuffer.writeDataWatcherEntry(DataWatcherKey.ITEM_STACK, CraftItemStack.asNMSCopy(itemStack));
|
||||
return this;
|
||||
}
|
||||
|
||||
DataWatcherPacketBuilder<T> setSlimeSmall() {
|
||||
packetByteBuffer.writeDataWatcherEntry(DataWatcherKey.SLIME_SIZE, 1);
|
||||
return this;
|
||||
}
|
||||
|
||||
T build() {
|
||||
packetByteBuffer.writeDataWatcherEntriesEnd();
|
||||
return createPacket(packetByteBuffer);
|
||||
}
|
||||
|
||||
abstract T createPacket(PacketByteBuffer packetByteBuffer);
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) filoghost and contributors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package me.filoghost.holographicdisplays.nms.v1_20_R1;
|
||||
|
||||
import me.filoghost.holographicdisplays.nms.common.EntityID;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutEntityDestroy;
|
||||
|
||||
class EntityDestroyNMSPacket extends VersionNMSPacket {
|
||||
|
||||
private final Packet<?> rawPacket;
|
||||
|
||||
EntityDestroyNMSPacket(EntityID entityID) {
|
||||
PacketByteBuffer packetByteBuffer = PacketByteBuffer.get();
|
||||
|
||||
packetByteBuffer.writeVarIntArray(entityID.getNumericID());
|
||||
|
||||
this.rawPacket = new PacketPlayOutEntityDestroy(packetByteBuffer.getInternalSerializer());
|
||||
}
|
||||
|
||||
EntityDestroyNMSPacket(EntityID entityID1, EntityID entityID2) {
|
||||
PacketByteBuffer packetByteBuffer = PacketByteBuffer.get();
|
||||
|
||||
packetByteBuffer.writeVarIntArray(entityID1.getNumericID(), entityID2.getNumericID());
|
||||
|
||||
this.rawPacket = new PacketPlayOutEntityDestroy(packetByteBuffer.getInternalSerializer());
|
||||
}
|
||||
|
||||
@Override
|
||||
Packet<?> getRawPacket() {
|
||||
return rawPacket;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) filoghost and contributors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package me.filoghost.holographicdisplays.nms.v1_20_R1;
|
||||
|
||||
import me.filoghost.holographicdisplays.nms.common.EntityID;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata;
|
||||
|
||||
class EntityMetadataNMSPacket extends VersionNMSPacket {
|
||||
|
||||
private final Packet<?> rawPacket;
|
||||
|
||||
private EntityMetadataNMSPacket(PacketByteBuffer packetByteBuffer) {
|
||||
this.rawPacket = new PacketPlayOutEntityMetadata(packetByteBuffer.getInternalSerializer());
|
||||
}
|
||||
|
||||
@Override
|
||||
Packet<?> getRawPacket() {
|
||||
return rawPacket;
|
||||
}
|
||||
|
||||
public static DataWatcherPacketBuilder<EntityMetadataNMSPacket> builder(EntityID entityID) {
|
||||
PacketByteBuffer packetByteBuffer = PacketByteBuffer.get();
|
||||
packetByteBuffer.writeVarInt(entityID.getNumericID());
|
||||
return new Builder(packetByteBuffer);
|
||||
}
|
||||
|
||||
|
||||
private static class Builder extends DataWatcherPacketBuilder<EntityMetadataNMSPacket> {
|
||||
|
||||
private Builder(PacketByteBuffer packetByteBuffer) {
|
||||
super(packetByteBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
EntityMetadataNMSPacket createPacket(PacketByteBuffer packetByteBuffer) {
|
||||
return new EntityMetadataNMSPacket(packetByteBuffer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) filoghost and contributors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package me.filoghost.holographicdisplays.nms.v1_20_R1;
|
||||
|
||||
import me.filoghost.holographicdisplays.nms.common.EntityID;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutMount;
|
||||
|
||||
class EntityMountNMSPacket extends VersionNMSPacket {
|
||||
|
||||
private final Packet<?> rawPacket;
|
||||
|
||||
EntityMountNMSPacket(EntityID vehicleEntityID, EntityID passengerEntityID) {
|
||||
PacketByteBuffer packetByteBuffer = PacketByteBuffer.get();
|
||||
|
||||
packetByteBuffer.writeVarInt(vehicleEntityID.getNumericID());
|
||||
packetByteBuffer.writeVarIntArray(passengerEntityID.getNumericID());
|
||||
|
||||
this.rawPacket = new PacketPlayOutMount(packetByteBuffer.getInternalSerializer());
|
||||
}
|
||||
|
||||
@Override
|
||||
Packet<?> getRawPacket() {
|
||||
return rawPacket;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) filoghost and contributors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package me.filoghost.holographicdisplays.nms.v1_20_R1;
|
||||
|
||||
import me.filoghost.holographicdisplays.common.PositionCoordinates;
|
||||
import me.filoghost.holographicdisplays.nms.common.EntityID;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutSpawnEntity;
|
||||
|
||||
class EntitySpawnNMSPacket extends VersionNMSPacket {
|
||||
|
||||
private final Packet<?> rawPacket;
|
||||
|
||||
EntitySpawnNMSPacket(EntityID entityID, int entityTypeID, PositionCoordinates position, double positionOffsetY) {
|
||||
PacketByteBuffer packetByteBuffer = PacketByteBuffer.get();
|
||||
|
||||
packetByteBuffer.writeVarInt(entityID.getNumericID());
|
||||
packetByteBuffer.writeUUID(entityID.getUUID());
|
||||
packetByteBuffer.writeVarInt(entityTypeID);
|
||||
|
||||
// Position
|
||||
packetByteBuffer.writeDouble(position.getX());
|
||||
packetByteBuffer.writeDouble(position.getY() + positionOffsetY);
|
||||
packetByteBuffer.writeDouble(position.getZ());
|
||||
|
||||
// Rotation
|
||||
packetByteBuffer.writeByte(0);
|
||||
packetByteBuffer.writeByte(0);
|
||||
|
||||
// Object data
|
||||
if (entityTypeID == EntityTypeID.ITEM) {
|
||||
packetByteBuffer.writeInt(1); // Velocity is present and zero (otherwise by default a random velocity is applied)
|
||||
} else {
|
||||
packetByteBuffer.writeInt(0);
|
||||
}
|
||||
|
||||
// Velocity
|
||||
packetByteBuffer.writeShort(0);
|
||||
packetByteBuffer.writeShort(0);
|
||||
packetByteBuffer.writeShort(0);
|
||||
|
||||
this.rawPacket = new PacketPlayOutSpawnEntity(packetByteBuffer.getInternalSerializer());
|
||||
}
|
||||
|
||||
@Override
|
||||
Packet<?> getRawPacket() {
|
||||
return rawPacket;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) filoghost and contributors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package me.filoghost.holographicdisplays.nms.v1_20_R1;
|
||||
|
||||
import me.filoghost.holographicdisplays.common.PositionCoordinates;
|
||||
import me.filoghost.holographicdisplays.nms.common.EntityID;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutEntityTeleport;
|
||||
|
||||
class EntityTeleportNMSPacket extends VersionNMSPacket {
|
||||
|
||||
private final Packet<?> rawPacket;
|
||||
|
||||
EntityTeleportNMSPacket(EntityID entityID, PositionCoordinates position, double positionOffsetY) {
|
||||
PacketByteBuffer packetByteBuffer = PacketByteBuffer.get();
|
||||
|
||||
packetByteBuffer.writeVarInt(entityID.getNumericID());
|
||||
|
||||
// Position
|
||||
packetByteBuffer.writeDouble(position.getX());
|
||||
packetByteBuffer.writeDouble(position.getY() + positionOffsetY);
|
||||
packetByteBuffer.writeDouble(position.getZ());
|
||||
|
||||
// Rotation
|
||||
packetByteBuffer.writeByte(0);
|
||||
packetByteBuffer.writeByte(0);
|
||||
|
||||
// On ground
|
||||
packetByteBuffer.writeBoolean(false);
|
||||
|
||||
this.rawPacket = new PacketPlayOutEntityTeleport(packetByteBuffer.getInternalSerializer());
|
||||
}
|
||||
|
||||
@Override
|
||||
Packet<?> getRawPacket() {
|
||||
return rawPacket;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (C) filoghost and contributors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package me.filoghost.holographicdisplays.nms.v1_20_R1;
|
||||
|
||||
class EntityTypeID {
|
||||
|
||||
static final int ARMOR_STAND = 2;
|
||||
static final int ITEM = 54;
|
||||
static final int SLIME = 88;
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) filoghost and contributors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package me.filoghost.holographicdisplays.nms.v1_20_R1;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import me.filoghost.fcommons.logging.Log;
|
||||
import me.filoghost.fcommons.reflection.ReflectField;
|
||||
import me.filoghost.holographicdisplays.nms.common.NMSErrors;
|
||||
import me.filoghost.holographicdisplays.nms.common.PacketListener;
|
||||
import net.minecraft.network.protocol.game.PacketPlayInUseEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
class InboundPacketHandler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
public static final String HANDLER_NAME = "holographic_displays_listener";
|
||||
private static final ReflectField<Integer> ENTITY_ID_FIELD = ReflectField.lookup(int.class, PacketPlayInUseEntity.class, "a");
|
||||
|
||||
private final Player player;
|
||||
private final PacketListener packetListener;
|
||||
|
||||
InboundPacketHandler(Player player, PacketListener packetListener) {
|
||||
this.player = player;
|
||||
this.packetListener = packetListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext context, Object packet) throws Exception {
|
||||
try {
|
||||
if (packet instanceof PacketPlayInUseEntity) {
|
||||
int entityID = ENTITY_ID_FIELD.get(packet);
|
||||
boolean cancel = packetListener.onAsyncEntityInteract(player, entityID);
|
||||
if (cancel) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Log.warning(NMSErrors.EXCEPTION_ON_PACKET_READ, t);
|
||||
}
|
||||
super.channelRead(context, packet);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) filoghost and contributors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package me.filoghost.holographicdisplays.nms.v1_20_R1;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.network.PacketDataSerializer;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
class PacketByteBuffer {
|
||||
|
||||
private static final PacketByteBuffer INSTANCE = new PacketByteBuffer();
|
||||
|
||||
private final PacketDataSerializer serializer;
|
||||
|
||||
static PacketByteBuffer get() {
|
||||
INSTANCE.clear();
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private PacketByteBuffer() {
|
||||
this.serializer = new PacketDataSerializer(Unpooled.buffer());
|
||||
}
|
||||
|
||||
void writeBoolean(boolean flag) {
|
||||
serializer.writeBoolean(flag);
|
||||
}
|
||||
|
||||
void writeByte(int i) {
|
||||
serializer.writeByte(i);
|
||||
}
|
||||
|
||||
void writeShort(int i) {
|
||||
serializer.writeShort(i);
|
||||
}
|
||||
|
||||
void writeInt(int i) {
|
||||
serializer.writeInt(i);
|
||||
}
|
||||
|
||||
void writeDouble(double d) {
|
||||
serializer.writeDouble(d);
|
||||
}
|
||||
|
||||
void writeVarInt(int i) {
|
||||
serializer.d(i);
|
||||
}
|
||||
|
||||
void writeVarIntArray(int i1) {
|
||||
writeVarInt(1);
|
||||
writeVarInt(i1);
|
||||
}
|
||||
|
||||
void writeVarIntArray(int i1, int i2) {
|
||||
writeVarInt(2);
|
||||
writeVarInt(i1);
|
||||
writeVarInt(i2);
|
||||
}
|
||||
|
||||
void writeUUID(UUID uuid) {
|
||||
serializer.a(uuid);
|
||||
}
|
||||
|
||||
<T> void writeDataWatcherEntry(DataWatcherKey<T> key, T value) {
|
||||
serializer.writeByte(key.getIndex());
|
||||
writeVarInt(key.getSerializerTypeID());
|
||||
key.getSerializer().a(serializer, value);
|
||||
}
|
||||
|
||||
void writeDataWatcherEntriesEnd() {
|
||||
serializer.writeByte(0xFF);
|
||||
}
|
||||
|
||||
public PacketDataSerializer getInternalSerializer() {
|
||||
return serializer;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
serializer.clear();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) filoghost and contributors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package me.filoghost.holographicdisplays.nms.v1_20_R1;
|
||||
|
||||
import me.filoghost.holographicdisplays.common.PositionCoordinates;
|
||||
import me.filoghost.holographicdisplays.nms.common.EntityID;
|
||||
import me.filoghost.holographicdisplays.nms.common.PacketGroup;
|
||||
import me.filoghost.holographicdisplays.nms.common.entity.ClickableNMSPacketEntity;
|
||||
|
||||
class VersionClickableNMSPacketEntity implements ClickableNMSPacketEntity {
|
||||
|
||||
private final EntityID slimeID;
|
||||
|
||||
VersionClickableNMSPacketEntity(EntityID slimeID) {
|
||||
this.slimeID = slimeID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityID getID() {
|
||||
return slimeID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketGroup newSpawnPackets(PositionCoordinates position) {
|
||||
return PacketGroup.of(
|
||||
new EntitySpawnNMSPacket(slimeID, EntityTypeID.SLIME, position, SLIME_Y_OFFSET),
|
||||
EntityMetadataNMSPacket.builder(slimeID)
|
||||
.setInvisible()
|
||||
.setSlimeSmall() // Required for a correct client-side collision box
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketGroup newTeleportPackets(PositionCoordinates position) {
|
||||
return new EntityTeleportNMSPacket(slimeID, position, SLIME_Y_OFFSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketGroup newDestroyPackets() {
|
||||
return new EntityDestroyNMSPacket(slimeID);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) filoghost and contributors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package me.filoghost.holographicdisplays.nms.v1_20_R1;
|
||||
|
||||
import me.filoghost.holographicdisplays.common.PositionCoordinates;
|
||||
import me.filoghost.holographicdisplays.nms.common.EntityID;
|
||||
import me.filoghost.holographicdisplays.nms.common.PacketGroup;
|
||||
import me.filoghost.holographicdisplays.nms.common.entity.ItemNMSPacketEntity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
class VersionItemNMSPacketEntity implements ItemNMSPacketEntity {
|
||||
|
||||
private final EntityID itemID;
|
||||
private final EntityID vehicleID;
|
||||
|
||||
VersionItemNMSPacketEntity(EntityID itemID, EntityID vehicleID) {
|
||||
this.itemID = itemID;
|
||||
this.vehicleID = vehicleID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketGroup newSpawnPackets(PositionCoordinates position, ItemStack itemStack) {
|
||||
return PacketGroup.of(
|
||||
new EntitySpawnNMSPacket(vehicleID, EntityTypeID.ARMOR_STAND, position, ITEM_Y_OFFSET),
|
||||
EntityMetadataNMSPacket.builder(vehicleID)
|
||||
.setArmorStandMarker()
|
||||
.build(),
|
||||
new EntitySpawnNMSPacket(itemID, EntityTypeID.ITEM, position, ITEM_Y_OFFSET),
|
||||
EntityMetadataNMSPacket.builder(itemID)
|
||||
.setItemStack(itemStack)
|
||||
.build(),
|
||||
new EntityMountNMSPacket(vehicleID, itemID)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketGroup newChangePackets(ItemStack itemStack) {
|
||||
return EntityMetadataNMSPacket.builder(itemID)
|
||||
.setItemStack(itemStack)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketGroup newTeleportPackets(PositionCoordinates position) {
|
||||
return new EntityTeleportNMSPacket(vehicleID, position, ITEM_Y_OFFSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketGroup newDestroyPackets() {
|
||||
return new EntityDestroyNMSPacket(itemID, vehicleID);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) filoghost and contributors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package me.filoghost.holographicdisplays.nms.v1_20_R1;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import me.filoghost.fcommons.logging.ErrorCollector;
|
||||
import me.filoghost.fcommons.logging.Log;
|
||||
import me.filoghost.fcommons.reflection.ReflectField;
|
||||
import me.filoghost.holographicdisplays.nms.common.EntityID;
|
||||
import me.filoghost.holographicdisplays.nms.common.FallbackEntityIDGenerator;
|
||||
import me.filoghost.holographicdisplays.nms.common.NMSErrors;
|
||||
import me.filoghost.holographicdisplays.nms.common.NMSManager;
|
||||
import me.filoghost.holographicdisplays.nms.common.PacketListener;
|
||||
import me.filoghost.holographicdisplays.nms.common.entity.ClickableNMSPacketEntity;
|
||||
import me.filoghost.holographicdisplays.nms.common.entity.ItemNMSPacketEntity;
|
||||
import me.filoghost.holographicdisplays.nms.common.entity.TextNMSPacketEntity;
|
||||
import net.minecraft.network.NetworkManager;
|
||||
import net.minecraft.server.network.PlayerConnection;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class VersionNMSManager implements NMSManager {
|
||||
|
||||
private static final ReflectField<AtomicInteger> ENTITY_ID_COUNTER_FIELD = ReflectField.lookup(AtomicInteger.class, Entity.class, "d");
|
||||
private static final ReflectField<NetworkManager> NETWORK_MANAGER_FIELD = ReflectField.lookup(NetworkManager.class, PlayerConnection.class, "h");
|
||||
private final Supplier<Integer> entityIDGenerator;
|
||||
|
||||
public VersionNMSManager(ErrorCollector errorCollector) {
|
||||
this.entityIDGenerator = getEntityIDGenerator(errorCollector);
|
||||
|
||||
// Force initialization of class to eventually throw exceptions early
|
||||
DataWatcherKey.ENTITY_STATUS.getIndex();
|
||||
}
|
||||
|
||||
private Supplier<Integer> getEntityIDGenerator(ErrorCollector errorCollector) {
|
||||
try {
|
||||
AtomicInteger nmsEntityIDCounter = ENTITY_ID_COUNTER_FIELD.getStatic();
|
||||
return nmsEntityIDCounter::incrementAndGet;
|
||||
} catch (ReflectiveOperationException e) {
|
||||
errorCollector.add(e, NMSErrors.EXCEPTION_GETTING_ENTITY_ID_GENERATOR);
|
||||
return new FallbackEntityIDGenerator();
|
||||
}
|
||||
}
|
||||
|
||||
private EntityID newEntityID() {
|
||||
return new EntityID(entityIDGenerator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextNMSPacketEntity newTextPacketEntity() {
|
||||
return new VersionTextNMSPacketEntity(newEntityID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemNMSPacketEntity newItemPacketEntity() {
|
||||
return new VersionItemNMSPacketEntity(newEntityID(), newEntityID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClickableNMSPacketEntity newClickablePacketEntity() {
|
||||
return new VersionClickableNMSPacketEntity(newEntityID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectPacketListener(Player player, PacketListener packetListener) {
|
||||
modifyPipeline(player, (ChannelPipeline pipeline) -> {
|
||||
ChannelHandler currentListener = pipeline.get(InboundPacketHandler.HANDLER_NAME);
|
||||
if (currentListener != null) {
|
||||
pipeline.remove(InboundPacketHandler.HANDLER_NAME);
|
||||
}
|
||||
pipeline.addBefore("packet_handler", InboundPacketHandler.HANDLER_NAME, new InboundPacketHandler(player, packetListener));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninjectPacketListener(Player player) {
|
||||
modifyPipeline(player, (ChannelPipeline pipeline) -> {
|
||||
ChannelHandler currentListener = pipeline.get(InboundPacketHandler.HANDLER_NAME);
|
||||
if (currentListener != null) {
|
||||
pipeline.remove(InboundPacketHandler.HANDLER_NAME);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Modifying the pipeline in the main thread can cause deadlocks, delays and other concurrency issues,
|
||||
* which can be avoided by using the event loop. Thanks to ProtocolLib for this insight.
|
||||
*/
|
||||
private void modifyPipeline(Player player, Consumer<ChannelPipeline> pipelineModifierTask) {
|
||||
PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().c;
|
||||
NetworkManager networkManager;
|
||||
try {
|
||||
networkManager = NETWORK_MANAGER_FIELD.get(playerConnection);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
Log.warning(NMSErrors.EXCEPTION_MODIFYING_CHANNEL_PIPELINE, e);
|
||||
return;
|
||||
}
|
||||
Channel channel = networkManager.m;
|
||||
|
||||
channel.eventLoop().execute(() -> {
|
||||
if (!player.isOnline()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
pipelineModifierTask.accept(channel.pipeline());
|
||||
} catch (Exception e) {
|
||||
Log.warning(NMSErrors.EXCEPTION_MODIFYING_CHANNEL_PIPELINE, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) filoghost and contributors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package me.filoghost.holographicdisplays.nms.v1_20_R1;
|
||||
|
||||
import me.filoghost.holographicdisplays.nms.common.PacketGroup;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
abstract class VersionNMSPacket implements PacketGroup {
|
||||
|
||||
@Override
|
||||
public void sendTo(Player player) {
|
||||
((CraftPlayer) player).getHandle().c.a(getRawPacket());
|
||||
}
|
||||
|
||||
abstract Packet<?> getRawPacket();
|
||||
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) filoghost and contributors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package me.filoghost.holographicdisplays.nms.v1_20_R1;
|
||||
|
||||
import me.filoghost.holographicdisplays.common.PositionCoordinates;
|
||||
import me.filoghost.holographicdisplays.nms.common.EntityID;
|
||||
import me.filoghost.holographicdisplays.nms.common.IndividualTextPacketGroup;
|
||||
import me.filoghost.holographicdisplays.nms.common.PacketGroup;
|
||||
import me.filoghost.holographicdisplays.nms.common.entity.TextNMSPacketEntity;
|
||||
|
||||
class VersionTextNMSPacketEntity implements TextNMSPacketEntity {
|
||||
|
||||
private final EntityID armorStandID;
|
||||
|
||||
VersionTextNMSPacketEntity(EntityID armorStandID) {
|
||||
this.armorStandID = armorStandID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketGroup newSpawnPackets(PositionCoordinates position, String text) {
|
||||
return PacketGroup.of(
|
||||
new EntitySpawnNMSPacket(armorStandID, EntityTypeID.ARMOR_STAND, position, ARMOR_STAND_Y_OFFSET),
|
||||
EntityMetadataNMSPacket.builder(armorStandID)
|
||||
.setArmorStandMarker()
|
||||
.setCustomName(text)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IndividualTextPacketGroup newSpawnPackets(PositionCoordinates position) {
|
||||
return IndividualTextPacketGroup.of(
|
||||
new EntitySpawnNMSPacket(armorStandID, EntityTypeID.ARMOR_STAND, position, ARMOR_STAND_Y_OFFSET),
|
||||
(String text) -> EntityMetadataNMSPacket.builder(armorStandID)
|
||||
.setArmorStandMarker()
|
||||
.setCustomName(text)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketGroup newChangePackets(String text) {
|
||||
return EntityMetadataNMSPacket.builder(armorStandID)
|
||||
.setCustomName(text)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IndividualTextPacketGroup newChangePackets() {
|
||||
return IndividualTextPacketGroup.of(
|
||||
(String text) -> EntityMetadataNMSPacket.builder(armorStandID)
|
||||
.setCustomName(text)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketGroup newTeleportPackets(PositionCoordinates position) {
|
||||
return new EntityTeleportNMSPacket(armorStandID, position, ARMOR_STAND_Y_OFFSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketGroup newDestroyPackets() {
|
||||
return new EntityDestroyNMSPacket(armorStandID);
|
||||
}
|
||||
|
||||
}
|
6
pom.xml
6
pom.xml
@ -201,6 +201,12 @@
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>holographicdisplays-nms-v1_20_r1</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
|
Loading…
Reference in New Issue
Block a user