diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TechhiderbugCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TechhiderbugCommand.java index 5527176b..f4ae7c73 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TechhiderbugCommand.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TechhiderbugCommand.java @@ -60,7 +60,7 @@ public class TechhiderbugCommand extends FightSWCommand { writer.append('\n'); writer.append("Hidden regions: "); - FightSystem.getTechHider().getHiddenRegion().forEach((p, r) -> writer.append(p.getName()).append(':').append(r.toString()).append(' ')); + FightSystem.getTechHider().getHiddenRegion().forEach((p, r) -> writer.append(p.getName()).append(':').append(Arrays.toString(r)).append(' ')); writer.append('\n'); writer.append("TinyProtocol: "); diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/TechHiderWrapper.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/TechHiderWrapper.java index c12fd38b..abc5dd52 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/TechHiderWrapper.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/TechHiderWrapper.java @@ -51,6 +51,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerQuitEvent; +import java.util.Arrays; import java.util.Collection; import java.util.Objects; import java.util.Set; @@ -62,8 +63,10 @@ public class TechHiderWrapper extends StateDependent implements Listener { public static final boolean ENABLED = !Config.OnlyPublicSchematics && !Config.test() && Config.GameModeConfig.Techhider.Active; + private static final Region[] NO_REGIONS = new Region[0]; + @Getter - private final ConcurrentHashMap hiddenRegion = new ConcurrentHashMap<>(); + private final ConcurrentHashMap hiddenRegion = new ConcurrentHashMap<>(); private final HullHider hullHider; public TechHiderWrapper(HullHider hullHider) { @@ -97,14 +100,9 @@ public class TechHiderWrapper extends StateDependent implements Listener { private AccessPrivilegeProvider newProvider(Set blockStatesToObfuscate, Set blocksToObfuscate, Set> blockEntityTypeToObfuscate) { return new AccessPrivilegeProvider() { - @Override - public boolean isEveryonePrivilegedToAccessAllDataWithinChunk(int chunkX, int chunkZ) { - return Fight.teams().stream().map(FightTeam::getExtendRegion).allMatch(region -> region.chunkOutside(chunkX, chunkZ)); - } - @Override public ForPlayer forPlayer(Player p) { - return new FightPlayerAccess(p, getHiddenRegion(p), blockStatesToObfuscate, blocksToObfuscate, blockEntityTypeToObfuscate); + return new FightPlayerAccess(p, getHiddenRegions(p), blockStatesToObfuscate, blocksToObfuscate, blockEntityTypeToObfuscate); } @Override @@ -119,24 +117,37 @@ public class TechHiderWrapper extends StateDependent implements Listener { */ private class FightPlayerAccess implements ForPlayer { private final Player player; - private final Region hiddenRegion; + private final Region[] hiddenRegions; private final Set blockStatesToObfuscate; private final Set blocksToObfuscate; private final Set> blockEntityTypeToObfuscate; - private FightPlayerAccess(Player player, Region hiddenRegion, Set blockStatesToObfuscate, Set blocksToObfuscate, Set> blockEntityTypeToObfuscate) { + private FightPlayerAccess(Player player, Region[] hiddenRegions, Set blockStatesToObfuscate, Set blocksToObfuscate, Set> blockEntityTypeToObfuscate) { this.player = player; - this.hiddenRegion = hiddenRegion; + this.hiddenRegions = hiddenRegions; this.blockStatesToObfuscate = blockStatesToObfuscate; this.blocksToObfuscate = blocksToObfuscate; this.blockEntityTypeToObfuscate = blockEntityTypeToObfuscate; } + private boolean isHidden(int blockX, int blockY, int blockZ) { + for (Region region : hiddenRegions) { + if (region.inRegion(blockX, blockY, blockZ)) return true; + } + return false; + } + @Override public Player getPlayer() { return player; } + @Override + public boolean canAccessAllDataWithinChunk(int chunkX, int chunkZ) { + // Hulls the player may not see lie within the hidden regions, everything outside of them is not critical + return Arrays.stream(hiddenRegions).allMatch(region -> region.chunkOutside(chunkX, chunkZ)); + } + @Override public boolean canAccessPosition(int blockX, int blockY, int blockZ) { return !hullHider.isBlockHidden(player, blockX, blockY, blockZ); @@ -144,12 +155,12 @@ public class TechHiderWrapper extends StateDependent implements Listener { @Override public boolean canAccessBlock(int blockX, int blockY, int blockZ, Block block) { - return !hiddenRegion.inRegion(blockX, blockY, blockZ) || !blocksToObfuscate.contains(block); + return !isHidden(blockX, blockY, blockZ) || !blocksToObfuscate.contains(block); } @Override public boolean canAccessBlockState(int blockX, int blockY, int blockZ, BlockState blockState) { - return !hiddenRegion.inRegion(blockX, blockY, blockZ) || !blockStatesToObfuscate.contains(blockState); + return !isHidden(blockX, blockY, blockZ) || !blockStatesToObfuscate.contains(blockState); } // TODO will require entity tracking on the netty thread to prevent future race conditions @@ -166,7 +177,7 @@ public class TechHiderWrapper extends StateDependent implements Listener { @Override public boolean canAccessBlockEntity(int blockX, int blockY, int blockZ, BlockEntityType type) { - return !hiddenRegion.inRegion(blockX, blockY, blockZ) || !blockEntityTypeToObfuscate.contains(type); + return !isHidden(blockX, blockY, blockZ) || !blockEntityTypeToObfuscate.contains(type); } } @@ -177,19 +188,19 @@ public class TechHiderWrapper extends StateDependent implements Listener { @EventHandler public void teamJoin(TeamSpawnEvent e) { - e.getFightPlayer().ifPlayer(player -> hiddenRegion.put(player, getHiddenRegion(player))); + e.getFightPlayer().ifPlayer(player -> hiddenRegion.put(player, getHiddenRegions(player))); } @EventHandler public void boarding(BoardingEvent e) { - e.getFightPlayer().ifPlayer(player -> hiddenRegion.put(player, getHiddenRegion(player))); + e.getFightPlayer().ifPlayer(player -> hiddenRegion.put(player, getHiddenRegions(player))); } @EventHandler public void teamLeave(TeamLeaveEvent e) { e.getFightPlayer().ifPlayer(player -> { if (player.isOnline()) { - hiddenRegion.put(player, getHiddenRegion(player)); + hiddenRegion.put(player, getHiddenRegions(player)); } }); } @@ -210,16 +221,19 @@ public class TechHiderWrapper extends StateDependent implements Listener { }); } - private Region getHiddenRegion(Player player) { - if (Config.isReferee(player)) return Region.EMPTY; + private Region[] getHiddenRegions(Player player) { + if (Config.isReferee(player)) return NO_REGIONS; // Single lookup: runs on netty threads, the player can leave the team at any time FightPlayer fightPlayer = Fight.getFightPlayer(player); - if (fightPlayer == null) return Config.ArenaRegion; + if (fightPlayer == null) { + // Spectators: both teams, the rest of the arena contains nothing critical + return Fight.teams().stream().map(FightTeam::getExtendRegion).toArray(Region[]::new); + } - if (fightPlayer.canEntern()) return Region.EMPTY; + if (fightPlayer.canEntern()) return NO_REGIONS; - return Fight.getOpposite(fightPlayer.getTeam()).getExtendRegion(); + return new Region[]{Fight.getOpposite(fightPlayer.getTeam()).getExtendRegion()}; } private Stream getWaterloggedBlockStates() { diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/AccessPrivilegeProvider.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/AccessPrivilegeProvider.java index 740528a8..38b9b463 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/AccessPrivilegeProvider.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/AccessPrivilegeProvider.java @@ -25,8 +25,6 @@ import net.minecraft.world.level.block.state.BlockState; import org.bukkit.entity.Player; public interface AccessPrivilegeProvider { - boolean isEveryonePrivilegedToAccessAllDataWithinChunk(int chunkX, int chunkZ); - /** * Resolves everything that can change concurrently about this player once. * The result is used for all decisions of one outgoing packet (including all packets of a bundle). @@ -41,6 +39,11 @@ public interface AccessPrivilegeProvider { interface ForPlayer { Player getPlayer(); + /** + * @return true if nothing within this chunk is restricted for this player, so the chunk may be sent unmodified + */ + boolean canAccessAllDataWithinChunk(int chunkX, int chunkZ); + boolean canAccessPosition(int blockX, int blockY, int blockZ); boolean canAccessBlock(int blockX, int blockY, int blockZ, Block block); diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java index c24fad71..b4424f30 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java @@ -530,7 +530,7 @@ public class TechHider { } private ClientboundLevelChunkWithLightPacket processChunkWithLight(ForPlayer access, ClientboundLevelChunkWithLightPacket packet) { - if (privilegeProvider.isEveryonePrivilegedToAccessAllDataWithinChunk(packet.getX(), packet.getZ())) { + if (access.canAccessAllDataWithinChunk(packet.getX(), packet.getZ())) { return packet; } else { return chunkHider.processLevelChunkWithLightPacket(access, packet);