mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2026-01-04 15:41:38 +00:00
@@ -6,6 +6,9 @@ import net.momirealms.craftengine.bukkit.block.behavior.UnsafeCompositeBlockBeha
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.plugin.injector.BlockGenerator;
|
||||
import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager;
|
||||
import net.momirealms.craftengine.bukkit.plugin.network.payload.PayloadHelper;
|
||||
import net.momirealms.craftengine.bukkit.plugin.network.payload.protocol.VisualBlockStatePacket;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.*;
|
||||
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
|
||||
@@ -63,6 +66,8 @@ public final class BukkitBlockManager extends AbstractBlockManager {
|
||||
private Set<Object> missingHitSounds = Set.of();
|
||||
private Set<Object> missingStepSounds = Set.of();
|
||||
private Set<Key> missingInteractSoundBlocks = Set.of();
|
||||
// 缓存的VisualBlockStatePacket
|
||||
private VisualBlockStatePacket cachedVisualBlockStatePacket;
|
||||
|
||||
public BukkitBlockManager(BukkitCraftEngine plugin) {
|
||||
super(plugin, RegistryUtils.currentBlockRegistrySize(), Config.serverSideBlocks());
|
||||
@@ -122,6 +127,11 @@ public final class BukkitBlockManager extends AbstractBlockManager {
|
||||
public void delayedLoad() {
|
||||
this.plugin.networkManager().registerBlockStatePacketListeners(this.blockStateMappings); // 重置方块映射表
|
||||
super.delayedLoad();
|
||||
this.cachedVisualBlockStatePacket = VisualBlockStatePacket.create();
|
||||
for (BukkitServerPlayer player : BukkitNetworkManager.instance().onlineUsers()) {
|
||||
if (!player.clientModEnabled()) continue;
|
||||
PayloadHelper.sendData(player, this.cachedVisualBlockStatePacket);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -358,6 +368,10 @@ public final class BukkitBlockManager extends AbstractBlockManager {
|
||||
return this.cachedUpdateTagsPacket;
|
||||
}
|
||||
|
||||
public VisualBlockStatePacket cachedVisualBlockStatePacket() {
|
||||
return this.cachedVisualBlockStatePacket;
|
||||
}
|
||||
|
||||
private void markVanillaNoteBlocks() {
|
||||
try {
|
||||
Object block = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, KeyUtils.toResourceLocation(BlockKeys.NOTE_BLOCK));
|
||||
|
||||
@@ -75,11 +75,11 @@ public class DirectionalAttachedBlockBehavior extends BukkitBlockBehavior {
|
||||
if (behavior == null) return false;
|
||||
Direction direction;
|
||||
if (isSixDirection) {
|
||||
direction = ((Direction) state.get(behavior.facingProperty)).opposite();
|
||||
direction = (Direction) state.get(behavior.facingProperty);
|
||||
} else {
|
||||
direction = ((HorizontalDirection) state.get(behavior.facingProperty)).opposite().toDirection();
|
||||
direction = ((HorizontalDirection) state.get(behavior.facingProperty)).toDirection();
|
||||
}
|
||||
BlockPos blockPos = LocationUtils.fromBlockPos(args[2]).relative(direction);
|
||||
BlockPos blockPos = LocationUtils.fromBlockPos(args[2]).relative(direction.opposite());
|
||||
Object nmsPos = LocationUtils.toBlockPos(blockPos);
|
||||
Object nmsState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(args[1], nmsPos);
|
||||
return FastNMS.INSTANCE.method$BlockStateBase$isFaceSturdy(nmsState, args[1], nmsPos, DirectionUtils.toNMSDirection(direction), CoreReflections.instance$SupportType$FULL)
|
||||
|
||||
@@ -187,9 +187,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
||||
Object bundle = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets);
|
||||
this.immediatePacketConsumer.accept(channel, bundle, sendListener);
|
||||
};
|
||||
// set up mod channel
|
||||
this.plugin.javaPlugin().getServer().getMessenger().registerIncomingPluginChannel(this.plugin.javaPlugin(), MOD_CHANNEL, this);
|
||||
this.plugin.javaPlugin().getServer().getMessenger().registerOutgoingPluginChannel(this.plugin.javaPlugin(), MOD_CHANNEL);
|
||||
// Inject server channel
|
||||
try {
|
||||
Object server = FastNMS.INSTANCE.method$MinecraftServer$getServer();
|
||||
@@ -1612,7 +1609,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if (clientPayload == null || !clientPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY)) return;
|
||||
if (clientPayload == null) return;
|
||||
PayloadHelper.handleReceiver(clientPayload, user);
|
||||
}
|
||||
}
|
||||
@@ -1943,6 +1940,10 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
||||
this.needsDowngrade = MiscUtils.ceilLog2(BlockStateUtils.vanillaBlockStateCount()) != MiscUtils.ceilLog2(blockRegistrySize);
|
||||
}
|
||||
|
||||
public int remapBlockState(int stateId, boolean enableMod) {
|
||||
return enableMod ? this.modBlockStateMapper[stateId] : this.blockStateMapper[stateId];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) {
|
||||
BukkitServerPlayer player = (BukkitServerPlayer) user;
|
||||
@@ -1989,14 +1990,14 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
||||
}
|
||||
Palette<Integer> palette = container.data().palette();
|
||||
if (palette.canRemap()) {
|
||||
if (palette.remapAndCheck(s -> this.blockStateMapper[s])) {
|
||||
if (palette.remapAndCheck(s -> remapBlockState(s, user.clientModEnabled()))) {
|
||||
hasChangedAnyBlock = true;
|
||||
}
|
||||
} else {
|
||||
hasGlobalPalette = true;
|
||||
for (int j = 0; j < 4096; j++) {
|
||||
int state = container.get(j);
|
||||
int newState = this.blockStateMapper[state];
|
||||
int newState = remapBlockState(state, user.clientModEnabled());
|
||||
if (newState != state) {
|
||||
container.set(j, newState);
|
||||
hasChangedAnyBlock = true;
|
||||
@@ -3752,7 +3753,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
||||
if (VersionHelper.isOrAbove1_20_2()) return;
|
||||
FriendlyByteBuf byteBuf = event.getBuffer();
|
||||
Key key = byteBuf.readKey();
|
||||
if (!key.equals(NetworkManager.MOD_CHANNEL_KEY)) return;
|
||||
PayloadHelper.handleReceiver(new UnknownPayload(key, byteBuf.readBytes(byteBuf.readableBytes())), user);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.network.payload;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.momirealms.craftengine.bukkit.plugin.network.payload.protocol.CancelBlockUpdatePacket;
|
||||
import net.momirealms.craftengine.bukkit.plugin.network.payload.protocol.ClientBlockStateSizePacket;
|
||||
import net.momirealms.craftengine.bukkit.plugin.network.payload.protocol.ClientCustomBlockPacket;
|
||||
import net.momirealms.craftengine.bukkit.plugin.network.payload.protocol.VisualBlockStatePacket;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.logger.Debugger;
|
||||
import net.momirealms.craftengine.core.plugin.network.PayloadChannelKeys;
|
||||
import net.momirealms.craftengine.core.plugin.network.ModPacket;
|
||||
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
|
||||
import net.momirealms.craftengine.core.plugin.network.NetworkManager;
|
||||
import net.momirealms.craftengine.core.plugin.network.codec.NetworkCodec;
|
||||
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
|
||||
import net.momirealms.craftengine.core.registry.WritableRegistry;
|
||||
@@ -15,11 +18,13 @@ import net.momirealms.craftengine.core.util.FriendlyByteBuf;
|
||||
import net.momirealms.craftengine.core.util.ResourceKey;
|
||||
|
||||
public class PayloadHelper {
|
||||
public static final byte[] JADE_RESPONSE = new byte[]{0, 0, 0, 0};
|
||||
|
||||
public static void registerDataTypes() {
|
||||
registerDataType(ClientCustomBlockPacket.TYPE, ClientCustomBlockPacket.CODEC);
|
||||
registerDataType(CancelBlockUpdatePacket.TYPE, CancelBlockUpdatePacket.CODEC);
|
||||
registerDataType(ClientBlockStateSizePacket.TYPE, ClientBlockStateSizePacket.CODEC);
|
||||
registerDataType(VisualBlockStatePacket.TYPE, VisualBlockStatePacket.CODEC);
|
||||
}
|
||||
|
||||
public static <T extends ModPacket> void registerDataType(ResourceKey<NetworkCodec<FriendlyByteBuf, ? extends ModPacket>> key, NetworkCodec<FriendlyByteBuf, T> codec) {
|
||||
@@ -36,16 +41,31 @@ public class PayloadHelper {
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
|
||||
buf.writeByte(BuiltInRegistries.MOD_PACKET.getId(codec));
|
||||
codec.encode(buf, data);
|
||||
user.sendCustomPayload(NetworkManager.MOD_CHANNEL_KEY, buf.array());
|
||||
user.sendCustomPayload(PayloadChannelKeys.CRAFTENGINE_CHANNEL, buf.array());
|
||||
}
|
||||
|
||||
public static void handleReceiver(Payload payload, NetWorkUser user) {
|
||||
try {
|
||||
if (payload.channel().equals(PayloadChannelKeys.CRAFTENGINE_CHANNEL)) {
|
||||
handleCraftEngineModReceiver(payload, user);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// 乱发包我给你踹了
|
||||
user.kick(Component.translatable(
|
||||
"disconnect.craftengine.invalid_payload",
|
||||
"Connection terminated due to transmission of invalid payload. \n Please ensure that the client mod and server plugin are the latest version."
|
||||
));
|
||||
Debugger.COMMON.warn(() -> "Failed to handle payload", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void handleCraftEngineModReceiver(Payload payload, NetWorkUser user) {
|
||||
FriendlyByteBuf buf = payload.toBuffer();
|
||||
byte type = buf.readByte();
|
||||
@SuppressWarnings("unchecked")
|
||||
NetworkCodec<FriendlyByteBuf, ModPacket> codec = (NetworkCodec<FriendlyByteBuf, ModPacket>) BuiltInRegistries.MOD_PACKET.getValue(type);
|
||||
if (codec == null) {
|
||||
CraftEngine.instance().logger().warn("Unknown data type received: " + type);
|
||||
Debugger.COMMON.debug(() -> "Unknown data type received: " + type);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,13 @@ package net.momirealms.craftengine.bukkit.plugin.network.payload.protocol;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TranslationArgument;
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.network.payload.PayloadHelper;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.paper.PaperReflections;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.RegistryUtils;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.network.ModPacket;
|
||||
@@ -17,7 +20,7 @@ import net.momirealms.craftengine.core.registry.BuiltInRegistries;
|
||||
import net.momirealms.craftengine.core.util.*;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public record ClientCustomBlockPacket(int size) implements ModPacket {
|
||||
public record ClientCustomBlockPacket(int vanillaSize, int currentSize) implements ModPacket {
|
||||
public static final ResourceKey<NetworkCodec<FriendlyByteBuf, ? extends ModPacket>> TYPE = ResourceKey.create(
|
||||
BuiltInRegistries.MOD_PACKET.key().location(), Key.of("craftengine", "client_custom_block")
|
||||
);
|
||||
@@ -27,11 +30,12 @@ public record ClientCustomBlockPacket(int size) implements ModPacket {
|
||||
);
|
||||
|
||||
private ClientCustomBlockPacket(FriendlyByteBuf buf) {
|
||||
this(buf.readInt());
|
||||
this(buf.readInt(), buf.readInt());
|
||||
}
|
||||
|
||||
private void encode(FriendlyByteBuf buf) {
|
||||
buf.writeInt(this.size);
|
||||
buf.writeInt(this.vanillaSize);
|
||||
buf.writeInt(this.currentSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -42,17 +46,27 @@ public record ClientCustomBlockPacket(int size) implements ModPacket {
|
||||
@Override
|
||||
public void handle(NetWorkUser user) {
|
||||
if (user.clientModEnabled()) return; // 防止滥用
|
||||
int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize();
|
||||
if (this.size != serverBlockRegistrySize) {
|
||||
int vanillaBlockRegistrySize = BlockStateUtils.vanillaBlockStateCount();
|
||||
if (this.vanillaSize != vanillaBlockRegistrySize) {
|
||||
user.kick(Component.translatable(
|
||||
"disconnect.craftengine.block_registry_mismatch",
|
||||
TranslationArgument.numeric(this.size),
|
||||
"disconnect.craftengine.vanilla_block_registry_mismatch",
|
||||
TranslationArgument.numeric(this.vanillaSize),
|
||||
TranslationArgument.numeric(vanillaBlockRegistrySize)
|
||||
));
|
||||
return;
|
||||
}
|
||||
int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize();
|
||||
if (this.currentSize != serverBlockRegistrySize) {
|
||||
user.kick(Component.translatable(
|
||||
"disconnect.craftengine.current_block_registry_mismatch",
|
||||
TranslationArgument.numeric(this.currentSize),
|
||||
TranslationArgument.numeric(serverBlockRegistrySize)
|
||||
));
|
||||
return;
|
||||
}
|
||||
user.setClientModState(true);
|
||||
user.setClientBlockList(new IntIdentityList(this.size));
|
||||
user.setClientBlockList(new IntIdentityList(this.currentSize));
|
||||
PayloadHelper.sendData(user, BukkitBlockManager.instance().cachedVisualBlockStatePacket());
|
||||
if (!VersionHelper.isOrAbove1_20_2()) {
|
||||
// 因为旧版本没有配置阶段需要重新发送区块
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.network.payload.protocol;
|
||||
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
import net.momirealms.craftengine.core.plugin.network.ModPacket;
|
||||
import net.momirealms.craftengine.core.plugin.network.codec.NetworkCodec;
|
||||
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
|
||||
import net.momirealms.craftengine.core.util.FriendlyByteBuf;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.ResourceKey;
|
||||
|
||||
public record VisualBlockStatePacket(int[] data) implements ModPacket {
|
||||
public static final ResourceKey<NetworkCodec<FriendlyByteBuf, ? extends ModPacket>> TYPE = ResourceKey.create(
|
||||
BuiltInRegistries.MOD_PACKET.key().location(), Key.of("craftengine", "visual_block_state")
|
||||
);
|
||||
public static final NetworkCodec<FriendlyByteBuf, VisualBlockStatePacket> CODEC = ModPacket.codec(
|
||||
VisualBlockStatePacket::encode,
|
||||
VisualBlockStatePacket::new
|
||||
);
|
||||
private static final int RLE_THRESHOLD = 3;
|
||||
private static final int RLE_TAG = 0;
|
||||
private static final int DELTA_TAG = 1;
|
||||
|
||||
private VisualBlockStatePacket(FriendlyByteBuf buf) {
|
||||
this(decode(buf));
|
||||
}
|
||||
|
||||
private void encode(FriendlyByteBuf buf) {
|
||||
encode(buf, this.data);
|
||||
}
|
||||
|
||||
private static void encode(FriendlyByteBuf buf, int[] data) {
|
||||
if (data.length == 0) {
|
||||
buf.writeVarInt(0);
|
||||
return;
|
||||
}
|
||||
buf.writeVarInt(data.length);
|
||||
int i = 0;
|
||||
int previousValue = 0;
|
||||
while (i < data.length) {
|
||||
int currentValue = data[i];
|
||||
int repeatCount = 1;
|
||||
int j = i + 1;
|
||||
while (j < data.length && data[j] == currentValue) {
|
||||
repeatCount++;
|
||||
j++;
|
||||
}
|
||||
if (repeatCount >= RLE_THRESHOLD) {
|
||||
buf.writeVarInt(RLE_TAG);
|
||||
buf.writeVarInt(currentValue);
|
||||
buf.writeVarInt(repeatCount);
|
||||
i += repeatCount;
|
||||
previousValue = currentValue;
|
||||
} else {
|
||||
buf.writeVarInt(DELTA_TAG);
|
||||
int delta = currentValue - previousValue;
|
||||
buf.writeVarInt(delta);
|
||||
previousValue = currentValue;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int[] decode(FriendlyByteBuf buf) {
|
||||
int length = buf.readVarInt();
|
||||
if (length == 0) return new int[0];
|
||||
int[] data = new int[length];
|
||||
int previousValue = 0;
|
||||
int i = 0;
|
||||
while (i < length) {
|
||||
int tag = buf.readVarInt();
|
||||
if (tag == RLE_TAG) {
|
||||
int value = buf.readVarInt();
|
||||
int count = buf.readVarInt();
|
||||
if (i + count > length) throw new DecoderException("RLE count exceeds array bounds");
|
||||
for (int j = 0; j < count; j++) data[i++] = value;
|
||||
previousValue = value;
|
||||
} else if (tag == DELTA_TAG) {
|
||||
int delta = buf.readVarInt();
|
||||
int currentValue = previousValue + delta;
|
||||
data[i++] = currentValue;
|
||||
previousValue = currentValue;
|
||||
} else {
|
||||
throw new DecoderException("Unknown encoding tag: " + tag);
|
||||
}
|
||||
}
|
||||
if (i != length) throw new DecoderException("Decoded length mismatch");
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceKey<NetworkCodec<FriendlyByteBuf, ? extends ModPacket>> type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
public static VisualBlockStatePacket create() {
|
||||
int vanillaBlockStateCount = BlockStateUtils.vanillaBlockStateCount();
|
||||
int serverSideBlockCount = Config.serverSideBlocks();
|
||||
int[] mappings = new int[serverSideBlockCount];
|
||||
for (int i = 0; i < serverSideBlockCount; i++) {
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(i + vanillaBlockStateCount);
|
||||
if (state.isEmpty()) continue;
|
||||
mappings[state.customBlockState().registryId() - vanillaBlockStateCount] = state.vanillaBlockState().registryId();
|
||||
}
|
||||
return new VisualBlockStatePacket(mappings);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,16 +3,11 @@ package net.momirealms.craftengine.core.plugin.network;
|
||||
import io.netty.channel.Channel;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.plugin.Manageable;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface NetworkManager extends Manageable {
|
||||
String MOD_CHANNEL = "craftengine:payload";
|
||||
String VIA_CHANNEL = "vv:proxy_details";
|
||||
Key MOD_CHANNEL_KEY = Key.of(MOD_CHANNEL);
|
||||
Key VIA_CHANNEL_KEY = Key.of(VIA_CHANNEL);
|
||||
|
||||
void setUser(Channel channel, NetWorkUser user);
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.momirealms.craftengine.core.plugin.network;
|
||||
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
|
||||
public final class PayloadChannelKeys {
|
||||
public static final Key CRAFTENGINE_CHANNEL = Key.of("craftengine:payload"); // 进出
|
||||
}
|
||||
Reference in New Issue
Block a user