9
0
mirror of https://github.com/LeavesMC/Leaves.git synced 2025-12-19 14:59:32 +00:00
Files
LeavesMC/patches/server/0038-PCA-sync-protocol.patch
2024-01-19 11:09:19 +08:00

699 lines
30 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: violetc <58360096+s-yh-china@users.noreply.github.com>
Date: Mon, 28 Nov 2022 15:34:15 +0800
Subject: [PATCH] PCA sync protocol
This patch is Powered by plusls-carpet-addition(https://github.com/plusls/plusls-carpet-addition)
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java
index d9539f5275c4cb63910ba79aa522d9569ad35a89..577b0c8b1aee4cd120f4ef22b1fde27cb3f6c376 100644
--- a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java
@@ -373,6 +373,11 @@ public abstract class AbstractHorse extends Animal implements ContainerListener,
@Override
public void containerChanged(Container sender) {
+ // Leaves start - pca
+ if (top.leavesmc.leaves.LeavesConfig.pcaSyncProtocol) {
+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncEntityToClient(this);
+ }
+ // Leaves end - pca
boolean flag = this.isSaddled();
this.updateContainerEquipment();
diff --git a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java
index 5a591c439c5cef6b7e7e6f836ab813cb4f29b08c..17cc25b6fbc85c9e0023be7e9d857b2d76f6e58c 100644
--- a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java
+++ b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java
@@ -64,6 +64,15 @@ public abstract class AbstractVillager extends AgeableMob implements InventoryCa
super(type, world);
this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, 16.0F);
this.setPathfindingMalus(BlockPathTypes.DAMAGE_FIRE, -1.0F);
+ // Leaves start - pca
+ if (!this.level().isClientSide()) {
+ this.inventory.addListener(inventory -> {
+ if (top.leavesmc.leaves.LeavesConfig.pcaSyncProtocol) {
+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncEntityToClient(this);
+ }
+ });
+ }
+ // Leaves end - pca
}
@Override
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
index 6d23c39e4eadf23616080d6d08672e13b5d3c37d..f86384ba4e5b5ffd26dd64e41a9af8a3f3a8da49 100644
--- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
@@ -129,7 +129,13 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme
}
@Override
- public void setChanged() {}
+ public void setChanged() {
+ // Leaves start - pca
+ if (top.leavesmc.leaves.LeavesConfig.pcaSyncProtocol) {
+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncEntityToClient(this);
+ }
+ // Leaves end - pca
+ }
@Override
public boolean stillValid(Player player) {
diff --git a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
index 5eaab97a0c3b93a44a45e2ed11033fe01c0c95c2..d31bcddad2fa2ebac6269cc7bf22254710c1843e 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
@@ -570,6 +570,16 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
}
+ // Leaves start - pca
+ @Override
+ public void setChanged() {
+ super.setChanged();
+ if (top.leavesmc.leaves.LeavesConfig.pcaSyncProtocol) {
+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(this);
+ }
+ }
+ // Leaves end - pca
+
@Override
public boolean stillValid(net.minecraft.world.entity.player.Player player) {
return Container.stillValidBlockEntity(this, player);
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java
index 416aa989ebb18a8741cc9d605a1180ab830f6643..213bc3c11ff4ed9bc761e8153aa669d1e2301960 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java
@@ -131,6 +131,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity {
this.items = list;
}
+ // Leaves start - pca
+ @Override
+ public void setChanged() {
+ super.setChanged();
+ if (top.leavesmc.leaves.LeavesConfig.pcaSyncProtocol) {
+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(this);
+ }
+ }
+ // Leaves end - pca
+
@Override
protected Component getDefaultName() {
return Component.translatable("container.barrel");
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
index 3ba04d615fae9748c144b3dc7e7442be2e5a659f..bb16de61eeafe0d446e43710accb40991dc7c129 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
@@ -4,6 +4,7 @@ import com.google.common.collect.Lists;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
+import java.util.Objects;
import javax.annotation.Nullable;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
@@ -127,6 +128,11 @@ public class BeehiveBlockEntity extends BlockEntity {
super.setChanged();
}
+ // Leaves start - pca
+ if (top.leavesmc.leaves.LeavesConfig.pcaSyncProtocol) {
+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(this);
+ }
+ // Leaves end - pca
return list;
}
@@ -188,6 +194,12 @@ public class BeehiveBlockEntity extends BlockEntity {
this.level.gameEvent(GameEvent.BLOCK_CHANGE, blockposition, GameEvent.Context.of(entity, this.getBlockState()));
}
+ // Leaves start - pca
+ if (top.leavesmc.leaves.LeavesConfig.pcaSyncProtocol) {
+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(this);
+ }
+ // Leaves end - pca
+
entity.discard();
super.setChanged();
}
@@ -334,6 +346,11 @@ public class BeehiveBlockEntity extends BlockEntity {
if (BeehiveBlockEntity.releaseOccupant(world, pos, state, tileentitybeehive_hivebee, (List) null, tileentitybeehive_releasestatus, flowerPos)) {
flag = true;
iterator.remove();
+ // Leaves start - pca
+ if (top.leavesmc.leaves.LeavesConfig.pcaSyncProtocol) {
+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(Objects.requireNonNull(world.getBlockEntity(pos)));
+ }
+ // Leaves end - pca
// CraftBukkit start
} else {
tileentitybeehive_hivebee.exitTickCounter = tileentitybeehive_hivebee.minOccupationTicks / 2; // Not strictly Vanilla behaviour in cases where bees cannot spawn but still reasonable // Paper - Fix bees aging inside hives; use exitTickCounter to keep actual bee life
@@ -385,6 +402,11 @@ public class BeehiveBlockEntity extends BlockEntity {
this.maxBees = nbt.getInt("Bukkit.MaxEntities");
}
// CraftBukkit end
+ // Leaves start - pca
+ if (top.leavesmc.leaves.LeavesConfig.pcaSyncProtocol) {
+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(this);
+ }
+ // Leaves end - pca
}
@Override
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java
index bc01481ac5990ad1cfd1def5a16dd0ed2f9de8c9..e7bfc1008d270de81b375e3dd6e3c3439565752e 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java
@@ -334,6 +334,16 @@ public class BrewingStandBlockEntity extends BaseContainerBlockEntity implements
}
+ // Leaves start - pca
+ @Override
+ public void setChanged() {
+ super.setChanged();
+ if (top.leavesmc.leaves.LeavesConfig.pcaSyncProtocol) {
+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(this);
+ }
+ }
+ // Leaves end - pca
+
@Override
public boolean stillValid(Player player) {
return Container.stillValidBlockEntity(this, player);
diff --git a/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java
index a71414397bd45ee7bcacfeef0041d80dfa25f114..1d6c7a04b8246a60d80325e1615e50573b17a6bb 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java
@@ -190,6 +190,16 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement
this.items = list;
}
+ // Leaves start - pca
+ @Override
+ public void setChanged() {
+ super.setChanged();
+ if (top.leavesmc.leaves.LeavesConfig.pcaSyncProtocol) {
+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(this);
+ }
+ }
+ // Leaves end - pca
+
@Override
public float getOpenNess(float tickDelta) {
return this.chestLidController.getOpenness(tickDelta);
diff --git a/src/main/java/net/minecraft/world/level/block/entity/ComparatorBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/ComparatorBlockEntity.java
index 9b2c162c362fcf6093a3bf6da715ae8f18176c82..84b877a712a883b868b139d29da7e09c9552a1e5 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/ComparatorBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/ComparatorBlockEntity.java
@@ -23,6 +23,16 @@ public class ComparatorBlockEntity extends BlockEntity {
this.output = nbt.getInt("OutputSignal");
}
+ // Leaves start - pca
+ @Override
+ public void setChanged() {
+ super.setChanged();
+ if (top.leavesmc.leaves.LeavesConfig.pcaSyncProtocol) {
+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(this);
+ }
+ }
+ // Leaves end - pca
+
public int getOutputSignal() {
return this.output;
}
diff --git a/src/main/java/net/minecraft/world/level/block/entity/DispenserBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/DispenserBlockEntity.java
index 881379681c39230a00b3a1f11cd87498984396c7..e01eb2025458cf311348c58a1530854053af78f4 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/DispenserBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/DispenserBlockEntity.java
@@ -92,6 +92,16 @@ public class DispenserBlockEntity extends RandomizableContainerBlockEntity {
return -1;
}
+ // Leaves start - pca
+ @Override
+ public void setChanged() {
+ super.setChanged();
+ if (top.leavesmc.leaves.LeavesConfig.pcaSyncProtocol) {
+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(this);
+ }
+ }
+ // Leaves end - pca
+
@Override
protected Component getDefaultName() {
return Component.translatable("container.dispenser");
diff --git a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index df1c1c27b7c0065f8179d59bdb9de01dde22befa..b17b8f2a773fcdd20d26dcdb083d59f6b89af37f 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -129,6 +129,16 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
}
+ // Leaves start - pca
+ @Override
+ public void setChanged() {
+ super.setChanged();
+ if (top.leavesmc.leaves.LeavesConfig.pcaSyncProtocol) {
+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(this);
+ }
+ }
+ // Leaves end - pca
+
@Override
protected Component getDefaultName() {
return Component.translatable("container.hopper");
@@ -208,6 +218,11 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
if (flag) {
blockEntity.setCooldown(world.spigotConfig.hopperTransfer); // Spigot
setChanged(world, pos, state);
+ // Leaves start - pca
+ if (top.leavesmc.leaves.LeavesConfig.pcaSyncProtocol) {
+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(blockEntity);
+ }
+ // Leaves end - pca
return true;
}
}
diff --git a/src/main/java/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java
index 1fa22445a4ecc8c08dbcf0cc6bd39dc5003604c4..5c311270a39f6b4996c8b58822d24556c67adc41 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java
@@ -269,6 +269,16 @@ public class ShulkerBoxBlockEntity extends RandomizableContainerBlockEntity impl
this.itemStacks = list;
}
+ // Leaves start - pca
+ @Override
+ public void setChanged() {
+ super.setChanged();
+ if (top.leavesmc.leaves.LeavesConfig.pcaSyncProtocol) {
+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(this);
+ }
+ }
+ // Leaves end - pca
+
@Override
public int[] getSlotsForFace(Direction side) {
return ShulkerBoxBlockEntity.SLOTS;
diff --git a/src/main/java/top/leavesmc/leaves/protocol/PcaSyncProtocol.java b/src/main/java/top/leavesmc/leaves/protocol/PcaSyncProtocol.java
new file mode 100644
index 0000000000000000000000000000000000000000..f4a7aed61511ad9557c8cc4779229b3bf79159dd
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/protocol/PcaSyncProtocol.java
@@ -0,0 +1,389 @@
+package top.leavesmc.leaves.protocol;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.ChestBlock;
+import net.minecraft.world.level.block.entity.BlockEntity;
+import net.minecraft.world.level.block.state.BlockState;
+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.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import top.leavesmc.leaves.LeavesConfig;
+import top.leavesmc.leaves.LeavesLogger;
+import top.leavesmc.leaves.bot.ServerBot;
+import top.leavesmc.leaves.protocol.core.LeavesProtocol;
+import top.leavesmc.leaves.protocol.core.ProtocolHandler;
+import top.leavesmc.leaves.protocol.core.ProtocolUtils;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantLock;
+
+import static top.leavesmc.leaves.protocol.core.LeavesProtocolManager.EmptyPayload;
+
+@LeavesProtocol(namespace = "pca")
+public class PcaSyncProtocol {
+
+ public static final String PROTOCOL_ID = "pca";
+
+ public static final ReentrantLock lock = new ReentrantLock(true);
+ public static final ReentrantLock pairLock = new ReentrantLock(true);
+
+ // send
+ private static final ResourceLocation ENABLE_PCA_SYNC_PROTOCOL = id("enable_pca_sync_protocol");
+ private static final ResourceLocation DISABLE_PCA_SYNC_PROTOCOL = id("disable_pca_sync_protocol");
+ private static final ResourceLocation UPDATE_ENTITY = id("update_entity");
+ private static final ResourceLocation UPDATE_BLOCK_ENTITY = id("update_block_entity");
+
+ private static final Map<ServerPlayer, Pair<ResourceLocation, BlockPos>> playerWatchBlockPos = new HashMap<>();
+ private static final Map<ServerPlayer, Pair<ResourceLocation, Entity>> playerWatchEntity = new HashMap<>();
+ private static final Map<Pair<ResourceLocation, BlockPos>, Set<ServerPlayer>> blockPosWatchPlayerSet = new HashMap<>();
+ private static final Map<Pair<ResourceLocation, Entity>, Set<ServerPlayer>> entityWatchPlayerSet = new HashMap<>();
+ private static final MutablePair<ResourceLocation, Entity> ResourceLocationEntityPair = new MutablePair<>();
+ private static final MutablePair<ResourceLocation, BlockPos> ResourceLocationBlockPosPair = new MutablePair<>();
+
+ @Contract("_ -> new")
+ public static @NotNull ResourceLocation id(String path) {
+ return new ResourceLocation(PROTOCOL_ID, path);
+ }
+
+ @ProtocolHandler.PlayerJoin
+ private static void onJoin(ServerPlayer player) {
+ if (LeavesConfig.pcaSyncProtocol) {
+ enablePcaSyncProtocol(player);
+ }
+ }
+
+ @ProtocolHandler.ReloadServer
+ private static void onServerReload() {
+ if (LeavesConfig.pcaSyncProtocol) {
+ enablePcaSyncProtocolGlobal();
+ } else {
+ disablePcaSyncProtocolGlobal();
+ }
+ }
+
+ @ProtocolHandler.PayloadReceiver(payload = EmptyPayload.class, payloadId = "cancel_sync_block_entity")
+ private static void cancelSyncBlockEntityHandler(ServerPlayer player, EmptyPayload payload) {
+ if (!LeavesConfig.pcaSyncProtocol) {
+ return;
+ }
+ PcaSyncProtocol.clearPlayerWatchBlock(player);
+ }
+
+ @ProtocolHandler.PayloadReceiver(payload = EmptyPayload.class, payloadId = "cancel_sync_entity")
+ private static void cancelSyncEntityHandler(ServerPlayer player, EmptyPayload payload) {
+ if (!LeavesConfig.pcaSyncProtocol) {
+ return;
+ }
+ PcaSyncProtocol.clearPlayerWatchEntity(player);
+ }
+
+ @ProtocolHandler.PayloadReceiver(payload = SyncBlockEntityPayload.class, payloadId = "sync_block_entity")
+ private static void syncBlockEntityHandler(ServerPlayer player, SyncBlockEntityPayload payload) {
+ if (!LeavesConfig.pcaSyncProtocol) {
+ return;
+ }
+ MinecraftServer server = MinecraftServer.getServer();
+ BlockPos pos = payload.pos;
+ ServerLevel world = player.serverLevel();
+
+ server.execute(() -> {
+ BlockState blockState = world.getBlockState(pos);
+ clearPlayerWatchData(player);
+
+ BlockEntity blockEntityAdj = null;
+ if (blockState.getBlock() instanceof ChestBlock) {
+ if (blockState.getValue(ChestBlock.TYPE) != ChestType.SINGLE) {
+ BlockPos posAdj = pos.offset(ChestBlock.getConnectedDirection(blockState).getNormal());
+ // The method in World now checks that the caller is from the same thread...
+ blockEntityAdj = world.getChunk(posAdj).getBlockEntity(posAdj);
+ }
+ }
+
+ if (blockEntityAdj != null) {
+ updateBlockEntity(player, blockEntityAdj);
+ }
+
+ // The method in World now checks that the caller is from the same thread...
+ BlockEntity blockEntity = world.getChunk(pos).getBlockEntity(pos);
+ if (blockEntity != null) {
+ updateBlockEntity(player, blockEntity);
+ }
+
+ Pair<ResourceLocation, BlockPos> pair = new ImmutablePair<>(player.level().dimension().location(), pos);
+ lock.lock();
+ playerWatchBlockPos.put(player, pair);
+ if (!blockPosWatchPlayerSet.containsKey(pair)) {
+ blockPosWatchPlayerSet.put(pair, new HashSet<>());
+ }
+ blockPosWatchPlayerSet.get(pair).add(player);
+ lock.unlock();
+ });
+ }
+
+ @ProtocolHandler.PayloadReceiver(payload = SyncEntityPayload.class, payloadId = "sync_entity")
+ private static void syncEntityHandler(ServerPlayer player, SyncEntityPayload payload) {
+ if (!LeavesConfig.pcaSyncProtocol) {
+ return;
+ }
+ MinecraftServer server = MinecraftServer.getServer();
+ int entityId = payload.entityId;
+ ServerLevel world = player.serverLevel();
+ server.execute(() -> {
+ Entity entity = world.getEntity(entityId);
+ if (entity != null) {
+ clearPlayerWatchData(player);
+ if (entity instanceof Player) {
+ if (LeavesConfig.pcaSyncPlayerEntity.equals("NOBODY")) {
+ return;
+ } else if (LeavesConfig.pcaSyncPlayerEntity.equals("BOT")) {
+ if (!(entity instanceof ServerBot)) {
+ return;
+ }
+ } else if (LeavesConfig.pcaSyncPlayerEntity.equals("OPS")) {
+ if (!(entity instanceof ServerBot) && server.getProfilePermissions(player.getGameProfile()) < 2) {
+ return;
+ }
+ } else if (LeavesConfig.pcaSyncPlayerEntity.equals("OPS_AND_SELF")) {
+ if (!(entity instanceof ServerBot) &&
+ server.getProfilePermissions(player.getGameProfile()) < 2 &&
+ entity != player) {
+ return;
+ }
+ } else if (!LeavesConfig.pcaSyncPlayerEntity.equals("EVERYONE")) {
+ // wtf????
+ LeavesLogger.LOGGER.warning("pcaSyncPlayerEntity wtf???");
+ return;
+ }
+ }
+ updateEntity(player, entity);
+
+ Pair<ResourceLocation, Entity> pair = new ImmutablePair<>(entity.level().dimension().location(), entity);
+ lock.lock();
+ playerWatchEntity.put(player, pair);
+ if (!entityWatchPlayerSet.containsKey(pair)) {
+ entityWatchPlayerSet.put(pair, new HashSet<>());
+ }
+ entityWatchPlayerSet.get(pair).add(player);
+ lock.unlock();
+ }
+ });
+ }
+
+ public static void enablePcaSyncProtocol(@NotNull ServerPlayer player) {
+ ProtocolUtils.sendEmptyPayloadPacket(player, ENABLE_PCA_SYNC_PROTOCOL);
+ }
+
+ public static void disablePcaSyncProtocol(@NotNull ServerPlayer player) {
+ ProtocolUtils.sendEmptyPayloadPacket(player, DISABLE_PCA_SYNC_PROTOCOL);
+ }
+
+ public static void updateEntity(@NotNull ServerPlayer player, @NotNull Entity entity) {
+ CompoundTag nbt = entity.saveWithoutId(new CompoundTag());
+ ProtocolUtils.sendPayloadPacket(player, UPDATE_ENTITY, buf -> {
+ buf.writeResourceLocation(entity.level().dimension().location());
+ buf.writeInt(entity.getId());
+ buf.writeNbt(nbt);
+ });
+ }
+
+ public static void updateBlockEntity(@NotNull ServerPlayer player, @NotNull BlockEntity blockEntity) {
+ Level world = blockEntity.getLevel();
+
+ if (world == null) {
+ return;
+ }
+
+ ProtocolUtils.sendPayloadPacket(player, UPDATE_BLOCK_ENTITY, buf -> {
+ buf.writeResourceLocation(world.dimension().location());
+ buf.writeBlockPos(blockEntity.getBlockPos());
+ buf.writeNbt(blockEntity.saveWithId());
+ });
+ }
+
+ private static MutablePair<ResourceLocation, Entity> getResourceLocationEntityPair(ResourceLocation ResourceLocation, Entity entity) {
+ pairLock.lock();
+ ResourceLocationEntityPair.setLeft(ResourceLocation);
+ ResourceLocationEntityPair.setRight(entity);
+ pairLock.unlock();
+ return ResourceLocationEntityPair;
+ }
+
+ private static MutablePair<ResourceLocation, BlockPos> getResourceLocationBlockPosPair(ResourceLocation ResourceLocation, BlockPos pos) {
+ pairLock.lock();
+ ResourceLocationBlockPosPair.setLeft(ResourceLocation);
+ ResourceLocationBlockPosPair.setRight(pos);
+ pairLock.unlock();
+ return ResourceLocationBlockPosPair;
+ }
+
+ private static @Nullable Set<ServerPlayer> getWatchPlayerList(@NotNull Entity entity) {
+ return entityWatchPlayerSet.get(getResourceLocationEntityPair(entity.level().dimension().location(), entity));
+ }
+
+ private static @Nullable Set<ServerPlayer> getWatchPlayerList(@NotNull Level world, @NotNull BlockPos blockPos) {
+ return blockPosWatchPlayerSet.get(getResourceLocationBlockPosPair(world.dimension().location(), blockPos));
+ }
+
+ public static boolean syncEntityToClient(@NotNull Entity entity) {
+ if (entity.level().isClientSide()) {
+ return false;
+ }
+ lock.lock();
+ Set<ServerPlayer> playerList = getWatchPlayerList(entity);
+ boolean ret = false;
+ if (playerList != null) {
+ for (ServerPlayer player : playerList) {
+ updateEntity(player, entity);
+ ret = true;
+ }
+ }
+ lock.unlock();
+ return ret;
+ }
+
+ public static boolean syncBlockEntityToClient(@NotNull BlockEntity blockEntity) {
+ boolean ret = false;
+ Level world = blockEntity.getLevel();
+ BlockPos pos = blockEntity.getBlockPos();
+ if (world != null) {
+ if (world.isClientSide()) {
+ return false;
+ }
+ BlockState blockState = world.getBlockState(pos);
+ lock.lock();
+ Set<ServerPlayer> playerList = getWatchPlayerList(world, blockEntity.getBlockPos());
+
+ Set<ServerPlayer> playerListAdj = null;
+
+ if (blockState.getBlock() instanceof ChestBlock) {
+ if (blockState.getValue(ChestBlock.TYPE) != ChestType.SINGLE) {
+ BlockPos posAdj = pos.offset(ChestBlock.getConnectedDirection(blockState).getNormal());
+ playerListAdj = getWatchPlayerList(world, posAdj);
+ }
+ }
+ if (playerListAdj != null) {
+ if (playerList == null) {
+ playerList = playerListAdj;
+ } else {
+ playerList.addAll(playerListAdj);
+ }
+ }
+
+ if (playerList != null) {
+ for (ServerPlayer player : playerList) {
+ updateBlockEntity(player, blockEntity);
+ ret = true;
+ }
+ }
+ lock.unlock();
+ }
+ return ret;
+ }
+
+ private static void clearPlayerWatchEntity(ServerPlayer player) {
+ lock.lock();
+ Pair<ResourceLocation, Entity> pair = playerWatchEntity.get(player);
+ if (pair != null) {
+ Set<ServerPlayer> playerSet = entityWatchPlayerSet.get(pair);
+ playerSet.remove(player);
+ if (playerSet.isEmpty()) {
+ entityWatchPlayerSet.remove(pair);
+ }
+ playerWatchEntity.remove(player);
+ }
+ lock.unlock();
+ }
+
+ private static void clearPlayerWatchBlock(ServerPlayer player) {
+ lock.lock();
+ Pair<ResourceLocation, BlockPos> pair = playerWatchBlockPos.get(player);
+ if (pair != null) {
+ Set<ServerPlayer> playerSet = blockPosWatchPlayerSet.get(pair);
+ playerSet.remove(player);
+ if (playerSet.isEmpty()) {
+ blockPosWatchPlayerSet.remove(pair);
+ }
+ playerWatchBlockPos.remove(player);
+ }
+ lock.unlock();
+ }
+
+ public static void disablePcaSyncProtocolGlobal() {
+ lock.lock();
+ playerWatchBlockPos.clear();
+ playerWatchEntity.clear();
+ blockPosWatchPlayerSet.clear();
+ entityWatchPlayerSet.clear();
+ lock.unlock();
+ for (ServerPlayer player : MinecraftServer.getServer().getPlayerList().getPlayers()) {
+ disablePcaSyncProtocol(player);
+ }
+ }
+
+ public static void enablePcaSyncProtocolGlobal() {
+ for (ServerPlayer player : MinecraftServer.getServer().getPlayerList().getPlayers()) {
+ enablePcaSyncProtocol(player);
+ }
+ }
+
+
+ public static void clearPlayerWatchData(ServerPlayer player) {
+ PcaSyncProtocol.clearPlayerWatchBlock(player);
+ PcaSyncProtocol.clearPlayerWatchEntity(player);
+ }
+
+ public record SyncBlockEntityPayload(BlockPos pos) implements CustomPacketPayload {
+
+ public static final ResourceLocation SYNC_BLOCK_ENTITY = PcaSyncProtocol.id("sync_block_entity");
+
+ public SyncBlockEntityPayload(ResourceLocation id, FriendlyByteBuf buf) {
+ this(buf.readBlockPos());
+ }
+
+ @Override
+ public void write(FriendlyByteBuf buf) {
+ buf.writeBlockPos(pos);
+ }
+
+ @Override
+ public @NotNull ResourceLocation id() {
+ return SYNC_BLOCK_ENTITY;
+ }
+ }
+
+ public record SyncEntityPayload(int entityId) implements CustomPacketPayload {
+
+ public static final ResourceLocation SYNC_ENTITY = PcaSyncProtocol.id("sync_entity");
+
+ public SyncEntityPayload(ResourceLocation id, FriendlyByteBuf buf) {
+ this(buf.readInt());
+ }
+
+ @Override
+ public void write(FriendlyByteBuf buf) {
+ buf.writeInt(entityId);
+ }
+
+ @Override
+ public @NotNull ResourceLocation id() {
+ return SYNC_ENTITY;
+ }
+ }
+}