mirror of
https://github.com/LeavesMC/Leaves.git
synced 2026-01-04 15:41:31 +00:00
Update Servux Protocol
This commit is contained in:
@@ -179,12 +179,13 @@ index 0000000000000000000000000000000000000000..986d2a6641ff8017dddf3e5f2655adfc
|
||||
+}
|
||||
diff --git a/src/main/java/org/leavesmc/leaves/protocol/core/LeavesProtocolManager.java b/src/main/java/org/leavesmc/leaves/protocol/core/LeavesProtocolManager.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..4fd8e06c8d2d3016ccc0baf1c43d77d87ea1dca5
|
||||
index 0000000000000000000000000000000000000000..e5eb67c0bbdf4953ed0ccc3281f06eda26a7956e
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/org/leavesmc/leaves/protocol/core/LeavesProtocolManager.java
|
||||
@@ -0,0 +1,386 @@
|
||||
@@ -0,0 +1,435 @@
|
||||
+package org.leavesmc.leaves.protocol.core;
|
||||
+
|
||||
+import com.google.common.collect.ImmutableSet;
|
||||
+import net.minecraft.network.FriendlyByteBuf;
|
||||
+import net.minecraft.network.chat.Component;
|
||||
+import net.minecraft.resources.ResourceLocation;
|
||||
@@ -211,6 +212,7 @@ index 0000000000000000000000000000000000000000..4fd8e06c8d2d3016ccc0baf1c43d77d8
|
||||
+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;
|
||||
@@ -226,6 +228,7 @@ index 0000000000000000000000000000000000000000..4fd8e06c8d2d3016ccc0baf1c43d77d8
|
||||
+
|
||||
+ private static final Map<LeavesProtocol, Map<ProtocolHandler.PayloadReceiver, Executable>> KNOWN_TYPES = new HashMap<>();
|
||||
+ private static final Map<LeavesProtocol, Map<ProtocolHandler.PayloadReceiver, Method>> KNOW_RECEIVERS = new HashMap<>();
|
||||
+ private static Set<ResourceLocation> ALL_KNOWN_ID = new HashSet<>();
|
||||
+
|
||||
+ private static final List<Method> TICKERS = new ArrayList<>();
|
||||
+ private static final List<Method> PLAYER_JOIN = new ArrayList<>();
|
||||
@@ -340,6 +343,20 @@ index 0000000000000000000000000000000000000000..4fd8e06c8d2d3016ccc0baf1c43d77d8
|
||||
+ KNOWN_TYPES.put(protocol, map);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ for (LeavesProtocol protocol : KNOWN_TYPES.keySet()) {
|
||||
+ Map<ProtocolHandler.PayloadReceiver, Executable> map = KNOWN_TYPES.get(protocol);
|
||||
+ for (ProtocolHandler.PayloadReceiver receiver : map.keySet()) {
|
||||
+ if (receiver.sendFabricRegister() && !receiver.ignoreId()) {
|
||||
+ for (String payloadId : receiver.payloadId()) {
|
||||
+ for (String namespace : protocol.namespace()) {
|
||||
+ ALL_KNOWN_ID.add(new ResourceLocation(namespace, payloadId));
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ ALL_KNOWN_ID = ImmutableSet.copyOf(ALL_KNOWN_ID);
|
||||
+ }
|
||||
+
|
||||
+ public static LeavesCustomPayload<?> decode(ResourceLocation id, FriendlyByteBuf buf) {
|
||||
@@ -416,6 +433,8 @@ index 0000000000000000000000000000000000000000..4fd8e06c8d2d3016ccc0baf1c43d77d8
|
||||
+ LOGGER.warning("Failed to handle player join, " + exception.getCause() + ": " + exception.getMessage());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ ProtocolUtils.sendPayloadPacket(player, new FabricRegisterPayload(ALL_KNOWN_ID));
|
||||
+ }
|
||||
+
|
||||
+ public static void handlePlayerLeave(ServerPlayer player) {
|
||||
@@ -452,7 +471,7 @@ index 0000000000000000000000000000000000000000..4fd8e06c8d2d3016ccc0baf1c43d77d8
|
||||
+ Map<ProtocolHandler.MinecraftRegister, Method> map = MINECRAFT_REGISTER.get(protocol);
|
||||
+ for (ProtocolHandler.MinecraftRegister register : map.keySet()) {
|
||||
+ if (register.ignoreId() || register.channelId().equals(channel[1]) ||
|
||||
+ ArrayUtils.contains(register.channelIds(), channel[1])) {
|
||||
+ ArrayUtils.contains(register.channelIds(), channel[1])) {
|
||||
+ try {
|
||||
+ map.get(register).invoke(null, player);
|
||||
+ } catch (InvocationTargetException | IllegalAccessException exception) {
|
||||
@@ -568,13 +587,43 @@ index 0000000000000000000000000000000000000000..4fd8e06c8d2d3016ccc0baf1c43d77d8
|
||||
+ buf.writeBytes(data);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public record FabricRegisterPayload(Set<ResourceLocation> channels) implements LeavesCustomPayload<FabricRegisterPayload> {
|
||||
+
|
||||
+ public static final ResourceLocation CHANNEL = ResourceLocation.withDefaultNamespace("register");
|
||||
+
|
||||
+ @New
|
||||
+ public FabricRegisterPayload(ResourceLocation location, FriendlyByteBuf buf) {
|
||||
+ this(buf.readCollection(HashSet::new, FriendlyByteBuf::readResourceLocation));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void write(FriendlyByteBuf buf) {
|
||||
+ boolean first = true;
|
||||
+
|
||||
+ ResourceLocation channel;
|
||||
+ for (Iterator<ResourceLocation> var3 = this.channels.iterator(); var3.hasNext(); buf.writeBytes(channel.toString().getBytes(StandardCharsets.US_ASCII))) {
|
||||
+ channel = var3.next();
|
||||
+ if (first) {
|
||||
+ first = false;
|
||||
+ } else {
|
||||
+ buf.writeByte(0);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public ResourceLocation id() {
|
||||
+ return CHANNEL;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/org/leavesmc/leaves/protocol/core/ProtocolHandler.java b/src/main/java/org/leavesmc/leaves/protocol/core/ProtocolHandler.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..f941f095184cf4b7af284d1357ea1a85815e8a66
|
||||
index 0000000000000000000000000000000000000000..9d71f8e6af24301bedf60f5c87e0bb3c1697d5e3
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/org/leavesmc/leaves/protocol/core/ProtocolHandler.java
|
||||
@@ -0,0 +1,61 @@
|
||||
@@ -0,0 +1,63 @@
|
||||
+package org.leavesmc.leaves.protocol.core;
|
||||
+
|
||||
+import java.lang.annotation.ElementType;
|
||||
@@ -599,6 +648,8 @@ index 0000000000000000000000000000000000000000..f941f095184cf4b7af284d1357ea1a85
|
||||
+ String[] payloadId() default "";
|
||||
+
|
||||
+ boolean ignoreId() default false;
|
||||
+
|
||||
+ boolean sendFabricRegister() default true;
|
||||
+ }
|
||||
+
|
||||
+ @Target(ElementType.METHOD)
|
||||
|
||||
@@ -4,6 +4,23 @@ Date: Wed, 13 Sep 2023 19:31:20 +0800
|
||||
Subject: [PATCH] Servux Protocol
|
||||
|
||||
|
||||
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
index ab18bbf87dfc1455ed185a5152dad6d236565ecc..227c89f7d58cdcfad762f1f11e1f87203a444c6f 100644
|
||||
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
@@ -412,7 +412,11 @@ public final class RegionizedPlayerChunkLoader {
|
||||
if (this.sentChunks.add(CoordinateUtils.getChunkKey(chunkX, chunkZ))) {
|
||||
((ChunkSystemChunkHolder)((ChunkSystemServerLevel)this.world).moonrise$getChunkTaskScheduler().chunkHolderManager
|
||||
.getChunkHolder(chunkX, chunkZ).vanillaChunkHolder).moonrise$addReceivedChunk(this.player);
|
||||
- PlayerChunkSender.sendChunk(this.player.connection, this.world, ((ChunkSystemLevel)this.world).moonrise$getFullChunkIfLoaded(chunkX, chunkZ));
|
||||
+ // Leaves start - servux
|
||||
+ LevelChunk chunk = ((ChunkSystemLevel)this.world).moonrise$getFullChunkIfLoaded(chunkX, chunkZ);
|
||||
+ org.leavesmc.leaves.protocol.servux.ServuxStructuresProtocol.onStartedWatchingChunk(player, chunk);
|
||||
+ PlayerChunkSender.sendChunk(this.player.connection, this.world, chunk);
|
||||
+ // Leaves end - servux
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index fc9c4711495136c564ad0da3de314811256df4a1..0138c39c6c0b2c1f3526f9b4ff30d132d95a4e6f 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -139,6 +156,307 @@ index 0000000000000000000000000000000000000000..3a0e790f0d8e6866950601f9936984a8
|
||||
+ void encode(ServerPlayer player, FriendlyByteBuf buf);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/org/leavesmc/leaves/protocol/servux/ServuxEntityDataProtocol.java b/src/main/java/org/leavesmc/leaves/protocol/servux/ServuxEntityDataProtocol.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..8fb61870622738290167b5fa81f157f4eb6189a9
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/org/leavesmc/leaves/protocol/servux/ServuxEntityDataProtocol.java
|
||||
@@ -0,0 +1,295 @@
|
||||
+package org.leavesmc.leaves.protocol.servux;
|
||||
+
|
||||
+import io.netty.buffer.Unpooled;
|
||||
+import net.minecraft.Util;
|
||||
+import net.minecraft.core.BlockPos;
|
||||
+import net.minecraft.nbt.CompoundTag;
|
||||
+import net.minecraft.network.FriendlyByteBuf;
|
||||
+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.ChunkPos;
|
||||
+import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
+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.util.HashMap;
|
||||
+import java.util.List;
|
||||
+import java.util.Map;
|
||||
+import java.util.UUID;
|
||||
+
|
||||
+// Powered by Servux(https://github.com/sakura-ryoko/servux)
|
||||
+
|
||||
+@LeavesProtocol(namespace = "servux")
|
||||
+public class ServuxEntityDataProtocol {
|
||||
+
|
||||
+ public static final ResourceLocation CHANNEL = ServuxProtocol.id("entity_data");
|
||||
+ public static final int PROTOCOL_VERSION = 1;
|
||||
+
|
||||
+ private static final Map<UUID, Long> readingSessionKeys = new HashMap<>();
|
||||
+
|
||||
+ @ProtocolHandler.PlayerJoin
|
||||
+ public static void onPlayerLoggedIn(ServerPlayer player) {
|
||||
+ if (!LeavesConfig.servuxProtocol) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ sendMetadata(player);
|
||||
+ }
|
||||
+
|
||||
+ @ProtocolHandler.PayloadReceiver(payload = EntityDataPayload.class, payloadId = "entity_data")
|
||||
+ public static void onPacketReceive(ServerPlayer player, EntityDataPayload payload) {
|
||||
+ if (!LeavesConfig.servuxProtocol) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ switch (payload.packetType) {
|
||||
+ case PACKET_C2S_METADATA_REQUEST -> sendMetadata(player);
|
||||
+ case PACKET_C2S_BLOCK_ENTITY_REQUEST -> onBlockEntityRequest(player, payload.pos);
|
||||
+ case PACKET_C2S_ENTITY_REQUEST -> onEntityRequest(player, payload.entityId);
|
||||
+ case PACKET_C2S_NBT_RESPONSE_DATA -> {
|
||||
+ UUID uuid = player.getUUID();
|
||||
+ long readingSessionKey;
|
||||
+
|
||||
+ if (!readingSessionKeys.containsKey(uuid)) {
|
||||
+ readingSessionKey = RandomSource.create(Util.getMillis()).nextLong();
|
||||
+ readingSessionKeys.put(uuid, readingSessionKey);
|
||||
+ } else {
|
||||
+ readingSessionKey = readingSessionKeys.get(uuid);
|
||||
+ }
|
||||
+
|
||||
+ FriendlyByteBuf fullPacket = PacketSplitter.receive(readingSessionKey, payload.buffer);
|
||||
+
|
||||
+ if (fullPacket != null) {
|
||||
+ readingSessionKeys.remove(uuid);
|
||||
+ LeavesLogger.LOGGER.warning("ServuxEntityDataProtocol,PACKET_C2S_NBT_RESPONSE_DATA NOT Implemented!");
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static void sendMetadata(ServerPlayer player) {
|
||||
+ CompoundTag metadata = new CompoundTag();
|
||||
+ metadata.putString("name", "entity_data");
|
||||
+ metadata.putString("id", CHANNEL.toString());
|
||||
+ metadata.putInt("version", PROTOCOL_VERSION);
|
||||
+ metadata.putString("servux", ServuxProtocol.SERVUX_STRING);
|
||||
+
|
||||
+ EntityDataPayload payload = new EntityDataPayload(EntityDataPayloadType.PACKET_S2C_METADATA);
|
||||
+ payload.nbt.merge(metadata);
|
||||
+ sendPacket(player, payload);
|
||||
+ }
|
||||
+
|
||||
+ public static void onBlockEntityRequest(ServerPlayer player, BlockPos pos) {
|
||||
+ MinecraftServer.getServer().execute(() -> {
|
||||
+ BlockEntity be = player.serverLevel().getBlockEntity(pos);
|
||||
+ CompoundTag nbt = be != null ? be.saveWithoutMetadata(player.registryAccess()) : new CompoundTag();
|
||||
+
|
||||
+ EntityDataPayload payload = new EntityDataPayload(EntityDataPayloadType.PACKET_S2C_BLOCK_NBT_RESPONSE_SIMPLE);
|
||||
+ payload.pos = pos.immutable();
|
||||
+ payload.nbt.merge(nbt);
|
||||
+ sendPacket(player, payload);
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ public static void onEntityRequest(ServerPlayer player, int entityId) {
|
||||
+ MinecraftServer.getServer().execute(() -> {
|
||||
+ Entity entity = player.serverLevel().getEntity(entityId);
|
||||
+ CompoundTag nbt = entity != null ? entity.saveWithoutId(new CompoundTag()) : new CompoundTag();
|
||||
+
|
||||
+ EntityDataPayload payload = new EntityDataPayload(EntityDataPayloadType.PACKET_S2C_ENTITY_NBT_RESPONSE_SIMPLE);
|
||||
+ payload.entityId = entityId;
|
||||
+ payload.nbt.merge(nbt);
|
||||
+ sendPacket(player, payload);
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ public static void sendPacket(ServerPlayer player, EntityDataPayload payload) {
|
||||
+ if (!LeavesConfig.servuxProtocol) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (payload.packetType == EntityDataPayloadType.PACKET_S2C_NBT_RESPONSE_START) {
|
||||
+ FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.buffer());
|
||||
+ buffer.writeNbt(payload.nbt);
|
||||
+ PacketSplitter.send(ServuxEntityDataProtocol::sendWithSplitter, buffer, player);
|
||||
+ } else {
|
||||
+ ProtocolUtils.sendPayloadPacket(player, payload);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static void sendWithSplitter(ServerPlayer player, FriendlyByteBuf buf) {
|
||||
+ EntityDataPayload payload = new EntityDataPayload(EntityDataPayloadType.PACKET_S2C_NBT_RESPONSE_DATA);
|
||||
+ payload.buffer = buf;
|
||||
+ payload.nbt = new CompoundTag();
|
||||
+ sendPacket(player, payload);
|
||||
+ }
|
||||
+
|
||||
+ public enum EntityDataPayloadType {
|
||||
+ PACKET_S2C_METADATA(1),
|
||||
+ PACKET_C2S_METADATA_REQUEST(2),
|
||||
+ PACKET_C2S_BLOCK_ENTITY_REQUEST(3),
|
||||
+ PACKET_C2S_ENTITY_REQUEST(4),
|
||||
+ PACKET_S2C_BLOCK_NBT_RESPONSE_SIMPLE(5),
|
||||
+ PACKET_S2C_ENTITY_NBT_RESPONSE_SIMPLE(6),
|
||||
+ // For Packet Splitter (Oversize Packets, S2C)
|
||||
+ PACKET_S2C_NBT_RESPONSE_START(10),
|
||||
+ PACKET_S2C_NBT_RESPONSE_DATA(11),
|
||||
+ // For Packet Splitter (Oversize Packets, C2S)
|
||||
+ PACKET_C2S_NBT_RESPONSE_START(12),
|
||||
+ PACKET_C2S_NBT_RESPONSE_DATA(13),
|
||||
+ PACKET_C2S_LITEMATICA_PASTE(14),
|
||||
+ PACKET_C2S_REQUEST_ALL_ENTITIES_IN_CHUNK(15);
|
||||
+
|
||||
+ private static final class Helper {
|
||||
+ static Map<Integer, EntityDataPayloadType> ID_TO_TYPE = new HashMap<>();
|
||||
+ }
|
||||
+
|
||||
+ public final int type;
|
||||
+
|
||||
+ EntityDataPayloadType(int type) {
|
||||
+ this.type = type;
|
||||
+ EntityDataPayloadType.Helper.ID_TO_TYPE.put(type, this);
|
||||
+ }
|
||||
+
|
||||
+ public static EntityDataPayloadType fromId(int id) {
|
||||
+ return EntityDataPayloadType.Helper.ID_TO_TYPE.get(id);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static class EntityDataPayload implements LeavesCustomPayload<EntityDataPayload> {
|
||||
+
|
||||
+ private final EntityDataPayloadType packetType;
|
||||
+ private int transactionId;
|
||||
+ private int entityId;
|
||||
+ private BlockPos pos;
|
||||
+ private CompoundTag nbt;
|
||||
+ private FriendlyByteBuf buffer;
|
||||
+ private List<ChunkPos> requestingChunks;
|
||||
+
|
||||
+ private EntityDataPayload(EntityDataPayloadType type) {
|
||||
+ this.packetType = type;
|
||||
+ this.transactionId = -1;
|
||||
+ this.entityId = -1;
|
||||
+ this.pos = BlockPos.ZERO;
|
||||
+ this.nbt = new CompoundTag();
|
||||
+ this.clearPacket();
|
||||
+ }
|
||||
+
|
||||
+ private void clearPacket() {
|
||||
+ if (this.buffer != null) {
|
||||
+ this.buffer.clear();
|
||||
+ this.buffer = new FriendlyByteBuf(Unpooled.buffer());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @New
|
||||
+ public static EntityDataPayload decode(ResourceLocation location, FriendlyByteBuf buffer) {
|
||||
+ EntityDataPayloadType type = EntityDataPayloadType.fromId(buffer.readVarInt());
|
||||
+ if (type == null) {
|
||||
+ throw new IllegalStateException("invalid packet type received");
|
||||
+ }
|
||||
+
|
||||
+ EntityDataPayload payload = new EntityDataPayload(type);
|
||||
+ switch (type) {
|
||||
+ case PACKET_C2S_BLOCK_ENTITY_REQUEST -> {
|
||||
+ buffer.readVarInt();
|
||||
+ payload.pos = buffer.readBlockPos().immutable();
|
||||
+ }
|
||||
+
|
||||
+ case PACKET_C2S_ENTITY_REQUEST -> {
|
||||
+ buffer.readVarInt();
|
||||
+ payload.entityId = buffer.readVarInt();
|
||||
+ }
|
||||
+
|
||||
+ case PACKET_S2C_BLOCK_NBT_RESPONSE_SIMPLE -> {
|
||||
+ payload.pos = buffer.readBlockPos().immutable();
|
||||
+ CompoundTag nbt = buffer.readNbt();
|
||||
+ if (nbt != null) {
|
||||
+ payload.nbt.merge(nbt);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ case PACKET_S2C_ENTITY_NBT_RESPONSE_SIMPLE -> {
|
||||
+ payload.entityId = buffer.readVarInt();
|
||||
+ CompoundTag nbt = buffer.readNbt();
|
||||
+ if (nbt != null) {
|
||||
+ payload.nbt.merge(nbt);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ case PACKET_S2C_NBT_RESPONSE_DATA, PACKET_C2S_NBT_RESPONSE_DATA -> {
|
||||
+ payload.buffer = new FriendlyByteBuf(buffer.readBytes(buffer.readableBytes()));
|
||||
+ payload.nbt = new CompoundTag();
|
||||
+ }
|
||||
+
|
||||
+ case PACKET_C2S_METADATA_REQUEST, PACKET_S2C_METADATA -> {
|
||||
+ CompoundTag nbt = buffer.readNbt();
|
||||
+ if (nbt != null) {
|
||||
+ payload.nbt.merge(nbt);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ case PACKET_C2S_LITEMATICA_PASTE -> {
|
||||
+ payload.nbt = buffer.readNbt();
|
||||
+ }
|
||||
+
|
||||
+ case PACKET_C2S_REQUEST_ALL_ENTITIES_IN_CHUNK -> {
|
||||
+ payload.requestingChunks = buffer.readList(FriendlyByteBuf::readChunkPos);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return payload;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void write(FriendlyByteBuf buf) {
|
||||
+ buf.writeVarInt(this.packetType.type);
|
||||
+
|
||||
+ switch (this.packetType) {
|
||||
+ case PACKET_C2S_BLOCK_ENTITY_REQUEST -> {
|
||||
+ buf.writeVarInt(this.transactionId);
|
||||
+ buf.writeBlockPos(this.pos);
|
||||
+ }
|
||||
+
|
||||
+ case PACKET_C2S_ENTITY_REQUEST -> {
|
||||
+ buf.writeVarInt(this.transactionId);
|
||||
+ buf.writeVarInt(this.entityId);
|
||||
+ }
|
||||
+
|
||||
+ case PACKET_S2C_BLOCK_NBT_RESPONSE_SIMPLE -> {
|
||||
+ buf.writeBlockPos(this.pos);
|
||||
+ buf.writeNbt(this.nbt);
|
||||
+ }
|
||||
+
|
||||
+ case PACKET_S2C_ENTITY_NBT_RESPONSE_SIMPLE -> {
|
||||
+ buf.writeVarInt(this.entityId);
|
||||
+ buf.writeNbt(this.nbt);
|
||||
+ }
|
||||
+
|
||||
+ case PACKET_S2C_NBT_RESPONSE_DATA, PACKET_C2S_NBT_RESPONSE_DATA -> {
|
||||
+ buf.writeBytes(this.buffer.readBytes(this.buffer.readableBytes()));
|
||||
+ }
|
||||
+
|
||||
+ case PACKET_C2S_REQUEST_ALL_ENTITIES_IN_CHUNK -> {
|
||||
+ buf.writeCollection(this.requestingChunks, FriendlyByteBuf::writeChunkPos);
|
||||
+ }
|
||||
+
|
||||
+ case PACKET_C2S_METADATA_REQUEST, PACKET_S2C_METADATA, PACKET_C2S_LITEMATICA_PASTE -> {
|
||||
+ buf.writeNbt(this.nbt);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public ResourceLocation id() {
|
||||
+ return CHANNEL;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/org/leavesmc/leaves/protocol/servux/ServuxProtocol.java b/src/main/java/org/leavesmc/leaves/protocol/servux/ServuxProtocol.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..f80678c0abc38c72b63a32450bd726268d208d6a
|
||||
@@ -164,10 +482,10 @@ index 0000000000000000000000000000000000000000..f80678c0abc38c72b63a32450bd72626
|
||||
+}
|
||||
diff --git a/src/main/java/org/leavesmc/leaves/protocol/servux/ServuxStructuresProtocol.java b/src/main/java/org/leavesmc/leaves/protocol/servux/ServuxStructuresProtocol.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..b7839e1e8cdd68f5db3e6fe237a767a664659daa
|
||||
index 0000000000000000000000000000000000000000..028e9f00bb6422f0df40c6d6d286fd0c7e1c290c
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/org/leavesmc/leaves/protocol/servux/ServuxStructuresProtocol.java
|
||||
@@ -0,0 +1,413 @@
|
||||
@@ -0,0 +1,465 @@
|
||||
+package org.leavesmc.leaves.protocol.servux;
|
||||
+
|
||||
+import io.netty.buffer.Unpooled;
|
||||
@@ -186,6 +504,7 @@ index 0000000000000000000000000000000000000000..b7839e1e8cdd68f5db3e6fe237a767a6
|
||||
+import net.minecraft.world.level.GameRules;
|
||||
+import net.minecraft.world.level.Level;
|
||||
+import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
+import net.minecraft.world.level.chunk.LevelChunk;
|
||||
+import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
+import net.minecraft.world.level.levelgen.structure.Structure;
|
||||
+import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||
@@ -239,6 +558,15 @@ index 0000000000000000000000000000000000000000..b7839e1e8cdd68f5db3e6fe237a767a6
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @ProtocolHandler.PlayerJoin
|
||||
+ public static void onPlayerLoggedIn(ServerPlayer player) {
|
||||
+ if (!LeavesConfig.servuxProtocol) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ onPlayerSubscribed(player);
|
||||
+ }
|
||||
+
|
||||
+ @ProtocolHandler.PlayerLeave
|
||||
+ public static void onPlayerLoggedOut(@NotNull ServerPlayer player) {
|
||||
+ if (!LeavesConfig.servuxProtocol) {
|
||||
@@ -250,7 +578,7 @@ index 0000000000000000000000000000000000000000..b7839e1e8cdd68f5db3e6fe237a767a6
|
||||
+
|
||||
+ @ProtocolHandler.Ticker
|
||||
+ public static void tick() {
|
||||
+ if (LeavesConfig.servuxProtocol) {
|
||||
+ if (!LeavesConfig.servuxProtocol) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
@@ -273,6 +601,48 @@ index 0000000000000000000000000000000000000000..b7839e1e8cdd68f5db3e6fe237a767a6
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static void onStartedWatchingChunk(ServerPlayer player, LevelChunk chunk) {
|
||||
+ if (!LeavesConfig.servuxProtocol) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ MinecraftServer server = player.getServer();
|
||||
+
|
||||
+ if (players.containsKey(player.getId()) && server != null) {
|
||||
+ addChunkTimeoutIfHasReferences(player.getUUID(), chunk, server.getTickCount());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static void addChunkTimeoutIfHasReferences(final UUID uuid, LevelChunk chunk, final int tickCounter) {
|
||||
+ final ChunkPos pos = chunk.getPos();
|
||||
+
|
||||
+ if (chunkHasStructureReferences(pos.x, pos.z, chunk.getLevel())) {
|
||||
+ final Map<ChunkPos, Timeout> map = timeouts.computeIfAbsent(uuid, (u) -> new HashMap<>());
|
||||
+ map.computeIfAbsent(pos, (p) -> new Timeout(tickCounter - timeout));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static boolean chunkHasStructureReferences(int chunkX, int chunkZ, Level world) {
|
||||
+ if (!world.hasChunk(chunkX, chunkZ)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ ChunkAccess chunk = world.getChunk(chunkX, chunkZ, ChunkStatus.STRUCTURE_STARTS, false);
|
||||
+
|
||||
+ if (chunk == null) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ for (Map.Entry<Structure, LongSet> entry : chunk.getAllReferences().entrySet()) {
|
||||
+ if (!entry.getValue().isEmpty()) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ public static void onPlayerSubscribed(@NotNull ServerPlayer player) {
|
||||
+ if (!players.containsKey(player.getId())) {
|
||||
+ players.put(player.getId(), player);
|
||||
|
||||
Reference in New Issue
Block a user