diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index 8a3f5d23f..9df95e2ff 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -11,6 +11,7 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.network.id.PacketIdFinder; import net.momirealms.craftengine.bukkit.plugin.network.id.PacketIds1_20; import net.momirealms.craftengine.bukkit.plugin.network.id.PacketIds1_20_5; +import net.momirealms.craftengine.bukkit.plugin.network.payload.PayloadHelper; import net.momirealms.craftengine.bukkit.plugin.reflection.leaves.LeavesReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.LibraryReflections; @@ -105,6 +106,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes this.packetIds = VersionHelper.isOrAbove1_20_5() ? new PacketIds1_20_5() : new PacketIds1_20(); // register packet handlers this.registerPacketHandlers(); + PayloadHelper.registerDataTypes(); // set up packet senders this.packetConsumer = FastNMS.INSTANCE::method$Connection$send; this.packetsConsumer = ((connection, packets, sendListener) -> { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index f3897953b..e5cf08ac7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -11,7 +11,6 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntList; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.TranslationArgument; import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture; import net.momirealms.craftengine.bukkit.api.event.FurnitureAttemptBreakEvent; @@ -29,8 +28,8 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.ProtectedFieldVisitor; import net.momirealms.craftengine.bukkit.plugin.network.handler.*; import net.momirealms.craftengine.bukkit.plugin.network.payload.DiscardedPayload; -import net.momirealms.craftengine.bukkit.plugin.network.payload.NetWorkDataTypes; import net.momirealms.craftengine.bukkit.plugin.network.payload.Payload; +import net.momirealms.craftengine.bukkit.plugin.network.payload.PayloadHelper; import net.momirealms.craftengine.bukkit.plugin.network.payload.UnknownPayload; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; @@ -235,7 +234,7 @@ public class PacketConsumers { int[] newMappingsMOD = Arrays.copyOf(newMappings, registrySize); for (Map.Entry entry : map.entrySet()) { newMappings[entry.getKey()] = entry.getValue(); - if (BlockStateUtils.isVanillaBlock(entry.getKey())) { + if (BlockStateUtils.isVanillaBlock((int) entry.getKey())) { newMappingsMOD[entry.getKey()] = entry.getValue(); } } @@ -325,7 +324,7 @@ public class PacketConsumers { FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(byteBuf); FriendlyByteBuf newBuf = new FriendlyByteBuf(Unpooled.buffer()); for (int i = 0, count = player.clientSideSectionCount(); i < count; i++) { - MCSection mcSection = new MCSection(SERVER_BLOCK_LIST, SERVER_BLOCK_LIST, BIOME_LIST); + MCSection mcSection = new MCSection(user.clientBlockList(), SERVER_BLOCK_LIST, BIOME_LIST); mcSection.readPacket(friendlyByteBuf); PalettedContainer container = mcSection.blockStateContainer(); Palette palette = container.data().palette(); @@ -348,7 +347,7 @@ public class PacketConsumers { FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(byteBuf); FriendlyByteBuf newBuf = new FriendlyByteBuf(Unpooled.buffer()); for (int i = 0, count = player.clientSideSectionCount(); i < count; i++) { - MCSection mcSection = new MCSection(CLIENT_BLOCK_LIST, SERVER_BLOCK_LIST, BIOME_LIST); + MCSection mcSection = new MCSection(user.clientBlockList(), SERVER_BLOCK_LIST, BIOME_LIST); mcSection.readPacket(friendlyByteBuf); PalettedContainer container = mcSection.blockStateContainer(); Palette palette = container.data().palette(); @@ -1523,7 +1522,7 @@ public class PacketConsumers { int entityId = FastNMS.INSTANCE.method$ClientboundEntityPositionSyncPacket$id(packet); EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); if (handler != null) { - handler.handleSyncEntityPosition((BukkitServerPlayer) user, event, packet); + handler.handleSyncEntityPosition(user, event, packet); } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundEntityPositionSyncPacket", e); @@ -1925,35 +1924,13 @@ public class PacketConsumers { Payload clientPayload; if (NetworkReflections.clazz$DiscardedPayload.isInstance(payload)) { clientPayload = DiscardedPayload.from(payload); - } else if (!VersionHelper.isOrAbove1_20_5() && NetworkReflections.clazz$UnknownPayload.isInstance(payload)) { + } else if (!VersionHelper.isOrAbove1_20_5() && NetworkReflections.clazz$ServerboundCustomPayloadPacket$UnknownPayload.isInstance(payload)) { clientPayload = UnknownPayload.from(payload); } else { return; } - if (clientPayload == null || !clientPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY)) - return; - FriendlyByteBuf buf = clientPayload.toBuffer(); - NetWorkDataTypes dataType = buf.readEnumConstant(NetWorkDataTypes.class); - if (dataType == NetWorkDataTypes.CLIENT_CUSTOM_BLOCK) { - int clientBlockRegistrySize = dataType.decode(buf); - int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize(); - if (clientBlockRegistrySize != serverBlockRegistrySize) { - user.kick(Component.translatable( - "disconnect.craftengine.block_registry_mismatch", - TranslationArgument.numeric(clientBlockRegistrySize), - TranslationArgument.numeric(serverBlockRegistrySize) - )); - return; - } - user.setClientModState(true); - } else if (dataType == NetWorkDataTypes.CANCEL_BLOCK_UPDATE) { - if (dataType.decode(buf)) { - FriendlyByteBuf bufPayload = new FriendlyByteBuf(Unpooled.buffer()); - bufPayload.writeEnumConstant(dataType); - dataType.encode(bufPayload, true); - user.sendCustomPayload(NetworkManager.MOD_CHANNEL_KEY, bufPayload.array()); - } - } + if (clientPayload == null || !clientPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY)) return; + PayloadHelper.handleReceiver(clientPayload, user); } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundCustomPayloadPacket", e); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/Data.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/Data.java new file mode 100644 index 000000000..5c3831807 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/Data.java @@ -0,0 +1,18 @@ +package net.momirealms.craftengine.bukkit.plugin.network.payload; + +import io.netty.buffer.ByteBuf; +import net.momirealms.craftengine.bukkit.plugin.network.payload.codec.NetworkCodec; +import net.momirealms.craftengine.bukkit.plugin.network.payload.codec.NetworkDecoder; +import net.momirealms.craftengine.bukkit.plugin.network.payload.codec.NetworkMemberEncoder; +import net.momirealms.craftengine.core.plugin.network.NetWorkUser; + +public interface Data { + + default void handle(NetWorkUser user) { + } + + static NetworkCodec codec(NetworkMemberEncoder networkMemberEncoder, NetworkDecoder networkDecoder) { + return NetworkCodec.ofMember(networkMemberEncoder, networkDecoder); + } + +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkCodec.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkCodec.java deleted file mode 100644 index 7fa1d4131..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkCodec.java +++ /dev/null @@ -1,22 +0,0 @@ -package net.momirealms.craftengine.bukkit.plugin.network.payload; - -import io.netty.buffer.ByteBuf; - -import java.util.function.Function; - -public interface NetWorkCodec extends NetWorkEncoder, NetWorkDecoder { - - default NetWorkCodec map(Function factory, Function getter) { - return new NetWorkCodec<>() { - @Override - public O decode(ByteBuf in) { - return factory.apply(NetWorkCodec.this.decode(in)); - } - - @Override - public void encode(ByteBuf out, O value) { - NetWorkCodec.this.encode(out, getter.apply(value)); - } - }; - } -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDataTypes.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDataTypes.java deleted file mode 100644 index 37da1618d..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDataTypes.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.momirealms.craftengine.bukkit.plugin.network.payload; - -import io.netty.buffer.ByteBuf; - -public enum NetWorkDataTypes { - CLIENT_CUSTOM_BLOCK(NetWorkCodecs.INTEGER), - CANCEL_BLOCK_UPDATE(NetWorkCodecs.BOOLEAN); - - private final NetWorkCodec codec; - - NetWorkDataTypes(NetWorkCodec codec) { - this.codec = codec; - } - - public NetWorkCodec codec() { - return codec; - } - - @SuppressWarnings("unchecked") - public V decode(ByteBuf buf) { - return (V) codec.decode(buf); - } - - @SuppressWarnings("unchecked") - public void encode(ByteBuf buf, V value) { - ((NetWorkCodec) codec).encode(buf, value); - } -} \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDecoder.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDecoder.java deleted file mode 100644 index fc3024db0..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDecoder.java +++ /dev/null @@ -1,7 +0,0 @@ -package net.momirealms.craftengine.bukkit.plugin.network.payload; - -import io.netty.buffer.ByteBuf; - -public interface NetWorkDecoder { - T decode(ByteBuf in); -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkEncoder.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkEncoder.java deleted file mode 100644 index 3c346115a..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkEncoder.java +++ /dev/null @@ -1,7 +0,0 @@ -package net.momirealms.craftengine.bukkit.plugin.network.payload; - -import io.netty.buffer.ByteBuf; - -public interface NetWorkEncoder { - void encode(ByteBuf out, T value); -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/PayloadHelper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/PayloadHelper.java new file mode 100644 index 000000000..b3cb840f3 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/PayloadHelper.java @@ -0,0 +1,69 @@ +package net.momirealms.craftengine.bukkit.plugin.network.payload; + +import io.netty.buffer.Unpooled; +import net.momirealms.craftengine.bukkit.plugin.network.payload.codec.NetworkCodec; +import net.momirealms.craftengine.bukkit.plugin.network.payload.protocol.CancelBlockUpdateData; +import net.momirealms.craftengine.bukkit.plugin.network.payload.protocol.ClientBlockStateSizeData; +import net.momirealms.craftengine.bukkit.plugin.network.payload.protocol.ClientCustomBlockData; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.network.NetWorkUser; +import net.momirealms.craftengine.core.plugin.network.NetworkManager; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +public class PayloadHelper { + private static final Map, Byte> classToType = new HashMap<>(); + private static final Map> typeToCodec = new HashMap<>(); + private static final AtomicInteger typeCounter = new AtomicInteger(0); + + public static void registerDataTypes() { + registerDataType(ClientCustomBlockData.class, ClientCustomBlockData.CODEC); + registerDataType(CancelBlockUpdateData.class, CancelBlockUpdateData.CODEC); + registerDataType(ClientBlockStateSizeData.class, ClientBlockStateSizeData.CODEC); + } + + @SuppressWarnings("unchecked") + private static void registerDataType(Class dataClass, NetworkCodec codec) { + if (classToType.containsKey(dataClass)) { + CraftEngine.instance().logger().warn("Duplicate data type class: " + dataClass.getName()); + return; + } + int next = typeCounter.getAndIncrement(); + if (next > 255) { + throw new IllegalStateException("Too many data types registered, byte index overflow (max 256)"); + } + byte type = (byte) next; + classToType.put((Class) dataClass, type); + typeToCodec.put(type, (NetworkCodec) codec); + } + + public static void sendData(NetWorkUser user, Data data) { + Class dataClass = data.getClass(); + Byte type = classToType.get(dataClass); + if (type == null) { + CraftEngine.instance().logger().warn("Unknown data type class: " + dataClass.getName()); + return; + } + NetworkCodec codec = typeToCodec.get(type); + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeByte(type); + codec.encode(buf, data); + user.sendCustomPayload(NetworkManager.MOD_CHANNEL_KEY, buf.array()); + } + + public static void handleReceiver(Payload payload, NetWorkUser user) { + FriendlyByteBuf buf = payload.toBuffer(); + byte type = buf.readByte(); + NetworkCodec codec = typeToCodec.get(type); + if (codec == null) { + CraftEngine.instance().logger().warn("Unknown data type received: " + type); + return; + } + + Data networkData = codec.decode(buf); + networkData.handle(user); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/UnknownPayload.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/UnknownPayload.java index 4143eea27..7eece0691 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/UnknownPayload.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/UnknownPayload.java @@ -11,8 +11,8 @@ public record UnknownPayload(Key channel, ByteBuf rawPayload) implements Payload public static UnknownPayload from(Object payload) { try { - Object id = NetworkReflections.field$UnknownPayload$id.get(payload); - ByteBuf data = (ByteBuf) NetworkReflections.field$UnknownPayload$data.get(payload); + Object id = NetworkReflections.field$ServerboundCustomPayloadPacket$UnknownPayload$id.get(payload); + ByteBuf data = (ByteBuf) NetworkReflections.field$ServerboundCustomPayloadPacket$UnknownPayload$data.get(payload); Key channel = KeyUtils.resourceLocationToKey(id); return new UnknownPayload(channel, data); } catch (Exception e) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/codec/NetworkCodec.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/codec/NetworkCodec.java new file mode 100644 index 000000000..3b60ae459 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/codec/NetworkCodec.java @@ -0,0 +1,32 @@ +package net.momirealms.craftengine.bukkit.plugin.network.payload.codec; + +import java.util.function.Function; + +public interface NetworkCodec extends NetworkEncoder, NetworkDecoder { + + default NetworkCodec map(Function factory, Function getter) { + return new NetworkCodec<>() { + @Override + public V decode(B in) { + return factory.apply(NetworkCodec.this.decode(in)); + } + + @Override + public void encode(B out, V value) { + NetworkCodec.this.encode(out, getter.apply(value)); + } + }; + } + + static NetworkCodec ofMember(final NetworkMemberEncoder networkMemberEncoder, final NetworkDecoder networkDecoder) { + return new NetworkCodec<>() { + public V decode(B in) { + return networkDecoder.decode(in); + } + + public void encode(B out, V value) { + networkMemberEncoder.encode(value, out); + } + }; + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkCodecs.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/codec/NetworkCodecs.java similarity index 88% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkCodecs.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/codec/NetworkCodecs.java index 4642578bc..0ff08bc1d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkCodecs.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/codec/NetworkCodecs.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.bukkit.plugin.network.payload; +package net.momirealms.craftengine.bukkit.plugin.network.payload.codec; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufInputStream; @@ -21,9 +21,9 @@ import java.util.OptionalInt; /** * 随便写了点方便后面重构和客户端通讯 */ -public interface NetWorkCodecs { +public interface NetworkCodecs { - NetWorkCodec BOOLEAN = new NetWorkCodec<>() { + NetworkCodec BOOLEAN = new NetworkCodec<>() { @Override public Boolean decode(ByteBuf in) { return in.readBoolean(); @@ -35,7 +35,7 @@ public interface NetWorkCodecs { } }; - NetWorkCodec BYTE = new NetWorkCodec<>() { + NetworkCodec BYTE = new NetworkCodec<>() { @Override public Byte decode(ByteBuf in) { return in.readByte(); @@ -47,9 +47,9 @@ public interface NetWorkCodecs { } }; - NetWorkCodec ROTATION_BYTE = BYTE.map(MCUtils::unpackDegrees, MCUtils::packDegrees); + NetworkCodec ROTATION_BYTE = BYTE.map(MCUtils::unpackDegrees, MCUtils::packDegrees); - NetWorkCodec SHORT = new NetWorkCodec<>() { + NetworkCodec SHORT = new NetworkCodec<>() { @Override public Short decode(ByteBuf in) { return in.readShort(); @@ -61,7 +61,7 @@ public interface NetWorkCodecs { } }; - NetWorkCodec UNSIGNED_SHORT = new NetWorkCodec<>() { + NetworkCodec UNSIGNED_SHORT = new NetworkCodec<>() { @Override public Integer decode(ByteBuf in) { return in.readUnsignedShort(); @@ -73,7 +73,7 @@ public interface NetWorkCodecs { } }; - NetWorkCodec INTEGER = new NetWorkCodec<>() { + NetworkCodec INTEGER = new NetworkCodec<>() { @Override public Integer decode(ByteBuf in) { return in.readInt(); @@ -85,7 +85,7 @@ public interface NetWorkCodecs { } }; - NetWorkCodec VAR_INTEGER = new NetWorkCodec<>() { + NetworkCodec VAR_INTEGER = new NetworkCodec<>() { @Override public Integer decode(ByteBuf in) { int result = 0; @@ -111,12 +111,12 @@ public interface NetWorkCodecs { } }; - NetWorkCodec OPTIONAL_VAR_INTEGER = VAR_INTEGER.map( + NetworkCodec OPTIONAL_VAR_INTEGER = VAR_INTEGER.map( integer -> integer == 0 ? OptionalInt.empty() : OptionalInt.of(integer - 1), optionalInt -> optionalInt.isPresent() ? optionalInt.getAsInt() + 1 : 0 ); - NetWorkCodec LONG = new NetWorkCodec<>() { + NetworkCodec LONG = new NetworkCodec<>() { @Override public Long decode(ByteBuf in) { return in.readLong(); @@ -128,7 +128,7 @@ public interface NetWorkCodecs { } }; - NetWorkCodec VAR_LONG = new NetWorkCodec<>() { + NetworkCodec VAR_LONG = new NetworkCodec<>() { @Override public Long decode(ByteBuf in) { long result = 0L; @@ -154,7 +154,7 @@ public interface NetWorkCodecs { } }; - NetWorkCodec FLOAT = new NetWorkCodec<>() { + NetworkCodec FLOAT = new NetworkCodec<>() { @Override public Float decode(ByteBuf in) { return in.readFloat(); @@ -166,7 +166,7 @@ public interface NetWorkCodecs { } }; - NetWorkCodec DOUBLE = new NetWorkCodec<>() { + NetworkCodec DOUBLE = new NetworkCodec<>() { @Override public Double decode(ByteBuf in) { return in.readDouble(); @@ -178,7 +178,7 @@ public interface NetWorkCodecs { } }; - NetWorkCodec BYTE_ARRAY = new NetWorkCodec<>() { + NetworkCodec BYTE_ARRAY = new NetworkCodec<>() { @Override public byte[] decode(ByteBuf in) { int maxSize = in.readableBytes(); @@ -199,7 +199,7 @@ public interface NetWorkCodecs { } }; - NetWorkCodec LONG_ARRAY = new NetWorkCodec<>() { + NetworkCodec LONG_ARRAY = new NetworkCodec<>() { @Override public long[] decode(ByteBuf in) { int arrayLength = VAR_INTEGER.decode(in); @@ -224,7 +224,7 @@ public interface NetWorkCodecs { } }; - NetWorkCodec STRING_UTF8 = new NetWorkCodec<>() { + NetworkCodec STRING_UTF8 = new NetworkCodec<>() { private static final int MAX_STRING_LENGTH = 32767; @Override @@ -273,7 +273,7 @@ public interface NetWorkCodecs { } }; - NetWorkCodec TAG = new NetWorkCodec<>() { + NetworkCodec TAG = new NetworkCodec<>() { @Override public Tag decode(ByteBuf in) { int initialIndex = in.readerIndex(); @@ -304,7 +304,7 @@ public interface NetWorkCodecs { } }; - NetWorkCodec COMPOUND_TAG = TAG.map(tag -> { + NetworkCodec COMPOUND_TAG = TAG.map(tag -> { if (tag instanceof CompoundTag compoundTag) { return compoundTag; } else { @@ -312,7 +312,7 @@ public interface NetWorkCodecs { } }, tag -> tag); - NetWorkCodec> OPTIONAL_COMPOUND_TAG = new NetWorkCodec<>() { + NetworkCodec> OPTIONAL_COMPOUND_TAG = new NetworkCodec<>() { @Override public Optional decode(ByteBuf in) { int initialIndex = in.readerIndex(); @@ -347,7 +347,7 @@ public interface NetWorkCodecs { } }; - NetWorkCodec VECTOR3F = new NetWorkCodec<>() { + NetworkCodec VECTOR3F = new NetworkCodec<>() { @Override public Vector3f decode(ByteBuf in) { return new Vector3f(in.readFloat(), in.readFloat(), in.readFloat()); @@ -361,7 +361,7 @@ public interface NetWorkCodecs { } }; - NetWorkCodec QUATERNIONF = new NetWorkCodec<>() { + NetworkCodec QUATERNIONF = new NetworkCodec<>() { @Override public Quaternionf decode(ByteBuf in) { return new Quaternionf(in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat()); @@ -376,9 +376,9 @@ public interface NetWorkCodecs { } }; - NetWorkCodec CONTAINER_ID = VAR_INTEGER; + NetworkCodec CONTAINER_ID = VAR_INTEGER; - NetWorkCodec RGB_COLOR = new NetWorkCodec<>() { + NetworkCodec RGB_COLOR = new NetworkCodec<>() { @Override public Integer decode(ByteBuf in) { return 255 << 24 | in.readByte() & 0xFF << 16 | in.readByte() & 0xFF << 8 | in.readByte() & 0xFF; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/codec/NetworkDecoder.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/codec/NetworkDecoder.java new file mode 100644 index 000000000..6116b6f62 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/codec/NetworkDecoder.java @@ -0,0 +1,5 @@ +package net.momirealms.craftengine.bukkit.plugin.network.payload.codec; + +public interface NetworkDecoder { + T decode(I in); +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/codec/NetworkEncoder.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/codec/NetworkEncoder.java new file mode 100644 index 000000000..eb17f0476 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/codec/NetworkEncoder.java @@ -0,0 +1,5 @@ +package net.momirealms.craftengine.bukkit.plugin.network.payload.codec; + +public interface NetworkEncoder { + void encode(O out, T value); +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/codec/NetworkMemberEncoder.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/codec/NetworkMemberEncoder.java new file mode 100644 index 000000000..49a60707f --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/codec/NetworkMemberEncoder.java @@ -0,0 +1,6 @@ +package net.momirealms.craftengine.bukkit.plugin.network.payload.codec; + +@FunctionalInterface +public interface NetworkMemberEncoder { + void encode(T object, O object2); +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/protocol/CancelBlockUpdateData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/protocol/CancelBlockUpdateData.java new file mode 100644 index 000000000..96fddb2c1 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/protocol/CancelBlockUpdateData.java @@ -0,0 +1,28 @@ +package net.momirealms.craftengine.bukkit.plugin.network.payload.protocol; + +import net.momirealms.craftengine.bukkit.plugin.network.payload.Data; +import net.momirealms.craftengine.bukkit.plugin.network.payload.PayloadHelper; +import net.momirealms.craftengine.bukkit.plugin.network.payload.codec.NetworkCodec; +import net.momirealms.craftengine.core.plugin.network.NetWorkUser; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; + +public record CancelBlockUpdateData(boolean enabled) implements Data { + public static final NetworkCodec CODEC = Data.codec( + CancelBlockUpdateData::encode, + CancelBlockUpdateData::new + ); + + private CancelBlockUpdateData(FriendlyByteBuf buf) { + this(buf.readBoolean()); + } + + private void encode(FriendlyByteBuf buf) { + buf.writeBoolean(this.enabled); + } + + @Override + public void handle(NetWorkUser user) { + if (!this.enabled) return; + PayloadHelper.sendData(user, this); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/protocol/ClientBlockStateSizeData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/protocol/ClientBlockStateSizeData.java new file mode 100644 index 000000000..ff20e81e9 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/protocol/ClientBlockStateSizeData.java @@ -0,0 +1,29 @@ +package net.momirealms.craftengine.bukkit.plugin.network.payload.protocol; + + +import net.momirealms.craftengine.bukkit.plugin.network.payload.Data; +import net.momirealms.craftengine.bukkit.plugin.network.payload.codec.NetworkCodec; +import net.momirealms.craftengine.core.plugin.network.NetWorkUser; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import net.momirealms.craftengine.core.util.IntIdentityList; + +public record ClientBlockStateSizeData(int blockStateSize) implements Data { + public static final NetworkCodec CODEC = Data.codec( + ClientBlockStateSizeData::encode, + ClientBlockStateSizeData::new + ); + + private ClientBlockStateSizeData(FriendlyByteBuf buf) { + this(buf.readInt()); + } + + private void encode(FriendlyByteBuf buf) { + buf.writeInt(this.blockStateSize); + } + + @Override + public void handle(NetWorkUser user) { + user.setClientBlockList(new IntIdentityList(this.blockStateSize)); + } + +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/protocol/ClientCustomBlockData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/protocol/ClientCustomBlockData.java new file mode 100644 index 000000000..c24d0f403 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/protocol/ClientCustomBlockData.java @@ -0,0 +1,42 @@ +package net.momirealms.craftengine.bukkit.plugin.network.payload.protocol; + + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TranslationArgument; +import net.momirealms.craftengine.bukkit.plugin.network.payload.Data; +import net.momirealms.craftengine.bukkit.plugin.network.payload.codec.NetworkCodec; +import net.momirealms.craftengine.bukkit.util.RegistryUtils; +import net.momirealms.craftengine.core.plugin.network.NetWorkUser; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import net.momirealms.craftengine.core.util.IntIdentityList; + +public record ClientCustomBlockData(int size) implements Data { + public static final NetworkCodec CODEC = Data.codec( + ClientCustomBlockData::encode, + ClientCustomBlockData::new + ); + + private ClientCustomBlockData(FriendlyByteBuf buf) { + this(buf.readInt()); + } + + private void encode(FriendlyByteBuf buf) { + buf.writeInt(this.size); + } + + @Override + public void handle(NetWorkUser user) { + int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize(); + if (this.size != serverBlockRegistrySize) { + user.kick(Component.translatable( + "disconnect.craftengine.block_registry_mismatch", + TranslationArgument.numeric(this.size), + TranslationArgument.numeric(serverBlockRegistrySize) + )); + return; + } + user.setClientModState(true); + user.setClientBlockList(new IntIdentityList(this.size)); + } + +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java index 4e421cff8..0da437e2a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java @@ -1635,7 +1635,7 @@ public final class NetworkReflections { } // 1.20.2~1.20.4 - public static final Class clazz$UnknownPayload = MiscUtils.requireNonNullIf( + public static final Class clazz$ServerboundCustomPayloadPacket$UnknownPayload = MiscUtils.requireNonNullIf( ReflectionUtils.getClazz( BukkitReflectionUtils.assembleMCClass("network.protocol.common.ServerboundCustomPayloadPacket$UnknownPayload") ), @@ -1643,17 +1643,17 @@ public final class NetworkReflections { ); // 1.20.2~1.20.4 - public static final Field field$UnknownPayload$id = Optional.ofNullable(clazz$UnknownPayload) + public static final Field field$ServerboundCustomPayloadPacket$UnknownPayload$id = Optional.ofNullable(clazz$ServerboundCustomPayloadPacket$UnknownPayload) .map(it -> ReflectionUtils.getDeclaredField(it, CoreReflections.clazz$ResourceLocation, 0)) .orElse(null); // 1.20.2~1.20.4 - public static final Field field$UnknownPayload$data = Optional.ofNullable(clazz$UnknownPayload) + public static final Field field$ServerboundCustomPayloadPacket$UnknownPayload$data = Optional.ofNullable(clazz$ServerboundCustomPayloadPacket$UnknownPayload) .map(it -> ReflectionUtils.getDeclaredField(it, ByteBuf.class, 0)) .orElse(null); // 1.20.2~1.20.4 - public static final Constructor constructor$UnknownPayload = Optional.ofNullable(clazz$UnknownPayload) + public static final Constructor constructor$ServerboundCustomPayloadPacket$UnknownPayload = Optional.ofNullable(clazz$ServerboundCustomPayloadPacket$UnknownPayload) .map(it -> ReflectionUtils.getConstructor(it, CoreReflections.clazz$ResourceLocation, ByteBuf.class)) .orElse(null); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index 9d4ebc8ee..04927c89c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -31,6 +31,7 @@ import net.momirealms.craftengine.core.plugin.network.ConnectionState; import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Direction; +import net.momirealms.craftengine.core.util.IntIdentityList; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; @@ -97,6 +98,7 @@ public class BukkitServerPlayer extends Player { private int resentSwingTick; // has fabric client mod or not private boolean hasClientMod = false; + private IntIdentityList blockList = new IntIdentityList(BlockStateUtils.vanillaStateSize()); // cache if player can break blocks private boolean clientSideCanBreak = true; // prevent AFK players from consuming too much CPU resource on predicting @@ -378,7 +380,7 @@ public class BukkitServerPlayer extends Player { if (VersionHelper.isOrAbove1_20_2()) { Object dataPayload; if (!VersionHelper.isOrAbove1_20_5()) { - dataPayload = NetworkReflections.constructor$UnknownPayload.newInstance(channelResourceLocation, Unpooled.wrappedBuffer(data)); + dataPayload = NetworkReflections.constructor$ServerboundCustomPayloadPacket$UnknownPayload.newInstance(channelResourceLocation, Unpooled.wrappedBuffer(data)); } else if (DiscardedPayload.useNewMethod) { dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelResourceLocation, data); } else { @@ -909,14 +911,26 @@ public class BukkitServerPlayer extends Player { return resentSwingTick == gameTicks(); } + @Override public boolean clientModEnabled() { return this.hasClientMod; } + @Override public void setClientModState(boolean enable) { this.hasClientMod = enable; } + @Override + public void setClientBlockList(IntIdentityList blockList) { + this.blockList = blockList; + } + + @Override + public IntIdentityList clientBlockList() { + return this.blockList; + } + @Override public void addResourcePackUUID(UUID uuid) { if (VersionHelper.isOrAbove1_20_3()) { diff --git a/common-files/src/main/resources/additional-real-blocks.yml b/common-files/src/main/resources/additional-real-blocks.yml index 1573d2fbf..58279f8a7 100644 --- a/common-files/src/main/resources/additional-real-blocks.yml +++ b/common-files/src/main/resources/additional-real-blocks.yml @@ -26,7 +26,7 @@ minecraft:cherry_sapling: 1 minecraft:anvil: 2 minecraft:chipped_anvil: 2 minecraft:damaged_anvil: 2 -minecraft:sugarcane: 14 +minecraft:sugar_cane: 14 minecraft:iron_trapdoor: 32 minecraft:acacia_trapdoor: 32 minecraft:oak_trapdoor: 32 diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index ba6327f9d..ce78d8bf1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -324,6 +324,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem // 结合variants JsonElement combinedVariant = GsonHelper.combine(variants); Map overrideMap = AbstractBlockManager.this.blockStateOverrides.computeIfAbsent(blockId, k -> new HashMap<>()); + AbstractBlockManager.this.tempVanillaBlockStateModels.put(registryId, combinedVariant); JsonElement previous = overrideMap.get(propertyNBT); if (previous != null && !previous.equals(combinedVariant)) { throw new LocalizedResourceConfigException("warning.config.block.state.model.conflict", GsonHelper.get().toJson(combinedVariant), blockState, GsonHelper.get().toJson(previous)); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java index 83661fd2f..32a50d188 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java @@ -4,6 +4,7 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.plugin.Plugin; +import net.momirealms.craftengine.core.util.IntIdentityList; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.ChunkPos; import org.jetbrains.annotations.ApiStatus; @@ -83,4 +84,8 @@ public interface NetWorkUser { void setChunkTrackStatus(ChunkPos chunkPos, boolean tracked); void clearTrackedChunks(); + + void setClientBlockList(IntIdentityList blockList); + + IntIdentityList clientBlockList(); }