9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-24 09:29:33 +00:00

feat(network): 适配客户端模组的变动

This commit is contained in:
jhqwqmc
2025-09-01 01:46:38 +08:00
parent 16334e0c88
commit 4f864b9d9d
22 changed files with 296 additions and 127 deletions

View File

@@ -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) -> {

View File

@@ -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<Integer, Integer> 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<Integer> container = mcSection.blockStateContainer();
Palette<Integer> 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<Integer> container = mcSection.blockStateContainer();
Palette<Integer> 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);
}

View File

@@ -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 <B extends ByteBuf, T extends Data> NetworkCodec<B, T> codec(NetworkMemberEncoder<B, T> networkMemberEncoder, NetworkDecoder<B, T> networkDecoder) {
return NetworkCodec.ofMember(networkMemberEncoder, networkDecoder);
}
}

View File

@@ -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<T> extends NetWorkEncoder<T>, NetWorkDecoder<T> {
default <O> NetWorkCodec<O> map(Function<? super T, ? extends O> factory, Function<? super O, ? extends T> 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));
}
};
}
}

View File

@@ -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> V decode(ByteBuf buf) {
return (V) codec.decode(buf);
}
@SuppressWarnings("unchecked")
public <V> void encode(ByteBuf buf, V value) {
((NetWorkCodec<V>) codec).encode(buf, value);
}
}

View File

@@ -1,7 +0,0 @@
package net.momirealms.craftengine.bukkit.plugin.network.payload;
import io.netty.buffer.ByteBuf;
public interface NetWorkDecoder<T> {
T decode(ByteBuf in);
}

View File

@@ -1,7 +0,0 @@
package net.momirealms.craftengine.bukkit.plugin.network.payload;
import io.netty.buffer.ByteBuf;
public interface NetWorkEncoder<T> {
void encode(ByteBuf out, T value);
}

View File

@@ -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<Class<Data>, Byte> classToType = new HashMap<>();
private static final Map<Byte, NetworkCodec<FriendlyByteBuf, Data>> 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 <T extends Data> void registerDataType(Class<T> dataClass, NetworkCodec<FriendlyByteBuf, T> 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<Data>) dataClass, type);
typeToCodec.put(type, (NetworkCodec<FriendlyByteBuf, Data>) codec);
}
public static void sendData(NetWorkUser user, Data data) {
Class<? extends Data> dataClass = data.getClass();
Byte type = classToType.get(dataClass);
if (type == null) {
CraftEngine.instance().logger().warn("Unknown data type class: " + dataClass.getName());
return;
}
NetworkCodec<FriendlyByteBuf, Data> 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<FriendlyByteBuf, Data> 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);
}
}

View File

@@ -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) {

View File

@@ -0,0 +1,32 @@
package net.momirealms.craftengine.bukkit.plugin.network.payload.codec;
import java.util.function.Function;
public interface NetworkCodec<B, T> extends NetworkEncoder<B, T>, NetworkDecoder<B, T> {
default <V> NetworkCodec<B, V> map(Function<? super T, ? extends V> factory, Function<? super V, ? extends T> 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 <B, V> NetworkCodec<B, V> ofMember(final NetworkMemberEncoder<B, V> networkMemberEncoder, final NetworkDecoder<B, V> networkDecoder) {
return new NetworkCodec<>() {
public V decode(B in) {
return networkDecoder.decode(in);
}
public void encode(B out, V value) {
networkMemberEncoder.encode(value, out);
}
};
}
}

View File

@@ -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> BOOLEAN = new NetWorkCodec<>() {
NetworkCodec<ByteBuf, Boolean> BOOLEAN = new NetworkCodec<>() {
@Override
public Boolean decode(ByteBuf in) {
return in.readBoolean();
@@ -35,7 +35,7 @@ public interface NetWorkCodecs {
}
};
NetWorkCodec<Byte> BYTE = new NetWorkCodec<>() {
NetworkCodec<ByteBuf, Byte> BYTE = new NetworkCodec<>() {
@Override
public Byte decode(ByteBuf in) {
return in.readByte();
@@ -47,9 +47,9 @@ public interface NetWorkCodecs {
}
};
NetWorkCodec<Float> ROTATION_BYTE = BYTE.map(MCUtils::unpackDegrees, MCUtils::packDegrees);
NetworkCodec<ByteBuf, Float> ROTATION_BYTE = BYTE.map(MCUtils::unpackDegrees, MCUtils::packDegrees);
NetWorkCodec<Short> SHORT = new NetWorkCodec<>() {
NetworkCodec<ByteBuf, Short> SHORT = new NetworkCodec<>() {
@Override
public Short decode(ByteBuf in) {
return in.readShort();
@@ -61,7 +61,7 @@ public interface NetWorkCodecs {
}
};
NetWorkCodec<Integer> UNSIGNED_SHORT = new NetWorkCodec<>() {
NetworkCodec<ByteBuf, Integer> UNSIGNED_SHORT = new NetworkCodec<>() {
@Override
public Integer decode(ByteBuf in) {
return in.readUnsignedShort();
@@ -73,7 +73,7 @@ public interface NetWorkCodecs {
}
};
NetWorkCodec<Integer> INTEGER = new NetWorkCodec<>() {
NetworkCodec<ByteBuf, Integer> INTEGER = new NetworkCodec<>() {
@Override
public Integer decode(ByteBuf in) {
return in.readInt();
@@ -85,7 +85,7 @@ public interface NetWorkCodecs {
}
};
NetWorkCodec<Integer> VAR_INTEGER = new NetWorkCodec<>() {
NetworkCodec<ByteBuf, Integer> VAR_INTEGER = new NetworkCodec<>() {
@Override
public Integer decode(ByteBuf in) {
int result = 0;
@@ -111,12 +111,12 @@ public interface NetWorkCodecs {
}
};
NetWorkCodec<OptionalInt> OPTIONAL_VAR_INTEGER = VAR_INTEGER.map(
NetworkCodec<ByteBuf, OptionalInt> OPTIONAL_VAR_INTEGER = VAR_INTEGER.map(
integer -> integer == 0 ? OptionalInt.empty() : OptionalInt.of(integer - 1),
optionalInt -> optionalInt.isPresent() ? optionalInt.getAsInt() + 1 : 0
);
NetWorkCodec<Long> LONG = new NetWorkCodec<>() {
NetworkCodec<ByteBuf, Long> LONG = new NetworkCodec<>() {
@Override
public Long decode(ByteBuf in) {
return in.readLong();
@@ -128,7 +128,7 @@ public interface NetWorkCodecs {
}
};
NetWorkCodec<Long> VAR_LONG = new NetWorkCodec<>() {
NetworkCodec<ByteBuf, Long> VAR_LONG = new NetworkCodec<>() {
@Override
public Long decode(ByteBuf in) {
long result = 0L;
@@ -154,7 +154,7 @@ public interface NetWorkCodecs {
}
};
NetWorkCodec<Float> FLOAT = new NetWorkCodec<>() {
NetworkCodec<ByteBuf, Float> FLOAT = new NetworkCodec<>() {
@Override
public Float decode(ByteBuf in) {
return in.readFloat();
@@ -166,7 +166,7 @@ public interface NetWorkCodecs {
}
};
NetWorkCodec<Double> DOUBLE = new NetWorkCodec<>() {
NetworkCodec<ByteBuf, Double> DOUBLE = new NetworkCodec<>() {
@Override
public Double decode(ByteBuf in) {
return in.readDouble();
@@ -178,7 +178,7 @@ public interface NetWorkCodecs {
}
};
NetWorkCodec<byte[]> BYTE_ARRAY = new NetWorkCodec<>() {
NetworkCodec<ByteBuf, byte[]> BYTE_ARRAY = new NetworkCodec<>() {
@Override
public byte[] decode(ByteBuf in) {
int maxSize = in.readableBytes();
@@ -199,7 +199,7 @@ public interface NetWorkCodecs {
}
};
NetWorkCodec<long[]> LONG_ARRAY = new NetWorkCodec<>() {
NetworkCodec<ByteBuf, long[]> 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> STRING_UTF8 = new NetWorkCodec<>() {
NetworkCodec<ByteBuf, String> STRING_UTF8 = new NetworkCodec<>() {
private static final int MAX_STRING_LENGTH = 32767;
@Override
@@ -273,7 +273,7 @@ public interface NetWorkCodecs {
}
};
NetWorkCodec<Tag> TAG = new NetWorkCodec<>() {
NetworkCodec<ByteBuf, Tag> TAG = new NetworkCodec<>() {
@Override
public Tag decode(ByteBuf in) {
int initialIndex = in.readerIndex();
@@ -304,7 +304,7 @@ public interface NetWorkCodecs {
}
};
NetWorkCodec<CompoundTag> COMPOUND_TAG = TAG.map(tag -> {
NetworkCodec<ByteBuf, CompoundTag> COMPOUND_TAG = TAG.map(tag -> {
if (tag instanceof CompoundTag compoundTag) {
return compoundTag;
} else {
@@ -312,7 +312,7 @@ public interface NetWorkCodecs {
}
}, tag -> tag);
NetWorkCodec<Optional<CompoundTag>> OPTIONAL_COMPOUND_TAG = new NetWorkCodec<>() {
NetworkCodec<ByteBuf, Optional<CompoundTag>> OPTIONAL_COMPOUND_TAG = new NetworkCodec<>() {
@Override
public Optional<CompoundTag> decode(ByteBuf in) {
int initialIndex = in.readerIndex();
@@ -347,7 +347,7 @@ public interface NetWorkCodecs {
}
};
NetWorkCodec<Vector3f> VECTOR3F = new NetWorkCodec<>() {
NetworkCodec<ByteBuf, Vector3f> 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> QUATERNIONF = new NetWorkCodec<>() {
NetworkCodec<ByteBuf, Quaternionf> 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<Integer> CONTAINER_ID = VAR_INTEGER;
NetworkCodec<ByteBuf, Integer> CONTAINER_ID = VAR_INTEGER;
NetWorkCodec<Integer> RGB_COLOR = new NetWorkCodec<>() {
NetworkCodec<ByteBuf, Integer> RGB_COLOR = new NetworkCodec<>() {
@Override
public Integer decode(ByteBuf in) {
return 255 << 24 | in.readByte() & 0xFF << 16 | in.readByte() & 0xFF << 8 | in.readByte() & 0xFF;

View File

@@ -0,0 +1,5 @@
package net.momirealms.craftengine.bukkit.plugin.network.payload.codec;
public interface NetworkDecoder<I, T> {
T decode(I in);
}

View File

@@ -0,0 +1,5 @@
package net.momirealms.craftengine.bukkit.plugin.network.payload.codec;
public interface NetworkEncoder<O, T> {
void encode(O out, T value);
}

View File

@@ -0,0 +1,6 @@
package net.momirealms.craftengine.bukkit.plugin.network.payload.codec;
@FunctionalInterface
public interface NetworkMemberEncoder<O, T> {
void encode(T object, O object2);
}

View File

@@ -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<FriendlyByteBuf, CancelBlockUpdateData> 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);
}
}

View File

@@ -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<FriendlyByteBuf, ClientBlockStateSizeData> 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));
}
}

View File

@@ -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<FriendlyByteBuf, ClientCustomBlockData> 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));
}
}

View File

@@ -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);

View File

@@ -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()) {

View File

@@ -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

View File

@@ -324,6 +324,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
// 结合variants
JsonElement combinedVariant = GsonHelper.combine(variants);
Map<String, JsonElement> 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));

View File

@@ -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();
}