diff --git a/src/main/java/cn/nukkit/entity/Entity.java b/src/main/java/cn/nukkit/entity/Entity.java index f19fcf4ac27..53565cd1dd1 100644 --- a/src/main/java/cn/nukkit/entity/Entity.java +++ b/src/main/java/cn/nukkit/entity/Entity.java @@ -1167,7 +1167,16 @@ public void sendData(Player player) { public void sendData(Player player, EntityMetadata data) { SetEntityDataPacket pk = new SetEntityDataPacket(); pk.eid = this.getId(); - pk.metadata = data == null ? this.dataProperties : data; + if (data == null) { + pk.metadata = this.dataProperties.copy(); + } else { + pk.metadata = data; + + EntityData nukkitFlags = this.dataProperties.get(DATA_NUKKIT_FLAGS); + if (nukkitFlags != null) { + data.put(nukkitFlags); + } + } player.dataPacket(pk); } @@ -1178,11 +1187,15 @@ public void sendData(Player[] players) { public void sendData(Player[] players, EntityMetadata data) { SetEntityDataPacket pk = new SetEntityDataPacket(); pk.eid = this.getId(); - pk.metadata = data == null ? this.dataProperties : data; + if (data == null) { + pk.metadata = this.dataProperties.copy(); + } else { + pk.metadata = data; - EntityData nukkitFlags = this.dataProperties.get(DATA_NUKKIT_FLAGS); - if (nukkitFlags != null) { - pk.metadata.put(nukkitFlags); + EntityData nukkitFlags = this.dataProperties.get(DATA_NUKKIT_FLAGS); + if (nukkitFlags != null) { + data.put(nukkitFlags); + } } for (Player player : players) { diff --git a/src/main/java/cn/nukkit/entity/data/EntityMetadata.java b/src/main/java/cn/nukkit/entity/data/EntityMetadata.java index f9d180e2ea0..43d0f18857b 100644 --- a/src/main/java/cn/nukkit/entity/data/EntityMetadata.java +++ b/src/main/java/cn/nukkit/entity/data/EntityMetadata.java @@ -20,6 +20,13 @@ public class EntityMetadata { private final Int2ObjectMap map = new Int2ObjectOpenHashMap<>(); + public EntityMetadata() { + } + + public EntityMetadata(EntityMetadata copy) { + map.putAll(copy.map); + } + @Nullable public EntityData get(int id) { return this.getOrDefault(id, null); @@ -187,7 +194,15 @@ public Int2ObjectMap getMap() { return new Int2ObjectOpenHashMap<>(map); } + public Int2ObjectMap getMapUnsafe() { + return map; + } + public boolean isEmpty() { return this.map.isEmpty(); } + + public EntityMetadata copy() { + return new EntityMetadata(this); + } } diff --git a/src/main/java/cn/nukkit/network/protocol/BatchPacket.java b/src/main/java/cn/nukkit/network/protocol/BatchPacket.java index 1318f9f9b0e..8c235513bc2 100644 --- a/src/main/java/cn/nukkit/network/protocol/BatchPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/BatchPacket.java @@ -1,5 +1,9 @@ package cn.nukkit.network.protocol; +import cn.nukkit.Server; +import cn.nukkit.network.Network; +import cn.nukkit.utils.Binary; +import cn.nukkit.utils.Zlib; import lombok.ToString; import javax.annotation.Nullable; @@ -36,6 +40,44 @@ public void trim() { setBuffer(null); } + public static BatchPacket compress(DataPacket... packets) { + return compress(false, packets); + } + + public static BatchPacket compress(boolean zlibRaw, DataPacket... packets) { + return compress(Server.getInstance().networkCompressionLevel, zlibRaw, packets); + } + + public static BatchPacket compress(int compressionLevel, DataPacket... packets) { + return compress(compressionLevel, false, packets); + } + + public static BatchPacket compress(int compressionLevel, boolean zlibRaw, DataPacket... packets) { + int count = packets.length; + Track[] tracks = new Track[count]; + + byte[][] payload = new byte[2 * count][]; + for (int i = 0; i < count; i++) { + DataPacket packet = packets[i]; + packet.tryEncode(); + byte[] buffer = packet.getBuffer(); + int index = 2 * i; + payload[index] = Binary.writeUnsignedVarInt(buffer.length); + payload[index + 1] = buffer; + + tracks[i] = new Track(packet.pid(), packet.getCount()); + } + + BatchPacket batch = new BatchPacket(); + try { + batch.payload = zlibRaw ? Network.deflateRaw(payload, compressionLevel) : Zlib.deflate(payload, compressionLevel); + } catch (Exception e) { + throw new RuntimeException(e); + } + batch.tracks = tracks; + return batch; + } + @ToString public static class Track { public final int packetId;