From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: violetc <58360096+s-yh-china@users.noreply.github.com> Date: Wed, 13 Sep 2023 19:31:20 +0800 Subject: [PATCH] Servux Protocol diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index fba016014ffc628887dc873cfa54f8c76a72c7ef..3201913bd2fba0038ab4853931a641e361a883b1 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1610,6 +1610,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop players = new ConcurrentHashMap<>(); + private static final Map> playerBoundingBoxesCache = new HashMap<>(); + private static final Map> dimensionCache = new ConcurrentHashMap<>(); + + @Contract("_ -> new") + public static @NotNull ResourceLocation id(String path) { + return new ResourceLocation(PROTOCOL_ID, path); + } + + public static void onPlayerSubscribed(@NotNull ServerPlayer player) { + if (LeavesConfig.servuxProtocol) { + players.put(player.getId(), player); + + CompoundTag tag = new CompoundTag(); + tag.putInt("version", PROTOCOL_VERSION); + tag.putString("id", CHANNEL.toString()); + tag.putInt("timeout", Integer.MAX_VALUE - 200); + sendNBTPacket(player, PACKET_METADATA, tag); + } + } + + public static void onPlayerLoggedOut(@NotNull ServerPlayer player) { + if (LeavesConfig.servuxProtocol) { + players.remove(player.getId()); + playerBoundingBoxesCache.remove(player.getId()); + } + } + + public static void onChunkLoaded(@NotNull LevelChunk chunk) { + if (LeavesConfig.servuxProtocol) { + List structures = new ArrayList<>(); + final Registry structureFeatureRegistry = chunk.getLevel().registryAccess().registryOrThrow(Registries.STRUCTURE); + for (var es : chunk.getAllStarts().entrySet()) { + final var optional = structureFeatureRegistry.getResourceKey(es.getKey()); + optional.ifPresent(key -> structures.add(es.getValue())); + } + + if (!structures.isEmpty()) { + onStructuresLoaded((ServerLevel) chunk.getLevel(), structures); + } + } + } + + public static void onStructuresLoaded(@NotNull ServerLevel level, @NotNull List structures) { + Map cache = getOrCreateCache(level.dimension().location()); + for (StructureStart structureStart : structures) { + if (structureStart == null) { + return; + } + + StructurePieceSerializationContext ctx = StructurePieceSerializationContext.fromLevel(level); + + BoundingBox boundingBox = structureStart.getBoundingBox(); + if (cache.containsKey(boundingBox)) { + return; + } + + cache.put(boundingBox, structureStart.createTag(ctx, structureStart.getChunkPos())); + } + } + + private static void sendBoundingToPlayer(int id, ServerPlayer player) { + Map boundingBoxMap = dimensionCache.get(player.level().dimension().location()); + if (boundingBoxMap == null) { + return; + } + + Set playerBoundingBoxes = playerBoundingBoxesCache.computeIfAbsent(id, k -> new HashSet<>()); + + ListTag listTag = new ListTag(); + for (BoundingBox key : boundingBoxMap.keySet()) { + if (listTag.size() >= 50) { + break; + } + if (playerBoundingBoxes.contains(key)) { + continue; + } + + CompoundTag boundingBoxes = boundingBoxMap.get(key); + if (boundingBoxes != null) { + listTag.add(boundingBoxes); + } + playerBoundingBoxes.add(key); + } + + if (!listTag.isEmpty()) { + CompoundTag tag = new CompoundTag(); + tag.put("Structures", listTag); + sendNBTPacket(player, PACKET_STRUCTURE_DATA, tag); + } + } + + public static void tick() { + if (LeavesConfig.servuxProtocol) { + for (var playerEntry : players.entrySet()) { + sendBoundingToPlayer(playerEntry.getKey(), playerEntry.getValue()); + } + } + } + + private static Map getOrCreateCache(ResourceLocation dimensionId) { + return dimensionCache.computeIfAbsent(dimensionId, dt -> new ConcurrentHashMap<>()); + } + + public static void sendNBTPacket(ServerPlayer player, int packetType, CompoundTag data) { + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeVarInt(packetType); + buf.writeNbt(data); + + int len = buf.writerIndex(); + buf.readerIndex(0); + + FriendlyByteBuf buf1 = new FriendlyByteBuf(Unpooled.buffer(len)); + buf1.writeVarInt(len); + buf1.writeBytes(buf, len); + ProtocolUtils.sendPayloadPacket(player, CHANNEL, buf1); + + buf.release(); + } +}