9
0
mirror of https://github.com/LeavesMC/Leaves.git synced 2025-12-28 19:39:22 +00:00

Fix protocol bugs (#537)

* Fix stupid protocol bug with for loop

* Fix tick freeze in jade and etc.

* Try to fix syncmatica

* Try to fix servux entity and build

* Go away LMS!

* Remove config

* Formatting

* Add ticker interval
This commit is contained in:
Lumine1909
2025-06-16 20:17:05 +08:00
committed by GitHub
parent 8615b2f4ca
commit 093b9290c7
10 changed files with 45 additions and 185 deletions

View File

@@ -811,9 +811,7 @@ public final class LeavesConfig {
public static class SyncmaticaValidator extends BooleanConfigValidator {
@Override
public void verify(Boolean old, Boolean value) throws IllegalArgumentException {
if (value) {
org.leavesmc.leaves.protocol.syncmatica.SyncmaticaProtocol.init();
}
org.leavesmc.leaves.protocol.syncmatica.SyncmaticaProtocol.init(value);
}
}
@@ -936,9 +934,6 @@ public final class LeavesConfig {
@GlobalConfig("leaves-carpet-support")
public boolean leavesCarpetSupport = false;
@GlobalConfig("lms-paster-protocol")
public boolean lmsPasterProtocol = false;
@GlobalConfig(value = "rei-server-protocol", validator = ReiValidator.class)
public boolean reiServerProtocol = false;
@@ -956,6 +951,9 @@ public final class LeavesConfig {
@RemovedConfig(name = "recipe-send-all", category = {"protocol"})
public boolean recipeSendAll = false;
@RemovedConfig(name = "lms-paster-protocol", category = {"protocol"})
public boolean lmsPasterProtocol = false;
}
public static MiscConfig mics = new MiscConfig();

View File

@@ -1,133 +0,0 @@
package org.leavesmc.leaves.protocol;
import com.google.common.collect.Sets;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.LeavesLogger;
import org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
import org.leavesmc.leaves.protocol.core.ProtocolHandler;
import org.leavesmc.leaves.protocol.core.ProtocolUtils;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.function.Consumer;
@LeavesProtocol.Register(namespace = "litematica-server-paster")
public class LMSPasterProtocol implements LeavesProtocol {
public static final String MOD_ID = "litematica-server-paster";
public static final String MOD_VERSION = "1.3.5";
private static final Map<ServerGamePacketListenerImpl, StringBuilder> VERY_LONG_CHATS = new WeakHashMap<>();
@ProtocolHandler.PayloadReceiver(payload = LmsPasterPayload.class)
public static void handlePackets(ServerPlayer player, LmsPasterPayload payload) {
String playerName = player.getName().getString();
int id = payload.id();
CompoundTag nbt = payload.nbt();
switch (id) {
case LMSPasterProtocol.C2S.HI -> {
String clientModVersion = nbt.getString("mod_version").orElseThrow();
LeavesLogger.LOGGER.info(String.format("Player %s connected with %s @ %s", playerName, LMSPasterProtocol.MOD_ID, clientModVersion));
ProtocolUtils.sendPayloadPacket(player, LMSPasterProtocol.S2C.build(LMSPasterProtocol.S2C.HI, nbt2 -> nbt2.putString("mod_version", LMSPasterProtocol.MOD_VERSION)));
ProtocolUtils.sendPayloadPacket(player, LMSPasterProtocol.S2C.build(LMSPasterProtocol.S2C.ACCEPT_PACKETS, nbt2 -> nbt2.putIntArray("ids", C2S.ALL_PACKET_IDS)));
}
case LMSPasterProtocol.C2S.CHAT -> {
String message = nbt.getString("chat").orElseThrow();
triggerCommand(player, playerName, message);
}
case LMSPasterProtocol.C2S.VERY_LONG_CHAT_START -> VERY_LONG_CHATS.put(player.connection, new StringBuilder());
case LMSPasterProtocol.C2S.VERY_LONG_CHAT_CONTENT -> {
String segment = nbt.getString("segment").orElseThrow();
getVeryLongChatBuilder(player).ifPresent(builder -> builder.append(segment));
}
case LMSPasterProtocol.C2S.VERY_LONG_CHAT_END -> {
getVeryLongChatBuilder(player).ifPresent(builder -> triggerCommand(player, playerName, builder.toString()));
VERY_LONG_CHATS.remove(player.connection);
}
}
}
private static Optional<StringBuilder> getVeryLongChatBuilder(ServerPlayer player) {
return Optional.ofNullable(VERY_LONG_CHATS.get(player.connection));
}
private static void triggerCommand(ServerPlayer player, String playerName, String command) {
if (command.isEmpty()) {
LeavesLogger.LOGGER.warning(String.format("Player %s sent an empty command", playerName));
return;
}
MinecraftServer.getServer().execute(() -> player.getBukkitEntity().performCommand(command));
}
@Override
public boolean isActive() {
return LeavesConfig.protocol.lmsPasterProtocol;
}
private static class C2S {
public static final int HI = 0;
public static final int CHAT = 1;
public static final int VERY_LONG_CHAT_START = 2;
public static final int VERY_LONG_CHAT_CONTENT = 3;
public static final int VERY_LONG_CHAT_END = 4;
public static final int[] ALL_PACKET_IDS;
static {
Set<Integer> allPacketIds = Sets.newLinkedHashSet();
for (Field field : C2S.class.getFields()) {
if (field.getType() == int.class && Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers())) {
try {
allPacketIds.add((int) field.get(null));
} catch (Exception e) {
LeavesLogger.LOGGER.severe("Failed to initialized Lms Paster: ", e);
}
}
}
ALL_PACKET_IDS = new int[allPacketIds.size()];
int i = 0;
for (Integer id : allPacketIds) {
ALL_PACKET_IDS[i++] = id;
}
}
}
private static class S2C {
public static final int HI = 0;
public static final int ACCEPT_PACKETS = 1;
public static CustomPacketPayload build(int packetId, Consumer<CompoundTag> payloadBuilder) {
CompoundTag nbt = new CompoundTag();
payloadBuilder.accept(nbt);
return new LmsPasterPayload(packetId, nbt);
}
}
public record LmsPasterPayload(int id, CompoundTag nbt) implements LeavesCustomPayload {
@ID
private static final ResourceLocation PACKET_ID = ResourceLocation.fromNamespaceAndPath(MOD_ID, "network_v2");
@Codec
private static final StreamCodec<FriendlyByteBuf, LmsPasterPayload> CODEC = StreamCodec.composite(
ByteBufCodecs.VAR_INT,
LmsPasterPayload::id,
ByteBufCodecs.COMPOUND_TAG,
LmsPasterPayload::nbt,
LmsPasterPayload::new
);
}
}

View File

@@ -19,12 +19,14 @@ import net.minecraft.world.level.block.state.properties.ChestType;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.LeavesLogger;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.plugin.MinecraftInternalPlugin;
import org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
import org.leavesmc.leaves.protocol.core.ProtocolHandler;
@@ -79,11 +81,10 @@ public class PcaSyncProtocol implements LeavesProtocol {
@ProtocolHandler.PayloadReceiver(payload = SyncBlockEntityPayload.class)
private static void syncBlockEntityHandler(ServerPlayer player, SyncBlockEntityPayload payload) {
MinecraftServer server = MinecraftServer.getServer();
BlockPos pos = payload.pos;
ServerLevel world = player.serverLevel();
server.execute(() -> {
Bukkit.getGlobalRegionScheduler().run(MinecraftInternalPlugin.INSTANCE, (task) -> {
BlockState blockState = world.getBlockState(pos);
clearPlayerWatchData(player);
@@ -123,7 +124,7 @@ public class PcaSyncProtocol implements LeavesProtocol {
int entityId = payload.entityId;
ServerLevel world = player.serverLevel();
server.execute(() -> {
Bukkit.getGlobalRegionScheduler().run(MinecraftInternalPlugin.INSTANCE, (task) -> {
Entity entity = world.getEntity(entityId);
if (entity != null) {

View File

@@ -28,7 +28,6 @@ import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@@ -311,9 +310,8 @@ public class LeavesProtocolManager {
}
});
ProtocolUtils.sendBytebufPacket(player, ResourceLocation.fromNamespaceAndPath("minecraft", "register"), buf -> {
ResourceLocation channel;
for (Iterator<String> var3 = set.iterator(); var3.hasNext(); buf.writeBytes(channel.toString().getBytes(StandardCharsets.US_ASCII))) {
channel = ResourceLocation.parse(var3.next());
for (String channel : set) {
buf.writeBytes(channel.getBytes(StandardCharsets.US_ASCII));
buf.writeByte(0);
}
buf.writerIndex(Math.max(buf.writerIndex() - 1, 0));

View File

@@ -36,10 +36,12 @@ import net.minecraft.world.level.block.entity.HopperBlockEntity;
import net.minecraft.world.level.block.entity.JukeboxBlockEntity;
import net.minecraft.world.level.block.entity.LecternBlockEntity;
import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.LeavesLogger;
import org.leavesmc.leaves.plugin.MinecraftInternalPlugin;
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
import org.leavesmc.leaves.protocol.core.ProtocolHandler;
import org.leavesmc.leaves.protocol.core.ProtocolUtils;
@@ -181,7 +183,7 @@ public class JadeProtocol implements LeavesProtocol {
@ProtocolHandler.PayloadReceiver(payload = RequestEntityPayload.class)
public static void requestEntityData(ServerPlayer player, RequestEntityPayload payload) {
MinecraftServer.getServer().execute(() -> {
Bukkit.getGlobalRegionScheduler().run(MinecraftInternalPlugin.INSTANCE, (task) -> {
EntityAccessor accessor = payload.data().unpack(player);
if (accessor == null) {
return;
@@ -217,8 +219,7 @@ public class JadeProtocol implements LeavesProtocol {
@ProtocolHandler.PayloadReceiver(payload = RequestBlockPayload.class)
public static void requestBlockData(ServerPlayer player, RequestBlockPayload payload) {
MinecraftServer server = MinecraftServer.getServer();
server.execute(() -> {
Bukkit.getGlobalRegionScheduler().run(MinecraftInternalPlugin.INSTANCE, (task) -> {
BlockAccessor accessor = payload.data().unpack(player);
if (accessor == null) {
return;

View File

@@ -13,7 +13,6 @@ import net.minecraft.world.entity.vehicle.ContainerEntity;
import net.minecraft.world.inventory.PlayerEnderChestContainer;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.ChestBlock;
import net.minecraft.world.level.block.EnderChestBlock;
import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
import net.minecraft.world.level.block.entity.ChestBlockEntity;
import net.minecraft.world.level.block.entity.EnderChestBlockEntity;

View File

@@ -33,6 +33,7 @@ import org.bukkit.plugin.PluginManager;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.plugin.MinecraftInternalPlugin;
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
import org.leavesmc.leaves.protocol.core.ProtocolHandler;
import org.leavesmc.leaves.protocol.core.ProtocolUtils;
@@ -167,7 +168,7 @@ public class REIServerProtocol implements LeavesProtocol {
);
cachedPayloads = listBuilder.build();
MinecraftServer.getServer().execute(() -> {
Bukkit.getGlobalRegionScheduler().run(MinecraftInternalPlugin.INSTANCE, (task) -> {
for (ServerPlayer player : enabledPlayers) {
for (CustomPacketPayload payload : cachedPayloads) {
ProtocolUtils.sendPayloadPacket(player, payload);

View File

@@ -7,13 +7,14 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.block.entity.BlockEntity;
import org.bukkit.Bukkit;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.LeavesLogger;
import org.leavesmc.leaves.plugin.MinecraftInternalPlugin;
import org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
import org.leavesmc.leaves.protocol.core.ProtocolHandler;
@@ -77,7 +78,7 @@ public class ServuxEntityDataProtocol implements LeavesProtocol {
}
public static void onBlockEntityRequest(ServerPlayer player, BlockPos pos) {
MinecraftServer.getServer().execute(() -> {
Bukkit.getGlobalRegionScheduler().run(MinecraftInternalPlugin.INSTANCE, (task) -> {
BlockEntity be = player.serverLevel().getBlockEntity(pos);
CompoundTag nbt = be != null ? be.saveWithoutMetadata(player.registryAccess()) : new CompoundTag();
@@ -89,7 +90,7 @@ public class ServuxEntityDataProtocol implements LeavesProtocol {
}
public static void onEntityRequest(ServerPlayer player, int entityId) {
MinecraftServer.getServer().execute(() -> {
Bukkit.getGlobalRegionScheduler().run(MinecraftInternalPlugin.INSTANCE, (task) -> {
Entity entity = player.serverLevel().getEntity(entityId);
CompoundTag nbt = entity != null ? entity.saveWithoutId(new CompoundTag()) : new CompoundTag();

View File

@@ -47,12 +47,13 @@ public class ServuxStructuresProtocol implements LeavesProtocol {
private static final Map<UUID, Map<ChunkPos, Timeout>> timeouts = new HashMap<>();
private static int retainDistance;
@ProtocolHandler.PlayerJoin
public static void onPlayerJoin(ServerPlayer player) {
sendMetaData(player);
}
@ProtocolHandler.PayloadReceiver(payload = StructuresPayload.class)
public static void onPacketReceive(ServerPlayer player, StructuresPayload payload) {
if (!LeavesConfig.protocol.servux.structureProtocol) {
return;
}
switch (payload.packetType()) {
case PACKET_C2S_STRUCTURES_REGISTER -> onPlayerSubscribed(player);
case PACKET_C2S_REQUEST_SPAWN_METADATA -> ServuxHudDataProtocol.refreshSpawnMetadata(player); // move to
@@ -62,37 +63,27 @@ public class ServuxStructuresProtocol implements LeavesProtocol {
@ProtocolHandler.PlayerLeave
public static void onPlayerLoggedOut(@NotNull ServerPlayer player) {
if (!LeavesConfig.protocol.servux.structureProtocol) {
return;
}
players.remove(player.getId());
}
@ProtocolHandler.Ticker
public static void tick() {
if (!LeavesConfig.protocol.servux.structureProtocol) {
return;
}
MinecraftServer server = MinecraftServer.getServer();
int tickCounter = server.getTickCount();
if ((tickCounter % updateInterval) == 0) {
retainDistance = server.getPlayerList().getViewDistance() + 2;
for (ServerPlayer player : players.values()) {
// TODO DimensionChange
refreshTrackedChunks(player, tickCounter);
}
retainDistance = server.getPlayerList().getViewDistance() + 2;
for (ServerPlayer player : players.values()) {
// TODO DimensionChange
refreshTrackedChunks(player, tickCounter);
}
}
@Override
public int tickerInterval(String tickerID) {
return updateInterval;
}
public static void onStartedWatchingChunk(ServerPlayer player, LevelChunk chunk) {
if (!LeavesConfig.protocol.servux.structureProtocol) {
return;
}
MinecraftServer server = player.getServer();
if (players.containsKey(player.getId()) && server != null) {
addChunkTimeoutIfHasReferences(player.getUUID(), chunk, server.getTickCount());
}
@@ -133,6 +124,11 @@ public class ServuxStructuresProtocol implements LeavesProtocol {
}
MinecraftServer server = MinecraftServer.getServer();
sendMetaData(player);
initialSyncStructures(player, player.moonrise$getViewDistanceHolder().getViewDistances().sendViewDistance() + 2, server.getTickCount());
}
private static void sendMetaData(ServerPlayer player) {
CompoundTag tag = new CompoundTag();
tag.putString("name", "structure_bounding_boxes");
tag.putString("id", StructuresPayload.CHANNEL.toString());
@@ -141,7 +137,6 @@ public class ServuxStructuresProtocol implements LeavesProtocol {
tag.putInt("timeout", timeout);
sendPacket(player, new StructuresPayload(StructuresPayloadType.PACKET_S2C_METADATA, tag));
initialSyncStructures(player, player.moonrise$getViewDistanceHolder().getViewDistances().sendViewDistance() + 2, server.getTickCount());
}
public static void initialSyncStructures(ServerPlayer player, int chunkRadius, int tickCounter) {
@@ -310,10 +305,6 @@ public class ServuxStructuresProtocol implements LeavesProtocol {
}
public static void sendPacket(ServerPlayer player, StructuresPayload payload) {
if (!LeavesConfig.protocol.servux.structureProtocol) {
return;
}
if (payload.packetType() == StructuresPayloadType.PACKET_S2C_STRUCTURE_DATA_START) {
FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.buffer());
buffer.writeNbt(payload.nbt());

View File

@@ -23,7 +23,7 @@ public class SyncmaticaProtocol {
private static final FeatureSet featureSet = new FeatureSet(Arrays.asList(Feature.values()));
private static final SyncmaticManager syncmaticManager = new SyncmaticManager();
private static final FileStorage fileStorage = new FileStorage();
private static final int[] ILLEGAL_CHARS = {34, 60, 62, 124, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 58, 42, 63, 92, 47};
private static final int[] ILLEGAL_CHARS = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 58, 42, 63, 92, 47, 34, 60, 62, 124};
private static final String ILLEGAL_PATTERNS = "(^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\\..*)?$)|(^\\.\\.*$)";
private static boolean loaded = false;
@@ -51,11 +51,14 @@ public class SyncmaticaProtocol {
return fileStorage;
}
public static void init() {
if (!loaded) {
public static void init(boolean status) {
if (status && !loaded) {
litematicFolder.mkdirs();
syncmaticManager.startup();
loaded = true;
} else if (!status && loaded) {
syncmaticManager.updateServerPlacement();
loaded = false;
}
}