From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Samsuik Date: Tue, 21 Sep 2021 23:54:25 +0100 Subject: [PATCH] Client Visibility Settings diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java index 6987eeace609fbfba967922e558e09268e0f6d44..e45e2d6094620d761b624bfaf5dfbbed4d559858 100644 --- a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java +++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java @@ -31,7 +31,7 @@ public class ClientboundLevelChunkPacketData { private static final int TWO_MEGABYTES = 2097152; private final Map heightmaps; private final byte[] buffer; - private final List blockEntitiesData; + public final List blockEntitiesData; // Sakura - client visibility settings; private -> public; ATs for some reason don't work here // Paper start - Handle oversized block entities in chunks private final java.util.List> extraPackets = new java.util.ArrayList<>(); private static final int BLOCK_ENTITY_LIMIT = Integer.getInteger("Paper.excessiveTELimit", 750); @@ -153,7 +153,7 @@ public class ClientboundLevelChunkPacketData { return this.heightmaps; } - static class BlockEntityInfo { + public static class BlockEntityInfo { // Sakura - client visibility settings; package-protected -> public; ATs for some reason don't work here public static final StreamCodec STREAM_CODEC = StreamCodec.ofMember( ClientboundLevelChunkPacketData.BlockEntityInfo::write, ClientboundLevelChunkPacketData.BlockEntityInfo::new ); @@ -162,7 +162,7 @@ public class ClientboundLevelChunkPacketData { ); final int packedXZ; final int y; - final BlockEntityType type; + public final BlockEntityType type; // Sakura - client visibility settings; private -> public; ATs for some reason don't work here @Nullable final CompoundTag tag; diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java index 88035581d220dd3653fa2d30102e59e9a9340002..f9dfbf11a39573e839153fd5d72bcf9019540359 100644 --- a/net/minecraft/server/level/ChunkMap.java +++ b/net/minecraft/server/level/ChunkMap.java @@ -173,6 +173,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.handleLegacyStructureIndex(pos); } // Paper end - rewrite chunk system + private final it.unimi.dsi.fastutil.longs.Long2IntMap minimalEntities; // Sakura - client visibility settings; minimal tnt/sand public ChunkMap( ServerLevel level, @@ -235,6 +236,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider ); this.setServerViewDistance(serverViewDistance); this.worldGenContext = new WorldGenContext(level, generator, structureManager, this.lightEngine, null, this::setChunkUnsaved); // Paper - rewrite chunk system + // Sakura start - client visibility settings; minimal tnt/sand + this.minimalEntities = new it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap(); + this.minimalEntities.defaultReturnValue(Integer.MIN_VALUE); + // Sakura end - client visibility settings; minimal tnt/sand } private void setChunkUnsaved(ChunkPos chunkPos) { @@ -1024,6 +1029,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider tracker.serverEntity.sendChanges(); } } + + this.minimalEntities.clear(); // Sakura - client visibility settings; minimal tnt/sand } // Paper end - optimise entity tracker @@ -1263,6 +1270,32 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider return !this.seenBy.isEmpty(); } // Paper end - optimise entity tracker + // Sakura start - client visibility settings; entity visibility + private boolean checkEntityVisibility(final ServerPlayer player) { + final Entity entity = this.entity; + final me.samsuik.sakura.player.visibility.VisibilitySettings settings = player.visibilitySettings; + if (!settings.playerModified() || !(entity.isPrimedTNT || entity.isFallingBlock)) { + return true; + } + + final me.samsuik.sakura.player.visibility.VisibilityType type = entity.isPrimedTNT + ? me.samsuik.sakura.player.visibility.VisibilityTypes.TNT + : me.samsuik.sakura.player.visibility.VisibilityTypes.SAND; + final me.samsuik.sakura.player.visibility.VisibilityState state = settings.get(type); + + if (state == me.samsuik.sakura.player.visibility.VisibilityState.MINIMAL) { + final long key = entity.blockPosition().asLong() ^ entity.getType().hashCode(); + final long visibleEntity = ChunkMap.this.minimalEntities.get(key); + if (visibleEntity != Integer.MIN_VALUE) { + return entity.getId() == visibleEntity; + } else { + ChunkMap.this.minimalEntities.put(key, entity.getId()); + } + } + + return state != me.samsuik.sakura.player.visibility.VisibilityState.OFF; + } + // Sakura end - client visibility settings; entity visibility public TrackedEntity(final Entity entity, final int range, final int updateInterval, final boolean trackDelta) { this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, updateInterval, trackDelta, this, this.seenBy); // Paper @@ -1347,6 +1380,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } flag = flag && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z); // Paper end - Configurable entity tracking range by Y + flag = flag && this.checkEntityVisibility(player); // Sakura start - client visibility settings; entity visibility // CraftBukkit start - respect vanish API if (flag && !player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { // Paper - only consider hits flag = false; diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java index 1b1e2cb3f97de8bce9a88709e3fe02f7c44c77b6..9a963308d5b1a896b0dfe6a47f7d257a173719c5 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java @@ -584,6 +584,22 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe this.playerTickingChunks.remove((LevelChunk)chunkHolder.getCurrentChunk()); } // Paper end - chunk tick iteration + // Sakura start - client visibility settings + public final LongSet explosionPositions = new it.unimi.dsi.fastutil.longs.LongOpenHashSet(); + + public final boolean checkExplosionVisibility(final Vec3 position, final ServerPlayer player) { + final me.samsuik.sakura.player.visibility.VisibilitySettings settings = player.visibilitySettings; + if (settings.isDisabled(me.samsuik.sakura.player.visibility.VisibilityTypes.EXPLOSIONS)) { + return false; + } else if (settings.isToggled(me.samsuik.sakura.player.visibility.VisibilityTypes.EXPLOSIONS)) { + final BlockPos blockPosition = BlockPos.containing(position); + final long encodedPosition = blockPosition.asLong(); + return this.explosionPositions.add(encodedPosition); + } + + return true; + } + // Sakura end - client visibility settings public ServerLevel( MinecraftServer server, @@ -692,6 +708,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe this.chunkDataController = new ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.ChunkDataController((ServerLevel)(Object)this, this.chunkTaskScheduler); // Paper end - rewrite chunk system this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit + this.levelTickScheduler.repeatingTask(this.explosionPositions::clear, 0); // Sakura - client visibility settings } // Paper start @@ -1931,7 +1948,20 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe for (ServerPlayer serverPlayer : this.players) { if (serverPlayer.distanceToSqr(vec3) < 4096.0) { Optional optional = Optional.ofNullable(serverExplosion.getHitPlayers().get(serverPlayer)); - serverPlayer.connection.send(new ClientboundExplodePacket(vec3, radius, i, optional, particleOptions, explosionSound, blockParticles)); + // Sakura start - client visibility settings; let players toggle explosion particles + ParticleOptions particle = particleOptions; + Vec3 position = vec3; + if (!this.checkExplosionVisibility(vec3, serverPlayer)) { + // todo: send knockback through PlayerPositionPacket + if (this.paperConfig().environment.disableExplosionKnockback) { + continue; + } else { + position = new Vec3(0.0, -1024.0, 0.0); + particle = net.minecraft.core.particles.ParticleTypes.SMOKE; + } + } + serverPlayer.connection.send(new ClientboundExplodePacket(position, radius, i, optional, particle, explosionSound, blockParticles)); + // Sakura end - client visibility settings; let players toggle explosion particles } } diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java index 637d60f082ca7aac689f9e7dc940e8c16d414445..24921be00af8df2314e54373c7014b6831940204 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java @@ -473,6 +473,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc return this.viewDistanceHolder; } // Paper end - rewrite chunk system + public final me.samsuik.sakura.player.visibility.PlayerVisibilitySettings visibilitySettings = new me.samsuik.sakura.player.visibility.PlayerVisibilitySettings(); // Sakura - client visibility settings public ServerPlayer(MinecraftServer server, ServerLevel level, GameProfile gameProfile, ClientInformation clientInformation) { super(level, gameProfile); diff --git a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java index c6db2c96db96453daaf49779f588f75f7c3d3d60..fd08d04c13a4064c658e0aad436b48831316129b 100644 --- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java @@ -58,6 +58,60 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack public @Nullable String playerBrand; public final java.util.Set pluginMessagerChannels; // Paper end - retain certain values + // Sakura start - client visibility settings + private boolean filterExtraPackets(final Packet packet, final net.minecraft.server.level.ServerPlayer player) { + final me.samsuik.sakura.player.visibility.VisibilitySettings settings = player.visibilitySettings; + if (settings.isToggled(me.samsuik.sakura.player.visibility.VisibilityTypes.SPAWNERS)) { + if (packet instanceof net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket bedPacket) { + return bedPacket.getType() == net.minecraft.world.level.block.entity.BlockEntityType.MOB_SPAWNER; + } + } + + return false; + } + + private boolean filterOrModifyPacket(final Packet packet, final net.minecraft.server.level.ServerPlayer player) { + final me.samsuik.sakura.player.visibility.VisibilitySettings settings = player.visibilitySettings; + final java.util.List> extraPackets = packet.getExtraPackets(); + if (extraPackets != null) { + // block entity data is sent as an extra packet + extraPackets.removeIf(extraPacket -> this.filterExtraPackets(extraPacket, player)); + } + + if (settings.isToggled(me.samsuik.sakura.player.visibility.VisibilityTypes.SPAWNERS)) { + net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData chunkData = null; + if (packet instanceof net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket chunkPacket) { + chunkData = chunkPacket.getChunkData(); + } else if (packet instanceof net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData chunkPacket) { + chunkData = chunkPacket; + } + + if (chunkData != null) { + chunkData.blockEntitiesData.removeIf(blockEntityInfo -> blockEntityInfo.type == net.minecraft.world.level.block.entity.BlockEntityType.MOB_SPAWNER); + } + + if (packet instanceof net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket bedPacket && bedPacket.getType() == net.minecraft.world.level.block.entity.BlockEntityType.MOB_SPAWNER) { + return true; + } + } + + if (packet instanceof net.minecraft.network.protocol.game.ClientboundBlockEventPacket bePacket) { + if (settings.isToggled(me.samsuik.sakura.player.visibility.VisibilityTypes.PISTONS)) { + return bePacket.getBlock() instanceof net.minecraft.world.level.block.piston.PistonBaseBlock; + } + } + + return false; + } + + private net.minecraft.server.level.ServerPlayer getPlayer() { + if (this instanceof ServerGamePacketListenerImpl gamePacketListener) { + return gamePacketListener.getPlayer(); + } else { + return this.connection.getPlayer(); + } + } + // Sakura end - client visibility settings public ServerCommonPacketListenerImpl(MinecraftServer server, Connection connection, CommonListenerCookie cookie) { this.server = server; @@ -318,6 +372,12 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack } else if (packet instanceof net.minecraft.network.protocol.game.ClientboundSetDefaultSpawnPositionPacket defaultSpawnPositionPacket && this instanceof ServerGamePacketListenerImpl serverGamePacketListener) { serverGamePacketListener.player.compassTarget = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(defaultSpawnPositionPacket.respawnData().pos(), serverGamePacketListener.getPlayer().level()); } + // Sakura start - client visibility settings + final net.minecraft.server.level.ServerPlayer player = this.getPlayer(); + if (player != null && player.visibilitySettings.playerModified() && this.filterOrModifyPacket(packet, player)) { + return; + } + // Sakura end - client visibility settings // CraftBukkit end if (packet.isTerminal()) { this.close(); diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java index 11d55309f3030399386b4deeab58d5f760b3574d..57934cb30c7704f7ff10d25a47df894fabd4687a 100644 --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -3215,6 +3215,7 @@ public class ServerGamePacketListenerImpl event.setCancelled(cancelled); net.minecraft.world.inventory.AbstractContainerMenu oldContainer = this.player.containerMenu; // SPIGOT-1224 + me.samsuik.sakura.player.gui.FeatureGui.clickEvent(event); // Sakura - client visibility settings this.cserver.getPluginManager().callEvent(event); if (this.player.containerMenu != oldContainer) { this.player.containerMenu.resumeRemoteUpdates(); diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java index 40983aa59d0d8ee7e725c3daf2049a8a9d775d70..8d64020b4c4d5f86ab692db05f40e79b9c42ee68 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -535,6 +535,10 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name } // Paper end - optimise entity tracker public boolean pushedByFluid = true; // Sakura - entity pushed by fluid api + // Sakura start - client visibility settings + public boolean isPrimedTNT; + public boolean isFallingBlock; + // Sakura end - client visibility settings public Entity(EntityType entityType, Level level) { this.type = entityType; diff --git a/net/minecraft/world/entity/item/FallingBlockEntity.java b/net/minecraft/world/entity/item/FallingBlockEntity.java index 31e0739bc20096fa368f2b22bb45034a6fe1fe43..c7a930caa2264c9465baf61a0ed8a188119f28c8 100644 --- a/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/net/minecraft/world/entity/item/FallingBlockEntity.java @@ -79,6 +79,7 @@ public class FallingBlockEntity extends Entity { super(entityType, level); this.dropItem = level.sakuraConfig().cannons.sand.dropItems; // Sakura - configure falling blocks dropping items this.heightParity = level.sakuraConfig().cannons.mechanics.fallingBlockParity; // Sakura - configure cannon mechanics + this.isFallingBlock = true; // Sakura - client visibility settings } public FallingBlockEntity(Level level, double x, double y, double z, BlockState state) { diff --git a/net/minecraft/world/entity/item/PrimedTnt.java b/net/minecraft/world/entity/item/PrimedTnt.java index df5b6c6c06fc594c3d51e59bab59a625ac1e4bae..4d0bc49ce0868d7a5a1870be4e19eb08f3f31482 100644 --- a/net/minecraft/world/entity/item/PrimedTnt.java +++ b/net/minecraft/world/entity/item/PrimedTnt.java @@ -63,6 +63,7 @@ public class PrimedTnt extends Entity implements TraceableEntity { public PrimedTnt(EntityType entityType, Level level) { super(entityType, level); this.blocksBuilding = true; + this.isPrimedTNT = true; // Sakura - client visibility settings } public PrimedTnt(Level level, double x, double y, double z, @Nullable LivingEntity owner) {