From 29927985b1fd51e436c685ed989bb5931d039a4a Mon Sep 17 00:00:00 2001 From: Lixfel Date: Sat, 16 Dec 2023 18:21:33 +0100 Subject: [PATCH 1/8] =?UTF-8?q?Initial=20directional=20quadrant=2045=C2=B0?= =?UTF-8?q?=20hullhider=20implementation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lixfel --- .../de/steamwar/fightsystem/FightSystem.java | 1 + .../steamwar/fightsystem/utils/HullHider.java | 295 ++++++++++++++++++ .../de/steamwar/fightsystem/utils/Region.java | 12 +- 3 files changed, 306 insertions(+), 2 deletions(-) create mode 100644 FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java b/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java index c5adc13..fcbafbc 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java @@ -108,6 +108,7 @@ public class FightSystem extends JavaPlugin { new EnterHandler(); techHider = new TechHiderWrapper(); + new HullHider(); new FightWorld(); new FightUI(); new FightStatistics(); diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java b/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java new file mode 100644 index 0000000..08ae9c7 --- /dev/null +++ b/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java @@ -0,0 +1,295 @@ +/* + This file is a part of the SteamWar software. + + Copyright (C) 2022 SteamWar.de-Serverteam + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ + +package de.steamwar.fightsystem.utils; + +import de.steamwar.fightsystem.ArenaMode; +import de.steamwar.fightsystem.Config; +import de.steamwar.fightsystem.FightSystem; +import de.steamwar.fightsystem.fight.Fight; +import de.steamwar.fightsystem.fight.FightTeam; +import de.steamwar.fightsystem.states.FightState; +import de.steamwar.fightsystem.states.OneShotStateDependent; +import de.steamwar.fightsystem.states.StateDependentListener; +import de.steamwar.techhider.BlockIds; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockPhysicsEvent; + +import java.util.*; +import java.util.function.BiConsumer; + +public class HullHider implements Listener { + + private final Hull blue = new Hull(Fight.getBlueTeam()); + private final Hull red = new Hull(Fight.getRedTeam()); + + //SpawnPackets: PacketPlayOutSpawnEntity, PacketPlayOutSpawnEntityWeather, PacketPlayOutSpawnEntityLiving, PacketPlayOutSpawnEntityPainting, PacketPlayOutSpawnEntityPlayer + //One-timePackets: PacketPlayOutEntityAnimation, PacketPlayOutBlockBreakAnimation, PacketPlayOutEntityStatus, PacketPlayOutEntityPosition, PacketPlayOutEntityPositionAndRotation, PacketPlayOutEntityRotation, PacketPlayOutEntityMovement, EntityHeadLook, EntitySoundEffect, CollectItem, EntityTeleport, + //Permanent: EntityMetadata, AttachEntity, EntityEquipment, SetPassengers, EntityProperties, EntityEffect, RemoveEntityEffect + //Other: Effect, Particle, Explosion + //Death: DestroyEntities + public HullHider() { + //TODO player enters/leaves team + new OneShotStateDependent(ArenaMode.AntiTest, FightState.Schem, () -> Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), () -> { + blue.newSchem(); + red.newSchem(); + }, 1)); //TODO better paste timer, SYNC PASTE + new StateDependentListener(ArenaMode.AntiTest, FightState.Schem, this); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockPhysic(BlockPhysicsEvent e) { + Block b = e.getBlock(); + //TODO adapt to 1.8 etc., Look out for Occluding->NotOccluding change + if(e.getSourceBlock() == b && b.getType().isOccluding() && !e.getChangedType().isOccluding()) { + if(blue.region.inRegion(b)) { + blue.updateBlockVisibility(new IntVector(b.getX(), b.getY(), b.getZ())); + blue.printDebug(b.getX(), b.getY(), b.getZ()); + } + if(red.region.inRegion(b)) { + red.updateBlockVisibility(new IntVector(b.getX(), b.getY(), b.getZ())); + red.printDebug(b.getX(), b.getY(), b.getZ()); + } + } + } + + private static class Hull { + private final Region region; + + private final BitSet visibility; + private final Map> blockVisibility = new HashMap<>(); + + private final boolean groundVisible; + + public Hull(FightTeam team) { + this.region = team.getSchemRegion(); + this.groundVisible = region.getMinY() != Config.PlayerRegion.getMinY(); + this.visibility = new BitSet(region.volume()); + + IntVector[] directions; + if(groundVisible) { + directions = new IntVector[] { + new IntVector(1, 0, 0), + new IntVector(-1, 0, 0), + new IntVector(0, 1, 0), + new IntVector(0, -1, 0), + new IntVector(0, 0, 1), + new IntVector(0, 0, -1) + }; + } else { + directions = new IntVector[] { + new IntVector(1, 0, 0), + new IntVector(-1, 0, 0), + new IntVector(0, -1, 0), + new IntVector(0, 0, 1), + new IntVector(0, 0, -1) + }; + } + + for(IntVector direction : directions) { + Map map = new HashMap<>(); + for(int z = (direction.z == 0 ? -1 : 0); z <= 1; z+=2) { + for(int y = (direction.y == 0 ? -1 : 0); y <= 1; y+=2) { + for(int x = (direction.x == 0 ? -1 : 0); x <= 1; x+=2) { + map.put(new IntVector(x, y, z), new BitSet(region.volume())); + } + } + } + blockVisibility.put(direction, map); + } + } + + private final int air = BlockIds.impl.materialToId(Material.AIR); + private final int stone = BlockIds.impl.materialToId(Material.STONE); + private final int red = BlockIds.impl.materialToId(Material.RED_CONCRETE); + public void printDebug(int x, int y, int z) { + int id = coordToId(x, y, z); + + BlockIdWrapper.impl.setBlock(Config.world, x, y + Config.BlueExtendRegion.getSizeY(), z, visibility.get(id) ? (new IntVector(x, y, z).isOccluding() ? red : air) : stone); + } + + public void forEachBorder(BiConsumer f) { + for(int x = region.getMinX(); x < region.getMaxX(); x++) { + for(int z = region.getMinZ(); z < region.getMaxZ(); z++) { + if(groundVisible) + f.accept(new IntVector(x, region.getMinY(), z), new IntVector(0, 1, 0)); + f.accept(new IntVector(x, region.getMaxY()-1, z), new IntVector(0, -1, 0)); + } + } + + for(int x = region.getMinX(); x < region.getMaxX(); x++) { + for(int y = region.getMinY(); y < region.getMaxY(); y++) { + f.accept(new IntVector(x, y, region.getMinZ()), new IntVector(0, 0, 1)); + f.accept(new IntVector(x, y, region.getMaxZ()-1), new IntVector(0, 0, -1)); + } + } + + for(int z = region.getMinZ(); z < region.getMaxZ(); z++) { + for(int y = region.getMinY(); y < region.getMaxY(); y++) { + f.accept(new IntVector(region.getMinX(), y, z), new IntVector(1, 0, 0)); + f.accept(new IntVector(region.getMaxX()-1, y, z), new IntVector(-1, 0, 0)); + } + } + } + + public void newSchem() { + visibility.clear(); + for(Map direction : blockVisibility.values()) { + for(BitSet set : direction.values()) + set.clear(); + } + + long start = System.currentTimeMillis(); + forEachBorder(this::sideInit); + System.out.println("finish " + (System.currentTimeMillis() - start) + " ms " + visibility.stream().count()); + + region.forEach(this::printDebug); + } + + private void sideInit(IntVector root, IntVector direction) { + for(Map.Entry quadrant : blockVisibility.get(direction).entrySet()) { + checkBlock(root, direction, quadrant.getKey(), quadrant.getValue()); + } + } + + private void checkBlock(IntVector root, IntVector direction, IntVector quadrant, BitSet quadVisibility) { + Set checkSet = new HashSet<>(); + checkSet.add(root); + + while(!checkSet.isEmpty()) { + Set nextSet = new HashSet<>(); + + for(IntVector block : checkSet) { + if(!block.inRegion(region)) + continue; + + int id = block.toId(region); + if(quadVisibility.get(id)) + continue; + + quadVisibility.set(id); + visibility.set(id); + if(block.isOccluding()) + continue; + + IntVector neighbour = block.add(direction); + nextSet.add(neighbour); + boolean neigbourTransparent = !neighbour.isOccluding(); + if(direction.x == 0 && (neigbourTransparent || !block.add(quadrant.x, 0, 0).isOccluding())) { + nextSet.add(neighbour.add(quadrant.x, 0, 0)); + if(!neighbour.add(quadrant.x, 0, 0).isOccluding()) + nextSet.add(neighbour.add(quadrant)); + } + + if(direction.y == 0 && (neigbourTransparent || !block.add(0, quadrant.y, 0).isOccluding())){ + nextSet.add(neighbour.add(0, quadrant.y, 0)); + if(!neighbour.add(0, quadrant.y, 0).isOccluding()) + nextSet.add(neighbour.add(quadrant)); + } + + if(direction.z == 0 && (neigbourTransparent || !block.add(0, 0, quadrant.z).isOccluding())) { + nextSet.add(neighbour.add(0, 0, quadrant.z)); + if(!neighbour.add(0, 0, quadrant.z).isOccluding()) + nextSet.add(neighbour.add(quadrant)); + } + } + + checkSet = nextSet; + } + } + + private void updateBlockVisibility(IntVector root) { + if(!root.inRegion(region)) + return; + + int id = root.toId(region); + for(Map.Entry> direction : blockVisibility.entrySet()) { + for(Map.Entry quadrant : direction.getValue().entrySet()) { + if(quadrant.getValue().get(id)) { + quadrant.getValue().clear(id); + checkBlock(root, direction.getKey(), quadrant.getKey(), quadrant.getValue()); + } + } + } + } + + private int coordToId(int x, int y, int z) { + return regionCoordToId(x - region.getMinX(), y - region.getMinY(), z - region.getMinZ()); + } + private int regionCoordToId(int x, int y, int z) { + return (y * region.getSizeZ() + z) * region.getSizeX() + x; + } + } + + private static class IntVector { + private final int x; + private final int y; + private final int z; + + public IntVector(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public boolean inRegion(Region region) { + return region.inRegion(x, y, z); + } + + public int toId(Region region) { + return ((y - region.getMinY()) * region.getSizeZ() + (z - region.getMinZ())) * region.getSizeX() + (x - region.getMinX()); + } + + public boolean isOccluding() { + return Config.world.getBlockAt(x, y, z).getType().isOccluding(); //TODO techhiderblocks? + } + + public IntVector add(int x, int y, int z) { + return new IntVector(this.x + x, this.y + y, this.z + z); + } + + public IntVector add(IntVector v) { + return add(v.x, v.y, v.z); + } + + @Override + public int hashCode() { + return y << 24 ^ x << 12 ^ z; + } + + @Override + public boolean equals(Object o) { + if(o == null || this.getClass() != o.getClass()) + return false; + + IntVector v = (IntVector) o; + return x == v.x && y == v.y && z == v.z; + } + + @Override + public String toString() { + return x + "," + y + "," + z; + } + } +} diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/utils/Region.java b/FightSystem_Core/src/de/steamwar/fightsystem/utils/Region.java index 6789d14..1308f40 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/utils/Region.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/utils/Region.java @@ -76,6 +76,10 @@ public class Region { return maxX - minX; } + public int getSizeY() { + return maxY - minY; + } + public int getSizeZ() { return maxZ - minZ; } @@ -110,7 +114,7 @@ public class Region { public void forEach(TriConsumer executor) { for(int x = minX; x < maxX; x++) { for(int y = minY; y < maxY; y++) { - for (int z = minZ; z <= maxZ; z++) { + for (int z = minZ; z < maxZ; z++) { executor.accept(x, y, z); } } @@ -146,13 +150,17 @@ public class Region { } public boolean in2dRegion(int x, int z) { - return minX <= x && x < maxX && minZ <= z && z <= maxZ; + return minX <= x && x < maxX && minZ <= z && z < maxZ; } public boolean inRegion(Block block){ return in2dRegion(block) && minY <= block.getY() && block.getY() < maxY; } + public boolean inRegion(int x, int y, int z) { + return in2dRegion(x, z) && minY <= y && y < maxY; + } + public interface TriConsumer{ void accept(T x, V y, U z); } -- 2.39.2 From 4d5f4e9be6c1e411551d1390ac44359a411df7cc Mon Sep 17 00:00:00 2001 From: Lixfel Date: Sat, 16 Dec 2023 21:59:56 +0100 Subject: [PATCH 2/8] =?UTF-8?q?Fast=20recursive=2045=C2=B0=20approx=20hull?= =?UTF-8?q?hider=20implementation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lixfel --- .../de/steamwar/fightsystem/FightSystem.java | 7 +- .../fightsystem/fight/FightSchematic.java | 2 +- .../steamwar/fightsystem/utils/HullHider.java | 217 +++++++++--------- 3 files changed, 111 insertions(+), 115 deletions(-) diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java b/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java index fcbafbc..48fe546 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java @@ -54,6 +54,7 @@ public class FightSystem extends JavaPlugin { private FightTeam lastWinner; private String lastWinreason; private TechHiderWrapper techHider; + private HullHider hullHider; @Override public void onLoad() { @@ -108,7 +109,7 @@ public class FightSystem extends JavaPlugin { new EnterHandler(); techHider = new TechHiderWrapper(); - new HullHider(); + hullHider = new HullHider(); new FightWorld(); new FightUI(); new FightStatistics(); @@ -219,6 +220,10 @@ public class FightSystem extends JavaPlugin { return plugin.techHider; } + public static HullHider getHullHider() { + return plugin.hullHider; + } + public static void shutdown() { //Staggered kick to prevent lobby overloading if(Bukkit.getOnlinePlayers().isEmpty()){ diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightSchematic.java b/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightSchematic.java index ee1ab0a..e22c50c 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightSchematic.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightSchematic.java @@ -45,7 +45,6 @@ import java.io.IOException; import java.util.List; import java.util.Random; import java.util.logging.Level; -import java.util.stream.Stream; public class FightSchematic extends StateDependent { @@ -149,6 +148,7 @@ public class FightSchematic extends StateDependent { ).add(new Vector(rotate ? 1 : 0, 0, rotate ? 1 : 0)), new AffineTransform().rotateY(rotate ? 180 : 0) ); + FightSystem.getHullHider().initialize(team); Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), freezer::disable, 3); Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), team::teleportToSpawn, 40); diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java b/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java index 08ae9c7..775c34d 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java @@ -19,16 +19,13 @@ package de.steamwar.fightsystem.utils; -import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightTeam; import de.steamwar.fightsystem.states.FightState; -import de.steamwar.fightsystem.states.OneShotStateDependent; import de.steamwar.fightsystem.states.StateDependentListener; import de.steamwar.techhider.BlockIds; -import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.event.EventHandler; @@ -38,11 +35,11 @@ import org.bukkit.event.block.BlockPhysicsEvent; import java.util.*; import java.util.function.BiConsumer; +import java.util.logging.Level; public class HullHider implements Listener { - private final Hull blue = new Hull(Fight.getBlueTeam()); - private final Hull red = new Hull(Fight.getRedTeam()); + private final Map hulls = new HashMap<>(); //SpawnPackets: PacketPlayOutSpawnEntity, PacketPlayOutSpawnEntityWeather, PacketPlayOutSpawnEntityLiving, PacketPlayOutSpawnEntityPainting, PacketPlayOutSpawnEntityPlayer //One-timePackets: PacketPlayOutEntityAnimation, PacketPlayOutBlockBreakAnimation, PacketPlayOutEntityStatus, PacketPlayOutEntityPosition, PacketPlayOutEntityPositionAndRotation, PacketPlayOutEntityRotation, PacketPlayOutEntityMovement, EntityHeadLook, EntitySoundEffect, CollectItem, EntityTeleport, @@ -50,41 +47,40 @@ public class HullHider implements Listener { //Other: Effect, Particle, Explosion //Death: DestroyEntities public HullHider() { + if(TechHiderWrapper.ENABLED) + Fight.teams().forEach(team -> hulls.put(team, new Hull(team))); + + new StateDependentListener(TechHiderWrapper.ENABLED, FightState.Schem, this); //TODO player enters/leaves team - new OneShotStateDependent(ArenaMode.AntiTest, FightState.Schem, () -> Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), () -> { - blue.newSchem(); - red.newSchem(); - }, 1)); //TODO better paste timer, SYNC PASTE - new StateDependentListener(ArenaMode.AntiTest, FightState.Schem, this); + } + + public void initialize(FightTeam team) { + if(!TechHiderWrapper.ENABLED) + return; + + hulls.get(team).initialize(); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockPhysic(BlockPhysicsEvent e) { - Block b = e.getBlock(); - //TODO adapt to 1.8 etc., Look out for Occluding->NotOccluding change - if(e.getSourceBlock() == b && b.getType().isOccluding() && !e.getChangedType().isOccluding()) { - if(blue.region.inRegion(b)) { - blue.updateBlockVisibility(new IntVector(b.getX(), b.getY(), b.getZ())); - blue.printDebug(b.getX(), b.getY(), b.getZ()); - } - if(red.region.inRegion(b)) { - red.updateBlockVisibility(new IntVector(b.getX(), b.getY(), b.getZ())); - red.printDebug(b.getX(), b.getY(), b.getZ()); - } + if(FlatteningWrapper.impl.doRecord(e)) { + hulls.values().forEach(hull -> hull.updateBlockVisibility(e.getBlock(), e.getChangedType())); } } private static class Hull { private final Region region; + private final boolean groundVisible; + private final BitSet occluding; private final BitSet visibility; private final Map> blockVisibility = new HashMap<>(); - private final boolean groundVisible; public Hull(FightTeam team) { this.region = team.getSchemRegion(); this.groundVisible = region.getMinY() != Config.PlayerRegion.getMinY(); + this.occluding = new BitSet(region.volume()); this.visibility = new BitSet(region.volume()); IntVector[] directions; @@ -107,6 +103,7 @@ public class HullHider implements Listener { }; } + // Generate quadrants for each direction for(IntVector direction : directions) { Map map = new HashMap<>(); for(int z = (direction.z == 0 ? -1 : 0); z <= 1; z+=2) { @@ -120,16 +117,62 @@ public class HullHider implements Listener { } } + public void initialize() { + visibility.clear(); + occluding.clear(); + for(Map direction : blockVisibility.values()) { + for(BitSet set : direction.values()) + set.clear(); + } + + long start = System.currentTimeMillis(); + region.forEach((x, y, z) -> { + IntVector block = new IntVector(x, y, z); + if(Config.world.getBlockAt(x, y, z).getType().isOccluding()) //TODO more accurate check + occluding.set(block.toId(region)); + }); + forEachBorder((root, direction) -> { + for(Map.Entry quadrant : blockVisibility.get(direction).entrySet()) { + checkBlock(root, direction, quadrant.getKey(), quadrant.getValue()); + } + }); + FightSystem.getPlugin().getLogger().log(Level.INFO, () -> "[HullHider] initialisation finished: " + (System.currentTimeMillis() - start) + " ms, visible blocks: " + visibility.stream().count()); + + region.forEach(this::printDebug); + } + + public void updateBlockVisibility(Block b, Material changedType) { + IntVector root = new IntVector(b.getX(), b.getY(), b.getZ()); + if(root.notInRegion(region)) + return; + + int id = root.toId(region); + if(!occluding.get(id) || changedType.isOccluding()) //TODO more accurate check + return; + + occluding.clear(id); + for(Map.Entry> direction : blockVisibility.entrySet()) { + for(Map.Entry quadrant : direction.getValue().entrySet()) { + if(quadrant.getValue().get(id)) { + quadrant.getValue().clear(id); + checkBlock(root, direction.getKey(), quadrant.getKey(), quadrant.getValue()); + } + } + } + + printDebug(root.x, root.y, root.z); + } + private final int air = BlockIds.impl.materialToId(Material.AIR); private final int stone = BlockIds.impl.materialToId(Material.STONE); private final int red = BlockIds.impl.materialToId(Material.RED_CONCRETE); - public void printDebug(int x, int y, int z) { - int id = coordToId(x, y, z); + private void printDebug(int x, int y, int z) { + int id = new IntVector(x, y, z).toId(region); - BlockIdWrapper.impl.setBlock(Config.world, x, y + Config.BlueExtendRegion.getSizeY(), z, visibility.get(id) ? (new IntVector(x, y, z).isOccluding() ? red : air) : stone); + BlockIdWrapper.impl.setBlock(Config.world, x, y + Config.BlueExtendRegion.getSizeY(), z, visibility.get(id) ? (occluding.get(id) ? red : air) : stone); } - public void forEachBorder(BiConsumer f) { + private void forEachBorder(BiConsumer f) { for(int x = region.getMinX(); x < region.getMaxX(); x++) { for(int z = region.getMinZ(); z < region.getMaxZ(); z++) { if(groundVisible) @@ -153,92 +196,44 @@ public class HullHider implements Listener { } } - public void newSchem() { - visibility.clear(); - for(Map direction : blockVisibility.values()) { - for(BitSet set : direction.values()) - set.clear(); - } - - long start = System.currentTimeMillis(); - forEachBorder(this::sideInit); - System.out.println("finish " + (System.currentTimeMillis() - start) + " ms " + visibility.stream().count()); - - region.forEach(this::printDebug); - } - - private void sideInit(IntVector root, IntVector direction) { - for(Map.Entry quadrant : blockVisibility.get(direction).entrySet()) { - checkBlock(root, direction, quadrant.getKey(), quadrant.getValue()); - } - } - - private void checkBlock(IntVector root, IntVector direction, IntVector quadrant, BitSet quadVisibility) { - Set checkSet = new HashSet<>(); - checkSet.add(root); - - while(!checkSet.isEmpty()) { - Set nextSet = new HashSet<>(); - - for(IntVector block : checkSet) { - if(!block.inRegion(region)) - continue; - - int id = block.toId(region); - if(quadVisibility.get(id)) - continue; - - quadVisibility.set(id); - visibility.set(id); - if(block.isOccluding()) - continue; - - IntVector neighbour = block.add(direction); - nextSet.add(neighbour); - boolean neigbourTransparent = !neighbour.isOccluding(); - if(direction.x == 0 && (neigbourTransparent || !block.add(quadrant.x, 0, 0).isOccluding())) { - nextSet.add(neighbour.add(quadrant.x, 0, 0)); - if(!neighbour.add(quadrant.x, 0, 0).isOccluding()) - nextSet.add(neighbour.add(quadrant)); - } - - if(direction.y == 0 && (neigbourTransparent || !block.add(0, quadrant.y, 0).isOccluding())){ - nextSet.add(neighbour.add(0, quadrant.y, 0)); - if(!neighbour.add(0, quadrant.y, 0).isOccluding()) - nextSet.add(neighbour.add(quadrant)); - } - - if(direction.z == 0 && (neigbourTransparent || !block.add(0, 0, quadrant.z).isOccluding())) { - nextSet.add(neighbour.add(0, 0, quadrant.z)); - if(!neighbour.add(0, 0, quadrant.z).isOccluding()) - nextSet.add(neighbour.add(quadrant)); - } - } - - checkSet = nextSet; - } - } - - private void updateBlockVisibility(IntVector root) { - if(!root.inRegion(region)) + private void checkBlock(IntVector block, IntVector direction, IntVector quadrant, BitSet quadVisibility) { + if(block.notInRegion(region)) return; - int id = root.toId(region); - for(Map.Entry> direction : blockVisibility.entrySet()) { - for(Map.Entry quadrant : direction.getValue().entrySet()) { - if(quadrant.getValue().get(id)) { - quadrant.getValue().clear(id); - checkBlock(root, direction.getKey(), quadrant.getKey(), quadrant.getValue()); - } - } + int id = block.toId(region); + if(quadVisibility.get(id)) + return; + + quadVisibility.set(id); + visibility.set(id); + if(occluding.get(id)) + return; + + IntVector neighbour = block.add(direction); + checkBlock(neighbour, direction, quadrant, quadVisibility); + boolean neigbourTransparent = boundedNonOccluding(neighbour); + boolean diagonalReachable = false; + if(direction.x == 0 && (neigbourTransparent || boundedNonOccluding(block.add(quadrant.x, 0, 0)))) { + checkBlock(neighbour.add(quadrant.x, 0, 0), direction, quadrant, quadVisibility); + diagonalReachable = boundedNonOccluding(neighbour.add(quadrant.x, 0, 0)); } + + if(direction.y == 0 && (neigbourTransparent || boundedNonOccluding(block.add(0, quadrant.y, 0)))) { + checkBlock(neighbour.add(0, quadrant.y, 0), direction, quadrant, quadVisibility); + diagonalReachable = diagonalReachable || boundedNonOccluding(neighbour.add(0, quadrant.y, 0)); + } + + if(direction.z == 0 && (neigbourTransparent || boundedNonOccluding(block.add(0, 0, quadrant.z)))) { + checkBlock(neighbour.add(0, 0, quadrant.z), direction, quadrant, quadVisibility); + diagonalReachable = diagonalReachable || boundedNonOccluding(neighbour.add(0, 0, quadrant.z)); + } + + if(diagonalReachable) + checkBlock(neighbour.add(quadrant), direction, quadrant, quadVisibility); } - private int coordToId(int x, int y, int z) { - return regionCoordToId(x - region.getMinX(), y - region.getMinY(), z - region.getMinZ()); - } - private int regionCoordToId(int x, int y, int z) { - return (y * region.getSizeZ() + z) * region.getSizeX() + x; + private boolean boundedNonOccluding(IntVector block) { + return !(block.notInRegion(region) || occluding.get(block.toId(region))); } } @@ -253,18 +248,14 @@ public class HullHider implements Listener { this.z = z; } - public boolean inRegion(Region region) { - return region.inRegion(x, y, z); + public boolean notInRegion(Region region) { + return !region.inRegion(x, y, z); } public int toId(Region region) { return ((y - region.getMinY()) * region.getSizeZ() + (z - region.getMinZ())) * region.getSizeX() + (x - region.getMinX()); } - public boolean isOccluding() { - return Config.world.getBlockAt(x, y, z).getType().isOccluding(); //TODO techhiderblocks? - } - public IntVector add(int x, int y, int z) { return new IntVector(this.x + x, this.y + y, this.z + z); } -- 2.39.2 From 5fab7e540422059a2c13e9698115f50e2997de02 Mon Sep 17 00:00:00 2001 From: Lixfel Date: Sun, 17 Dec 2023 16:18:20 +0100 Subject: [PATCH 3/8] Untested entity 1.18+ hullhiding Signed-off-by: Lixfel --- .../src/de/steamwar/fightsystem/Config.java | 4 +- .../steamwar/fightsystem/fight/FightTeam.java | 2 + .../fightsystem/listener/ArrowStopper.java | 2 +- .../fightsystem/record/PacketProcessor.java | 2 +- .../de/steamwar/fightsystem/utils/Hull.java | 325 ++++++++++++++++++ .../steamwar/fightsystem/utils/HullHider.java | 298 +++++----------- .../fightsystem/utils/TechHiderWrapper.java | 3 +- 7 files changed, 410 insertions(+), 226 deletions(-) create mode 100644 FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/Config.java b/FightSystem_Core/src/de/steamwar/fightsystem/Config.java index 331491f..b1030f7 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/Config.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/Config.java @@ -120,7 +120,7 @@ public class Config { //tech hider parameter public static final boolean TechhiderActive; - public static final Set HiddenBlocks; + public static final Set HiddenBlocks; public static final Set HiddenBlockEntities; public static final String ObfuscateWith; @@ -214,7 +214,7 @@ public class Config { TechhiderActive = config.getBoolean("Techhider.Active", false); ObfuscateWith = config.getString("Techhider.ObfuscateWith", "end_stone").toUpperCase(); - HiddenBlocks = Collections.unmodifiableSet(new HashSet<>(config.getStringList("Techhider.HiddenBlocks"))); + HiddenBlocks = config.getStringList("Techhider.HiddenBlocks").stream().map(String::toUpperCase).map(Material::getMaterial).collect(Collectors.toSet()); HiddenBlockEntities = Collections.unmodifiableSet(new HashSet<>(config.getStringList("Techhider.HiddenBlockEntities"))); if(schemsizeX < 0){ diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java b/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java index 54cad8e..6efb3fd 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java @@ -275,6 +275,7 @@ public class FightTeam { BountifulWrapper.impl.setAttackSpeed(player); player.setFoodLevel(20); player.getInventory().clear(); + FightSystem.getHullHider().removePlayer(this, player); if(FightState.Spectate.contains(FightState.getFightState())) { Fight.setPlayerGamemode(player, GameMode.SPECTATOR); @@ -318,6 +319,7 @@ public class FightTeam { player.getInventory().clear(); if(player.isOnline()){ + FightSystem.getHullHider().addPlayer(this, player); FightSystem.getTechHider().reloadChunks(player, chunksToReload, true); if(ArenaMode.VariableTeams.contains(Config.mode)) diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/listener/ArrowStopper.java b/FightSystem_Core/src/de/steamwar/fightsystem/listener/ArrowStopper.java index e7b4d01..3fd7f7d 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/listener/ArrowStopper.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/listener/ArrowStopper.java @@ -85,7 +85,7 @@ public class ArrowStopper { } private boolean checkBlock(Block block) { - return Config.HiddenBlocks.contains(block.getType().name().toLowerCase()); + return Config.HiddenBlocks.contains(block.getType()); } private boolean invalidEntity(Projectile entity) { diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java b/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java index d7c31fd..f50007a 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java @@ -88,7 +88,7 @@ public class PacketProcessor implements Listener { private final PacketSource source; private final BukkitTask task; private final LinkedList syncList = new LinkedList<>(); - private final Set hiddenBlockIds = Config.HiddenBlocks.stream().map(String::toUpperCase).map(Material::getMaterial).flatMap(m -> BlockIds.impl.materialToAllIds(m).stream()).collect(Collectors.toSet()); + private final Set hiddenBlockIds = Config.HiddenBlocks.stream().flatMap(m -> BlockIds.impl.materialToAllIds(m).stream()).collect(Collectors.toSet()); private final int obfuscateWith = BlockIds.impl.materialToId(Material.getMaterial(Config.ObfuscateWith.toUpperCase())); private final FreezeWorld freezer = new FreezeWorld(); private final REntityServer entityServer = new REntityServer(); diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java b/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java new file mode 100644 index 0000000..904c0cd --- /dev/null +++ b/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java @@ -0,0 +1,325 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2023 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.fightsystem.utils; + +import de.steamwar.fightsystem.Config; +import de.steamwar.fightsystem.FightSystem; +import de.steamwar.fightsystem.fight.FightTeam; +import de.steamwar.techhider.BlockIds; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; + +import java.util.*; +import java.util.function.BiConsumer; +import java.util.logging.Level; + +public class Hull { + + private static boolean isOccluding(Material material) { + return material.isOccluding() || Config.HiddenBlocks.contains(material); + } + + private final Region region; + private final boolean groundVisible; + + private final BitSet occluding; + private final BitSet visibility; + private final Map> blockVisibility = new HashMap<>(); + + private final Set players = new HashSet<>(); + private final Set entities = new HashSet<>(); + + public Hull(FightTeam team) { + this.region = team.getSchemRegion(); + this.groundVisible = region.getMinY() != Config.PlayerRegion.getMinY(); + this.occluding = new BitSet(region.volume()); + this.visibility = new BitSet(region.volume()); + + IntVector[] directions; + if (groundVisible) { + directions = new IntVector[]{ + new IntVector(1, 0, 0), + new IntVector(-1, 0, 0), + new IntVector(0, 1, 0), + new IntVector(0, -1, 0), + new IntVector(0, 0, 1), + new IntVector(0, 0, -1) + }; + } else { + directions = new IntVector[]{ + new IntVector(1, 0, 0), + new IntVector(-1, 0, 0), + new IntVector(0, -1, 0), + new IntVector(0, 0, 1), + new IntVector(0, 0, -1) + }; + } + + // Generate quadrants for each direction + for (IntVector direction : directions) { + Map map = new HashMap<>(); + for (int z = (direction.z == 0 ? -1 : 0); z <= 1; z += 2) { + for (int y = (direction.y == 0 ? -1 : 0); y <= 1; y += 2) { + for (int x = (direction.x == 0 ? -1 : 0); x <= 1; x += 2) { + map.put(new IntVector(x, y, z), new BitSet(region.volume())); + } + } + } + blockVisibility.put(direction, map); + } + } + + @SuppressWarnings("deprecation") + public void addPlayer(Player player, boolean activeHiding) { + if(players.add(player) && activeHiding) { + for(Entity entity : entities) + player.hideEntity(FightSystem.getPlugin(), entity); //TODO 1.15- + } + } + + @SuppressWarnings("deprecation") + public void removePlayer(Player player, boolean activeRemoval) { + if(players.remove(player) && activeRemoval) { + for(Entity entity : entities) + player.showEntity(FightSystem.getPlugin(), entity); //TODO 1.15- + } + } + + public void checkEntity(Entity entity) { + Location location = entity.getLocation(); + if(region.inRegion(location) && !visibility.get(new IntVector(location).toId(region))) { //TODO more precise + if(entities.add(entity)) { + for(Player player : players) + player.hideEntity(FightSystem.getPlugin(), entity); //TODO 1.15- + } + } else { + if(entities.remove(entity)) { + for(Player player : players) + player.showEntity(FightSystem.getPlugin(), entity); //TODO 1.15- + } + } + } + + public void removeEntity(Entity entity) { + entities.remove(entity); + } + + public void initialize() { + visibility.clear(); + occluding.clear(); + for (Map direction : blockVisibility.values()) { + for (BitSet set : direction.values()) + set.clear(); + } + + long start = System.currentTimeMillis(); + region.forEach((x, y, z) -> { + IntVector block = new IntVector(x, y, z); + if (isOccluding(Config.world.getBlockAt(x, y, z).getType())) + occluding.set(block.toId(region)); + }); + forEachBorder((root, direction) -> { + for (Map.Entry quadrant : blockVisibility.get(direction).entrySet()) { + checkBlock(new NullList<>(), root, direction, quadrant.getKey(), quadrant.getValue()); + } + }); + FightSystem.getPlugin().getLogger().log(Level.INFO, () -> "[HullHider] initialisation finished: " + (System.currentTimeMillis() - start) + " ms, visible blocks: " + visibility.cardinality()); + + region.forEach(this::printDebug); + } + + public void updateBlockVisibility(Block b, Material changedType) { + IntVector root = new IntVector(b.getX(), b.getY(), b.getZ()); + if (root.notInRegion(region)) + return; + + int id = root.toId(region); + if (!occluding.get(id) || isOccluding(changedType)) + return; + + List uncovered = new ArrayList<>(); + occluding.clear(id); + for (Map.Entry> direction : blockVisibility.entrySet()) { + for (Map.Entry quadrant : direction.getValue().entrySet()) { + if (quadrant.getValue().get(id)) { + quadrant.getValue().clear(id); + checkBlock(uncovered, root, direction.getKey(), quadrant.getKey(), quadrant.getValue()); + } + } + } + + for (IntVector block : uncovered) + printDebug(block.x, block.y, block.z); + + //TODO uncover entities + } + + private final int air = BlockIds.impl.materialToId(Material.AIR); + private final int stone = BlockIds.impl.materialToId(Material.STONE); + private final int red = BlockIds.impl.materialToId(Material.RED_CONCRETE); + + private void printDebug(int x, int y, int z) { + int id = new IntVector(x, y, z).toId(region); + + BlockIdWrapper.impl.setBlock(Config.world, x, y + Config.BlueExtendRegion.getSizeY(), z, visibility.get(id) ? (occluding.get(id) ? red : air) : stone); + } + + private void forEachBorder(BiConsumer f) { + for (int x = region.getMinX(); x < region.getMaxX(); x++) { + for (int z = region.getMinZ(); z < region.getMaxZ(); z++) { + if (groundVisible) + f.accept(new IntVector(x, region.getMinY(), z), new IntVector(0, 1, 0)); + f.accept(new IntVector(x, region.getMaxY() - 1, z), new IntVector(0, -1, 0)); + } + } + + for (int x = region.getMinX(); x < region.getMaxX(); x++) { + for (int y = region.getMinY(); y < region.getMaxY(); y++) { + f.accept(new IntVector(x, y, region.getMinZ()), new IntVector(0, 0, 1)); + f.accept(new IntVector(x, y, region.getMaxZ() - 1), new IntVector(0, 0, -1)); + } + } + + for (int z = region.getMinZ(); z < region.getMaxZ(); z++) { + for (int y = region.getMinY(); y < region.getMaxY(); y++) { + f.accept(new IntVector(region.getMinX(), y, z), new IntVector(1, 0, 0)); + f.accept(new IntVector(region.getMaxX() - 1, y, z), new IntVector(-1, 0, 0)); + } + } + } + + private void checkBlock(List uncovered, IntVector block, IntVector direction, IntVector quadrant, BitSet quadVisibility) { + if (block.notInRegion(region)) + return; + + int id = block.toId(region); + if (quadVisibility.get(id)) + return; + + quadVisibility.set(id); + if (!visibility.get(id)) { + visibility.set(id); + uncovered.add(block); + } + + if (occluding.get(id)) + return; + + IntVector neighbour = block.add(direction); + checkBlock(uncovered, neighbour, direction, quadrant, quadVisibility); + boolean neigbourTransparent = boundedNonOccluding(neighbour); + boolean diagonalReachable = false; + if (direction.x == 0 && (neigbourTransparent || boundedNonOccluding(block.add(quadrant.x, 0, 0)))) { + checkBlock(uncovered, neighbour.add(quadrant.x, 0, 0), direction, quadrant, quadVisibility); + diagonalReachable = boundedNonOccluding(neighbour.add(quadrant.x, 0, 0)); + } + + if (direction.y == 0 && (neigbourTransparent || boundedNonOccluding(block.add(0, quadrant.y, 0)))) { + checkBlock(uncovered, neighbour.add(0, quadrant.y, 0), direction, quadrant, quadVisibility); + diagonalReachable = diagonalReachable || boundedNonOccluding(neighbour.add(0, quadrant.y, 0)); + } + + if (direction.z == 0 && (neigbourTransparent || boundedNonOccluding(block.add(0, 0, quadrant.z)))) { + checkBlock(uncovered, neighbour.add(0, 0, quadrant.z), direction, quadrant, quadVisibility); + diagonalReachable = diagonalReachable || boundedNonOccluding(neighbour.add(0, 0, quadrant.z)); + } + + if (diagonalReachable) + checkBlock(uncovered, neighbour.add(quadrant), direction, quadrant, quadVisibility); + } + + private boolean boundedNonOccluding(IntVector block) { + return !(block.notInRegion(region) || occluding.get(block.toId(region))); + } + + + private static class IntVector { + private final int x; + private final int y; + private final int z; + + public IntVector(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public IntVector(Location location) { + this.x = location.getBlockX(); + this.y = location.getBlockY(); + this.z = location.getBlockZ(); + } + + public boolean notInRegion(Region region) { + return !region.inRegion(x, y, z); + } + + public int toId(Region region) { + return ((y - region.getMinY()) * region.getSizeZ() + (z - region.getMinZ())) * region.getSizeX() + (x - region.getMinX()); + } + + public IntVector add(int x, int y, int z) { + return new IntVector(this.x + x, this.y + y, this.z + z); + } + + public IntVector add(IntVector v) { + return add(v.x, v.y, v.z); + } + + @Override + public int hashCode() { + return y << 24 ^ x << 12 ^ z; + } + + @Override + public boolean equals(Object o) { + if(o == null || this.getClass() != o.getClass()) + return false; + + IntVector v = (IntVector) o; + return x == v.x && y == v.y && z == v.z; + } + + @Override + public String toString() { + return x + "," + y + "," + z; + } + } + + private static class NullList extends AbstractList { + @Override + public void add(int index, E element) { + // Straight to /dev/null! + } + + @Override + public E get(int index) { + return null; + } + + @Override + public int size() { + return 0; + } + } +} diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java b/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java index 775c34d..1291202 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java @@ -19,23 +19,27 @@ package de.steamwar.fightsystem.utils; -import de.steamwar.fightsystem.Config; -import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightTeam; +import de.steamwar.fightsystem.listener.Recording; import de.steamwar.fightsystem.states.FightState; +import de.steamwar.fightsystem.states.StateDependent; import de.steamwar.fightsystem.states.StateDependentListener; -import de.steamwar.techhider.BlockIds; -import org.bukkit.Material; -import org.bukkit.block.Block; +import de.steamwar.fightsystem.states.StateDependentTask; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPhysicsEvent; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.entity.EntitySpawnEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; -import java.util.*; -import java.util.function.BiConsumer; -import java.util.logging.Level; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; public class HullHider implements Listener { @@ -51,7 +55,18 @@ public class HullHider implements Listener { Fight.teams().forEach(team -> hulls.put(team, new Hull(team))); new StateDependentListener(TechHiderWrapper.ENABLED, FightState.Schem, this); - //TODO player enters/leaves team + new StateDependent(TechHiderWrapper.ENABLED, FightState.Schem) { + @Override + public void enable() { + Bukkit.getOnlinePlayers().forEach(player -> addPlayer(player, true)); + } + + @Override + public void disable() { + Bukkit.getOnlinePlayers().forEach(player -> removePlayer(player, true)); + } + }; + new StateDependentTask(TechHiderWrapper.ENABLED, FightState.Schem, this::onTick, 0, 1); } public void initialize(FightTeam team) { @@ -61,226 +76,69 @@ public class HullHider implements Listener { hulls.get(team).initialize(); } + + public void addPlayer(FightTeam team, Player player) { + if(!TechHiderWrapper.ENABLED) + return; + + hulls.get(team).addPlayer(player, true); + } + + public void removePlayer(FightTeam team, Player player) { + if(!TechHiderWrapper.ENABLED) + return; + + hulls.get(team).removePlayer(player, true); + } + + @EventHandler(priority = EventPriority.HIGH) + public void onJoin(PlayerJoinEvent e) { + addPlayer(e.getPlayer(), false); + } + + @EventHandler + public void onLeave(PlayerQuitEvent e) { + removePlayer(e.getPlayer(), false); + } + + private void addPlayer(Player player, boolean activeHiding) { + FightTeam team = Fight.getPlayerTeam(player); + for(Map.Entry hull : hulls.entrySet()) { + if(hull.getKey() == team) + continue; + + hull.getValue().addPlayer(player, activeHiding); + } + } + + private void removePlayer(Player player, boolean activeRemoval) { + hulls.values().forEach(hull -> hull.removePlayer(player, activeRemoval)); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockPhysic(BlockPhysicsEvent e) { if(FlatteningWrapper.impl.doRecord(e)) { - hulls.values().forEach(hull -> hull.updateBlockVisibility(e.getBlock(), e.getChangedType())); + for (Hull hull : hulls.values()) + hull.updateBlockVisibility(e.getBlock(), e.getChangedType()); } } - private static class Hull { - private final Region region; - private final boolean groundVisible; - private final BitSet occluding; - private final BitSet visibility; - private final Map> blockVisibility = new HashMap<>(); - - - public Hull(FightTeam team) { - this.region = team.getSchemRegion(); - this.groundVisible = region.getMinY() != Config.PlayerRegion.getMinY(); - this.occluding = new BitSet(region.volume()); - this.visibility = new BitSet(region.volume()); - - IntVector[] directions; - if(groundVisible) { - directions = new IntVector[] { - new IntVector(1, 0, 0), - new IntVector(-1, 0, 0), - new IntVector(0, 1, 0), - new IntVector(0, -1, 0), - new IntVector(0, 0, 1), - new IntVector(0, 0, -1) - }; - } else { - directions = new IntVector[] { - new IntVector(1, 0, 0), - new IntVector(-1, 0, 0), - new IntVector(0, -1, 0), - new IntVector(0, 0, 1), - new IntVector(0, 0, -1) - }; - } - - // Generate quadrants for each direction - for(IntVector direction : directions) { - Map map = new HashMap<>(); - for(int z = (direction.z == 0 ? -1 : 0); z <= 1; z+=2) { - for(int y = (direction.y == 0 ? -1 : 0); y <= 1; y+=2) { - for(int x = (direction.x == 0 ? -1 : 0); x <= 1; x+=2) { - map.put(new IntVector(x, y, z), new BitSet(region.volume())); - } - } - } - blockVisibility.put(direction, map); - } - } - - public void initialize() { - visibility.clear(); - occluding.clear(); - for(Map direction : blockVisibility.values()) { - for(BitSet set : direction.values()) - set.clear(); - } - - long start = System.currentTimeMillis(); - region.forEach((x, y, z) -> { - IntVector block = new IntVector(x, y, z); - if(Config.world.getBlockAt(x, y, z).getType().isOccluding()) //TODO more accurate check - occluding.set(block.toId(region)); - }); - forEachBorder((root, direction) -> { - for(Map.Entry quadrant : blockVisibility.get(direction).entrySet()) { - checkBlock(root, direction, quadrant.getKey(), quadrant.getValue()); - } - }); - FightSystem.getPlugin().getLogger().log(Level.INFO, () -> "[HullHider] initialisation finished: " + (System.currentTimeMillis() - start) + " ms, visible blocks: " + visibility.stream().count()); - - region.forEach(this::printDebug); - } - - public void updateBlockVisibility(Block b, Material changedType) { - IntVector root = new IntVector(b.getX(), b.getY(), b.getZ()); - if(root.notInRegion(region)) - return; - - int id = root.toId(region); - if(!occluding.get(id) || changedType.isOccluding()) //TODO more accurate check - return; - - occluding.clear(id); - for(Map.Entry> direction : blockVisibility.entrySet()) { - for(Map.Entry quadrant : direction.getValue().entrySet()) { - if(quadrant.getValue().get(id)) { - quadrant.getValue().clear(id); - checkBlock(root, direction.getKey(), quadrant.getKey(), quadrant.getValue()); - } - } - } - - printDebug(root.x, root.y, root.z); - } - - private final int air = BlockIds.impl.materialToId(Material.AIR); - private final int stone = BlockIds.impl.materialToId(Material.STONE); - private final int red = BlockIds.impl.materialToId(Material.RED_CONCRETE); - private void printDebug(int x, int y, int z) { - int id = new IntVector(x, y, z).toId(region); - - BlockIdWrapper.impl.setBlock(Config.world, x, y + Config.BlueExtendRegion.getSizeY(), z, visibility.get(id) ? (occluding.get(id) ? red : air) : stone); - } - - private void forEachBorder(BiConsumer f) { - for(int x = region.getMinX(); x < region.getMaxX(); x++) { - for(int z = region.getMinZ(); z < region.getMaxZ(); z++) { - if(groundVisible) - f.accept(new IntVector(x, region.getMinY(), z), new IntVector(0, 1, 0)); - f.accept(new IntVector(x, region.getMaxY()-1, z), new IntVector(0, -1, 0)); - } - } - - for(int x = region.getMinX(); x < region.getMaxX(); x++) { - for(int y = region.getMinY(); y < region.getMaxY(); y++) { - f.accept(new IntVector(x, y, region.getMinZ()), new IntVector(0, 0, 1)); - f.accept(new IntVector(x, y, region.getMaxZ()-1), new IntVector(0, 0, -1)); - } - } - - for(int z = region.getMinZ(); z < region.getMaxZ(); z++) { - for(int y = region.getMinY(); y < region.getMaxY(); y++) { - f.accept(new IntVector(region.getMinX(), y, z), new IntVector(1, 0, 0)); - f.accept(new IntVector(region.getMaxX()-1, y, z), new IntVector(-1, 0, 0)); - } - } - } - - private void checkBlock(IntVector block, IntVector direction, IntVector quadrant, BitSet quadVisibility) { - if(block.notInRegion(region)) - return; - - int id = block.toId(region); - if(quadVisibility.get(id)) - return; - - quadVisibility.set(id); - visibility.set(id); - if(occluding.get(id)) - return; - - IntVector neighbour = block.add(direction); - checkBlock(neighbour, direction, quadrant, quadVisibility); - boolean neigbourTransparent = boundedNonOccluding(neighbour); - boolean diagonalReachable = false; - if(direction.x == 0 && (neigbourTransparent || boundedNonOccluding(block.add(quadrant.x, 0, 0)))) { - checkBlock(neighbour.add(quadrant.x, 0, 0), direction, quadrant, quadVisibility); - diagonalReachable = boundedNonOccluding(neighbour.add(quadrant.x, 0, 0)); - } - - if(direction.y == 0 && (neigbourTransparent || boundedNonOccluding(block.add(0, quadrant.y, 0)))) { - checkBlock(neighbour.add(0, quadrant.y, 0), direction, quadrant, quadVisibility); - diagonalReachable = diagonalReachable || boundedNonOccluding(neighbour.add(0, quadrant.y, 0)); - } - - if(direction.z == 0 && (neigbourTransparent || boundedNonOccluding(block.add(0, 0, quadrant.z)))) { - checkBlock(neighbour.add(0, 0, quadrant.z), direction, quadrant, quadVisibility); - diagonalReachable = diagonalReachable || boundedNonOccluding(neighbour.add(0, 0, quadrant.z)); - } - - if(diagonalReachable) - checkBlock(neighbour.add(quadrant), direction, quadrant, quadVisibility); - } - - private boolean boundedNonOccluding(IntVector block) { - return !(block.notInRegion(region) || occluding.get(block.toId(region))); - } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onSpawn(EntitySpawnEvent e) { + hulls.values().forEach(hull -> hull.checkEntity(e.getEntity())); } - private static class IntVector { - private final int x; - private final int y; - private final int z; + private void onTick() { + Recording.iterateOverEntities(Objects::nonNull, entity -> { + for (Hull hull : hulls.values()) + hull.checkEntity(entity); + }); + } - public IntVector(int x, int y, int z) { - this.x = x; - this.y = y; - this.z = z; - } - - public boolean notInRegion(Region region) { - return !region.inRegion(x, y, z); - } - - public int toId(Region region) { - return ((y - region.getMinY()) * region.getSizeZ() + (z - region.getMinZ())) * region.getSizeX() + (x - region.getMinX()); - } - - public IntVector add(int x, int y, int z) { - return new IntVector(this.x + x, this.y + y, this.z + z); - } - - public IntVector add(IntVector v) { - return add(v.x, v.y, v.z); - } - - @Override - public int hashCode() { - return y << 24 ^ x << 12 ^ z; - } - - @Override - public boolean equals(Object o) { - if(o == null || this.getClass() != o.getClass()) - return false; - - IntVector v = (IntVector) o; - return x == v.x && y == v.y && z == v.z; - } - - @Override - public String toString() { - return x + "," + y + "," + z; - } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onDeath(EntityDeathEvent e) { + hulls.values().forEach(hull -> hull.removeEntity(e.getEntity())); } } diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/utils/TechHiderWrapper.java b/FightSystem_Core/src/de/steamwar/fightsystem/utils/TechHiderWrapper.java index 5b443da..9638292 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/utils/TechHiderWrapper.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/utils/TechHiderWrapper.java @@ -36,7 +36,6 @@ import org.bukkit.entity.Player; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.stream.Collectors; public class TechHiderWrapper extends StateDependent { @@ -45,7 +44,7 @@ public class TechHiderWrapper extends StateDependent { public TechHiderWrapper() { super(ENABLED, FightState.Schem); - techHider = new TechHider(this::bypass, Material.getMaterial(Config.ObfuscateWith), Config.HiddenBlocks.stream().map(String::toUpperCase).map(Material::getMaterial).collect(Collectors.toSet()), Config.HiddenBlockEntities); + techHider = new TechHider(this::bypass, Material.getMaterial(Config.ObfuscateWith), Config.HiddenBlocks, Config.HiddenBlockEntities); register(); } -- 2.39.2 From ce3384c7e95e7a3d65520944f23135a57d57fa74 Mon Sep 17 00:00:00 2001 From: Lixfel Date: Sun, 17 Dec 2023 18:23:54 +0100 Subject: [PATCH 4/8] Bugfixes, remove debug info Signed-off-by: Lixfel --- .../de/steamwar/fightsystem/utils/Hull.java | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java b/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java index 904c0cd..c9f4d72 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java @@ -22,7 +22,6 @@ package de.steamwar.fightsystem.utils; import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.fight.FightTeam; -import de.steamwar.techhider.BlockIds; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; @@ -144,10 +143,9 @@ public class Hull { } }); FightSystem.getPlugin().getLogger().log(Level.INFO, () -> "[HullHider] initialisation finished: " + (System.currentTimeMillis() - start) + " ms, visible blocks: " + visibility.cardinality()); - - region.forEach(this::printDebug); } + @SuppressWarnings("deprecation") public void updateBlockVisibility(Block b, Material changedType) { IntVector root = new IntVector(b.getX(), b.getY(), b.getZ()); if (root.notInRegion(region)) @@ -168,20 +166,19 @@ public class Hull { } } - for (IntVector block : uncovered) - printDebug(block.x, block.y, block.z); + if(uncovered.isEmpty()) + return; - //TODO uncover entities - } - - private final int air = BlockIds.impl.materialToId(Material.AIR); - private final int stone = BlockIds.impl.materialToId(Material.STONE); - private final int red = BlockIds.impl.materialToId(Material.RED_CONCRETE); - - private void printDebug(int x, int y, int z) { - int id = new IntVector(x, y, z).toId(region); - - BlockIdWrapper.impl.setBlock(Config.world, x, y + Config.BlueExtendRegion.getSizeY(), z, visibility.get(id) ? (occluding.get(id) ? red : air) : stone); + Set uncoveredSet = new HashSet<>(uncovered); + Iterator it = entities.iterator(); + while(it.hasNext()) { + Entity entity = it.next(); + if(uncoveredSet.contains(new IntVector(entity.getLocation()))) { //TODO more precise + it.remove(); + for(Player player : players) + player.showEntity(FightSystem.getPlugin(), entity); //TODO 1.15- + } + } } private void forEachBorder(BiConsumer f) { -- 2.39.2 From 9b781035922beca9061f329a826caf8fbdddb40d Mon Sep 17 00:00:00 2001 From: Lixfel Date: Tue, 19 Dec 2023 16:40:12 +0100 Subject: [PATCH 5/8] Replay HullHider, Fix HullHider for players already online Signed-off-by: Lixfel --- .../fightsystem/utils/BlockIdWrapper14.java | 8 +++++ .../fightsystem/utils/BlockIdWrapper8.java | 10 ++++++ .../fightsystem/record/PacketProcessor.java | 5 ++- .../fightsystem/utils/BlockIdWrapper.java | 2 ++ .../steamwar/fightsystem/utils/HullHider.java | 31 ++++++++++++------- 5 files changed, 43 insertions(+), 13 deletions(-) diff --git a/FightSystem_14/src/de/steamwar/fightsystem/utils/BlockIdWrapper14.java b/FightSystem_14/src/de/steamwar/fightsystem/utils/BlockIdWrapper14.java index 916bfb6..934d9b6 100644 --- a/FightSystem_14/src/de/steamwar/fightsystem/utils/BlockIdWrapper14.java +++ b/FightSystem_14/src/de/steamwar/fightsystem/utils/BlockIdWrapper14.java @@ -21,6 +21,7 @@ package de.steamwar.fightsystem.utils; import com.comphenix.tinyprotocol.Reflection; import de.steamwar.core.Core; +import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; @@ -56,4 +57,11 @@ public class BlockIdWrapper14 implements BlockIdWrapper { getTypeAndData.invoke(nworld, pos, blockData, 1042); flagDirty.invoke(getChunkProvider.invoke(nworld), pos); } + + private static final Reflection.MethodInvoker getMaterialByBlock = Reflection.getTypedMethod(Reflection.getClass("{obc}.util.CraftMagicNumbers"), "getMaterial", Material.class, block); + private static final Reflection.MethodInvoker getBlockByBlockData = Reflection.getTypedMethod(iBlockData, null, block); + @Override + public Material idToMaterial(int blockState) { + return (Material)getMaterialByBlock.invoke(null, getBlockByBlockData.invoke(getByCombinedId.invoke(null, blockState))); + } } diff --git a/FightSystem_8/src/de/steamwar/fightsystem/utils/BlockIdWrapper8.java b/FightSystem_8/src/de/steamwar/fightsystem/utils/BlockIdWrapper8.java index aedd2e8..cbf186a 100644 --- a/FightSystem_8/src/de/steamwar/fightsystem/utils/BlockIdWrapper8.java +++ b/FightSystem_8/src/de/steamwar/fightsystem/utils/BlockIdWrapper8.java @@ -19,6 +19,7 @@ package de.steamwar.fightsystem.utils; +import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; @@ -37,4 +38,13 @@ public class BlockIdWrapper8 implements BlockIdWrapper { world.getBlockAt(x, y, z).setTypeIdAndData(blockState >> 4, (byte)(blockState & 0b1111), false); } + + @Override + @SuppressWarnings("deprecation") + public Material idToMaterial(int blockState) { + if((blockState >> 4) > 256) // Illegal blockstate / corrupted replay + blockState = 0; + + return Material.getMaterial(blockState >> 4); + } } diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java b/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java index f50007a..fff0512 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java @@ -437,7 +437,10 @@ public class PacketProcessor implements Listener { if(!Config.ArenaRegion.in2dRegion(x, z)) return; //Outside of the arena - execSync(() -> BlockIdWrapper.impl.setBlock(Config.world, x, y, z, TechHiderWrapper.ENABLED && hiddenBlockIds.contains(blockState) ? obfuscateWith : blockState)); + execSync(() -> { + BlockIdWrapper.impl.setBlock(Config.world, x, y, z, TechHiderWrapper.ENABLED && hiddenBlockIds.contains(blockState) ? obfuscateWith : blockState); + FightSystem.getHullHider().blockUpdate(Config.world.getBlockAt(x, y, z), BlockIdWrapper.impl.idToMaterial(blockState)); + }); } private void particle() throws IOException { diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/utils/BlockIdWrapper.java b/FightSystem_Core/src/de/steamwar/fightsystem/utils/BlockIdWrapper.java index 6cda218..399e63d 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/utils/BlockIdWrapper.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/utils/BlockIdWrapper.java @@ -21,12 +21,14 @@ package de.steamwar.fightsystem.utils; import de.steamwar.core.VersionDependent; import de.steamwar.fightsystem.FightSystem; +import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; public interface BlockIdWrapper { BlockIdWrapper impl = VersionDependent.getVersionImpl(FightSystem.getPlugin()); + Material idToMaterial(int blockState); int blockToId(Block block); void setBlock(World world, int x, int y, int z, int blockState); } diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java b/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java index 1291202..c7f8e0d 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java @@ -19,6 +19,7 @@ package de.steamwar.fightsystem.utils; +import de.steamwar.core.Core; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightTeam; import de.steamwar.fightsystem.listener.Recording; @@ -27,6 +28,8 @@ import de.steamwar.fightsystem.states.StateDependent; import de.steamwar.fightsystem.states.StateDependentListener; import de.steamwar.fightsystem.states.StateDependentTask; import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -43,6 +46,7 @@ import java.util.Objects; public class HullHider implements Listener { + private static final boolean ENABLED = TechHiderWrapper.ENABLED && Core.getVersion() >= 18; private final Map hulls = new HashMap<>(); //SpawnPackets: PacketPlayOutSpawnEntity, PacketPlayOutSpawnEntityWeather, PacketPlayOutSpawnEntityLiving, PacketPlayOutSpawnEntityPainting, PacketPlayOutSpawnEntityPlayer @@ -51,11 +55,11 @@ public class HullHider implements Listener { //Other: Effect, Particle, Explosion //Death: DestroyEntities public HullHider() { - if(TechHiderWrapper.ENABLED) + if(ENABLED) Fight.teams().forEach(team -> hulls.put(team, new Hull(team))); - new StateDependentListener(TechHiderWrapper.ENABLED, FightState.Schem, this); - new StateDependent(TechHiderWrapper.ENABLED, FightState.Schem) { + new StateDependentListener(ENABLED, FightState.Schem, this); + new StateDependent(ENABLED, FightState.Schem) { @Override public void enable() { Bukkit.getOnlinePlayers().forEach(player -> addPlayer(player, true)); @@ -65,12 +69,12 @@ public class HullHider implements Listener { public void disable() { Bukkit.getOnlinePlayers().forEach(player -> removePlayer(player, true)); } - }; - new StateDependentTask(TechHiderWrapper.ENABLED, FightState.Schem, this::onTick, 0, 1); + }.register(); + new StateDependentTask(ENABLED, FightState.Schem, this::onTick, 0, 1); } public void initialize(FightTeam team) { - if(!TechHiderWrapper.ENABLED) + if(!ENABLED) return; hulls.get(team).initialize(); @@ -78,14 +82,14 @@ public class HullHider implements Listener { public void addPlayer(FightTeam team, Player player) { - if(!TechHiderWrapper.ENABLED) + if(!ENABLED) return; hulls.get(team).addPlayer(player, true); } public void removePlayer(FightTeam team, Player player) { - if(!TechHiderWrapper.ENABLED) + if(!ENABLED) return; hulls.get(team).removePlayer(player, true); @@ -118,10 +122,13 @@ public class HullHider implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockPhysic(BlockPhysicsEvent e) { - if(FlatteningWrapper.impl.doRecord(e)) { - for (Hull hull : hulls.values()) - hull.updateBlockVisibility(e.getBlock(), e.getChangedType()); - } + if(FlatteningWrapper.impl.doRecord(e)) + blockUpdate(e.getBlock(), e.getChangedType()); + } + + public void blockUpdate(Block block, Material changedType) { + for (Hull hull : hulls.values()) + hull.updateBlockVisibility(block, changedType); } -- 2.39.2 From 65028799b03c3c02c1aee074054f762afc1d967b Mon Sep 17 00:00:00 2001 From: Lixfel Date: Tue, 19 Dec 2023 22:18:16 +0100 Subject: [PATCH 6/8] Correct HullHider behaviour for boarding Signed-off-by: Lixfel --- .../countdown/EnternCountdown.java | 5 ++- .../steamwar/fightsystem/fight/FightTeam.java | 4 +-- .../de/steamwar/fightsystem/utils/Hull.java | 4 +-- .../steamwar/fightsystem/utils/HullHider.java | 36 ++++++++----------- 4 files changed, 22 insertions(+), 27 deletions(-) diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/countdown/EnternCountdown.java b/FightSystem_Core/src/de/steamwar/fightsystem/countdown/EnternCountdown.java index d8c78d9..157c296 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/countdown/EnternCountdown.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/countdown/EnternCountdown.java @@ -56,7 +56,10 @@ public class EnternCountdown extends Countdown { @Override public void countdownFinished() { FightSystem.getMessage().sendPrefixless("ENTERN_ALLOWED", fightPlayer.getEntity(), ChatMessageType.ACTION_BAR); - fightPlayer.ifPlayer(player -> FightSystem.getTechHider().reloadChunks(player, chunkPos, false)); + fightPlayer.ifPlayer(player -> { + FightSystem.getHullHider().updatePlayer(player); + FightSystem.getTechHider().reloadChunks(player, chunkPos, false); + }); } @Override diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java b/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java index 6efb3fd..7aad62d 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java @@ -275,7 +275,7 @@ public class FightTeam { BountifulWrapper.impl.setAttackSpeed(player); player.setFoodLevel(20); player.getInventory().clear(); - FightSystem.getHullHider().removePlayer(this, player); + FightSystem.getHullHider().updatePlayer(player); if(FightState.Spectate.contains(FightState.getFightState())) { Fight.setPlayerGamemode(player, GameMode.SPECTATOR); @@ -319,7 +319,7 @@ public class FightTeam { player.getInventory().clear(); if(player.isOnline()){ - FightSystem.getHullHider().addPlayer(this, player); + FightSystem.getHullHider().updatePlayer(player); FightSystem.getTechHider().reloadChunks(player, chunksToReload, true); if(ArenaMode.VariableTeams.contains(Config.mode)) diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java b/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java index c9f4d72..3f168a3 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java @@ -89,8 +89,8 @@ public class Hull { } @SuppressWarnings("deprecation") - public void addPlayer(Player player, boolean activeHiding) { - if(players.add(player) && activeHiding) { + public void addPlayer(Player player) { + if(players.add(player)) { for(Entity entity : entities) player.hideEntity(FightSystem.getPlugin(), entity); //TODO 1.15- } diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java b/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java index c7f8e0d..423f8cc 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java @@ -21,6 +21,7 @@ package de.steamwar.fightsystem.utils; import de.steamwar.core.Core; import de.steamwar.fightsystem.fight.Fight; +import de.steamwar.fightsystem.fight.FightPlayer; import de.steamwar.fightsystem.fight.FightTeam; import de.steamwar.fightsystem.listener.Recording; import de.steamwar.fightsystem.states.FightState; @@ -62,7 +63,7 @@ public class HullHider implements Listener { new StateDependent(ENABLED, FightState.Schem) { @Override public void enable() { - Bukkit.getOnlinePlayers().forEach(player -> addPlayer(player, true)); + Bukkit.getOnlinePlayers().forEach(player -> updatePlayer(player)); } @Override @@ -81,23 +82,9 @@ public class HullHider implements Listener { } - public void addPlayer(FightTeam team, Player player) { - if(!ENABLED) - return; - - hulls.get(team).addPlayer(player, true); - } - - public void removePlayer(FightTeam team, Player player) { - if(!ENABLED) - return; - - hulls.get(team).removePlayer(player, true); - } - @EventHandler(priority = EventPriority.HIGH) public void onJoin(PlayerJoinEvent e) { - addPlayer(e.getPlayer(), false); + updatePlayer(e.getPlayer()); } @EventHandler @@ -105,13 +92,18 @@ public class HullHider implements Listener { removePlayer(e.getPlayer(), false); } - private void addPlayer(Player player, boolean activeHiding) { - FightTeam team = Fight.getPlayerTeam(player); - for(Map.Entry hull : hulls.entrySet()) { - if(hull.getKey() == team) - continue; + public void updatePlayer(Player player) { + if(!ENABLED) + return; - hull.getValue().addPlayer(player, activeHiding); + FightTeam team = Fight.getPlayerTeam(player); + FightPlayer fp = Fight.getFightPlayer(player); + for(Map.Entry hull : hulls.entrySet()) { + if(hull.getKey() == team || (fp != null && fp.canEntern())) { + hull.getValue().removePlayer(player, true); + } else { + hull.getValue().addPlayer(player); + } } } -- 2.39.2 From 6f4e0f0293ee2b47810e0950ca01d065c4362de2 Mon Sep 17 00:00:00 2001 From: Lixfel Date: Sat, 30 Dec 2023 12:26:11 +0100 Subject: [PATCH 7/8] Replay REntity HullHider Signed-off-by: Lixfel --- .../fightsystem/record/PacketProcessor.java | 22 ++++++++---- .../de/steamwar/fightsystem/utils/Hull.java | 36 ++++++++++++++++--- .../steamwar/fightsystem/utils/HullHider.java | 16 +++++---- 3 files changed, 57 insertions(+), 17 deletions(-) diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java b/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java index fff0512..cb1dddb 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java @@ -165,6 +165,11 @@ public class PacketProcessor implements Listener { entityServer.addPlayer(player); } + private void addREntity(int entityId, REntity entity) { + entities.put(entityId, entity); + FightSystem.getHullHider().updateREntity(entity); + } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerJoin(PlayerJoinEvent e) { entityServer.addPlayer(e.getPlayer()); @@ -235,7 +240,7 @@ public class PacketProcessor implements Listener { execSync(() -> { SteamwarUser user = SteamwarUser.get(userId); - entities.put(entityId, new RPlayer(entityServer, user.getUUID(), user.getUserName(), Config.SpecSpawn)); + addREntity(entityId, new RPlayer(entityServer, user.getUUID(), user.getUserName(), Config.SpecSpawn)); team.addEntry(user.getUserName()); }); } @@ -257,8 +262,10 @@ public class PacketProcessor implements Listener { execSync(() -> { REntity entity = entities.get(entityId); - if(entity != null) + if(entity != null) { entity.move(locX, locY, locZ, pitch, yaw, headYaw); + FightSystem.getHullHider().updateREntity(entity); + } }); } @@ -267,8 +274,10 @@ public class PacketProcessor implements Listener { execSync(() -> { REntity entity = entities.remove(entityId); - if(entity != null) + if(entity != null) { + FightSystem.getHullHider().despawnREntity(entity); entity.die(); + } }); } @@ -289,7 +298,7 @@ public class PacketProcessor implements Listener { private void tntSpawn() throws IOException { int entityId = source.readInt(); - execSync(() -> entities.put(entityId, new REntity(entityServer, EntityType.PRIMED_TNT, Config.SpecSpawn))); + execSync(() -> addREntity(entityId, new REntity(entityServer, EntityType.PRIMED_TNT, Config.SpecSpawn))); } private void entityVelocity() throws IOException { @@ -344,13 +353,13 @@ public class PacketProcessor implements Listener { private void arrowSpawn() throws IOException { int entityId = source.readInt(); - execSync(() -> entities.put(entityId, new REntity(entityServer, EntityType.ARROW, Config.SpecSpawn))); + execSync(() -> addREntity(entityId, new REntity(entityServer, EntityType.ARROW, Config.SpecSpawn))); } private void fireballSpawn() throws IOException { int entityId = source.readInt(); - execSync(() -> entities.put(entityId, new REntity(entityServer, EntityType.FIREBALL, Config.SpecSpawn))); + execSync(() -> addREntity(entityId, new REntity(entityServer, EntityType.FIREBALL, Config.SpecSpawn))); } private void send(ChatMessageType type) throws IOException { @@ -581,6 +590,7 @@ public class PacketProcessor implements Listener { private void endReplay() { HandlerList.unregisterAll(this); entityServer.close(); + entities.values().forEach(FightSystem.getHullHider()::despawnREntity); entities.clear(); freezer.disable(); diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java b/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java index 3f168a3..57cfa29 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java @@ -19,6 +19,7 @@ package de.steamwar.fightsystem.utils; +import de.steamwar.entity.REntity; import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.fight.FightTeam; @@ -47,6 +48,7 @@ public class Hull { private final Set players = new HashSet<>(); private final Set entities = new HashSet<>(); + private final Set rentities = new HashSet<>(); public Hull(FightTeam team) { this.region = team.getSchemRegion(); @@ -92,7 +94,7 @@ public class Hull { public void addPlayer(Player player) { if(players.add(player)) { for(Entity entity : entities) - player.hideEntity(FightSystem.getPlugin(), entity); //TODO 1.15- + player.hideEntity(FightSystem.getPlugin(), entity); } } @@ -100,7 +102,7 @@ public class Hull { public void removePlayer(Player player, boolean activeRemoval) { if(players.remove(player) && activeRemoval) { for(Entity entity : entities) - player.showEntity(FightSystem.getPlugin(), entity); //TODO 1.15- + player.showEntity(FightSystem.getPlugin(), entity); } } @@ -109,12 +111,12 @@ public class Hull { if(region.inRegion(location) && !visibility.get(new IntVector(location).toId(region))) { //TODO more precise if(entities.add(entity)) { for(Player player : players) - player.hideEntity(FightSystem.getPlugin(), entity); //TODO 1.15- + player.hideEntity(FightSystem.getPlugin(), entity); } } else { if(entities.remove(entity)) { for(Player player : players) - player.showEntity(FightSystem.getPlugin(), entity); //TODO 1.15- + player.showEntity(FightSystem.getPlugin(), entity); } } } @@ -123,6 +125,21 @@ public class Hull { entities.remove(entity); } + public void checkREntity(REntity entity) { + Location location = new Location(Config.world, entity.getX(), entity.getY(), entity.getZ()); + if(region.inRegion(location) && !visibility.get(new IntVector(location).toId(region))) { //TODO more precise + if(rentities.add(entity)) + entity.hide(true); + } else { + if(rentities.remove(entity)) + entity.hide(false); + } + } + + public void removeREntity(REntity entity) { + rentities.remove(entity); + } + public void initialize() { visibility.clear(); occluding.clear(); @@ -176,7 +193,16 @@ public class Hull { if(uncoveredSet.contains(new IntVector(entity.getLocation()))) { //TODO more precise it.remove(); for(Player player : players) - player.showEntity(FightSystem.getPlugin(), entity); //TODO 1.15- + player.showEntity(FightSystem.getPlugin(), entity); + } + } + + Iterator rit = rentities.iterator(); + while(rit.hasNext()) { + REntity entity = rit.next(); + if(uncoveredSet.contains(new IntVector(new Location(Config.world, entity.getX(), entity.getY(), entity.getZ())))) { //TODO more precise + it.remove(); + entity.hide(false); } } } diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java b/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java index 423f8cc..1d95eef 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java @@ -20,6 +20,7 @@ package de.steamwar.fightsystem.utils; import de.steamwar.core.Core; +import de.steamwar.entity.REntity; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightPlayer; import de.steamwar.fightsystem.fight.FightTeam; @@ -50,11 +51,6 @@ public class HullHider implements Listener { private static final boolean ENABLED = TechHiderWrapper.ENABLED && Core.getVersion() >= 18; private final Map hulls = new HashMap<>(); - //SpawnPackets: PacketPlayOutSpawnEntity, PacketPlayOutSpawnEntityWeather, PacketPlayOutSpawnEntityLiving, PacketPlayOutSpawnEntityPainting, PacketPlayOutSpawnEntityPlayer - //One-timePackets: PacketPlayOutEntityAnimation, PacketPlayOutBlockBreakAnimation, PacketPlayOutEntityStatus, PacketPlayOutEntityPosition, PacketPlayOutEntityPositionAndRotation, PacketPlayOutEntityRotation, PacketPlayOutEntityMovement, EntityHeadLook, EntitySoundEffect, CollectItem, EntityTeleport, - //Permanent: EntityMetadata, AttachEntity, EntityEquipment, SetPassengers, EntityProperties, EntityEffect, RemoveEntityEffect - //Other: Effect, Particle, Explosion - //Death: DestroyEntities public HullHider() { if(ENABLED) Fight.teams().forEach(team -> hulls.put(team, new Hull(team))); @@ -63,7 +59,7 @@ public class HullHider implements Listener { new StateDependent(ENABLED, FightState.Schem) { @Override public void enable() { - Bukkit.getOnlinePlayers().forEach(player -> updatePlayer(player)); + Bukkit.getOnlinePlayers().forEach(HullHider.this::updatePlayer); } @Override @@ -140,4 +136,12 @@ public class HullHider implements Listener { public void onDeath(EntityDeathEvent e) { hulls.values().forEach(hull -> hull.removeEntity(e.getEntity())); } + + public void updateREntity(REntity e) { + hulls.values().forEach(hull -> hull.checkREntity(e)); + } + + public void despawnREntity(REntity e) { + hulls.values().forEach(hull -> hull.removeREntity(e)); + } } -- 2.39.2 From 7fab960315aefa16c7f1f3d6beb5dd52290bd1e5 Mon Sep 17 00:00:00 2001 From: Lixfel Date: Mon, 1 Jan 2024 16:45:32 +0100 Subject: [PATCH 8/8] Fix unchecked schematics at events Signed-off-by: Lixfel --- FightSystem_Core/src/de/steamwar/fightsystem/commands/GUI.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/commands/GUI.java b/FightSystem_Core/src/de/steamwar/fightsystem/commands/GUI.java index cbb392b..438bd1a 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/commands/GUI.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/commands/GUI.java @@ -19,6 +19,7 @@ package de.steamwar.fightsystem.commands; +import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.fight.*; @@ -189,7 +190,7 @@ public class GUI { return; } - if (type.checkType() != null && type.checkType() != type && !SchematicNode.getAllAccessibleSchematicsOfType(SteamwarUser.get(p.getUniqueId()).getId(), type.checkType().toDB()).isEmpty()) { + if (type.checkType() != null && type.checkType() != type && ArenaMode.AntiEvent.contains(Config.mode) && !SchematicNode.getAllAccessibleSchematicsOfType(SteamwarUser.get(p.getUniqueId()).getId(), type.checkType().toDB()).isEmpty()) { inv.setItem(row * 9 + 4, Material.ANVIL, msg.parse("SCHEM_UNCHECKED", p, type.name()), (ClickType click) -> { p.closeInventory(); schemDialog(p, type, false, true); -- 2.39.2