diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java index 05ff3fc8..86eda93d 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java @@ -24,6 +24,9 @@ import de.steamwar.entity.REntity; import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.fight.FightTeam; +import de.steamwar.techhider.BlockIds; +import it.unimi.dsi.fastutil.ints.Int2IntMap; +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import lombok.AllArgsConstructor; import lombok.Getter; import org.bukkit.Location; @@ -38,6 +41,40 @@ import java.util.logging.Level; public class Hull { + private static final boolean DEBUG = false; + private static final int AIR = BlockIds.impl.materialToId(Material.AIR); + private static final int RED_GLASS = BlockIds.impl.materialToId(Material.STONE); + private static final int GLASS = BlockIds.impl.materialToId(Material.GLASS); + + private static final IntVector[] DIRECTIONS = new IntVector[]{ + new IntVector(-1, -1, -1), + new IntVector(-1, -1, 0), + new IntVector(-1, -1, 1), + new IntVector(-1, 0, -1), + new IntVector(-1, 0, 0), + new IntVector(-1, 0, 1), + new IntVector(-1, 1, -1), + new IntVector(-1, 1, 0), + new IntVector(-1, 1, 1), + new IntVector(0, -1, -1), + new IntVector(0, -1, 0), + new IntVector(0, -1, 1), + new IntVector(0, 0, -1), + new IntVector(0, 0, 1), + new IntVector(0, 1, -1), + new IntVector(0, 1, 0), + new IntVector(0, 1, 1), + new IntVector(1, -1, -1), + new IntVector(1, -1, 0), + new IntVector(1, -1, 1), + new IntVector(1, 0, -1), + new IntVector(1, 0, 0), + new IntVector(1, 0, 1), + new IntVector(1, 1, -1), + new IntVector(1, 1, 0), + new IntVector(1, 1, 1), + }; + private static boolean isOccluding(Material material) { return material.isOccluding() || Config.HiddenBlocks.contains(material); } @@ -47,7 +84,7 @@ public class Hull { private final BitSet occluding; private final BitSet visibility; - private final Map> blockVisibility = new HashMap<>(); + private final Int2IntMap visibilityDirections = new Int2IntOpenHashMap(); // Contains the visible directions of each occluding visible block private final Set uncoveredSurface = new HashSet<>(); private final HashSet players = new HashSet<>(); @@ -59,39 +96,6 @@ public class Hull { 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 boolean blockPrecise(Player player, int chunkX, int chunkY, int chunkZ) { @@ -123,7 +127,7 @@ public class Hull { public void checkEntity(Entity entity) { Location location = entity.getLocation(); - if(region.inRegion(location) && !visibility.get(new IntVector(location).toId(region))) { //TODO more precise + if(region.inRegion(location) && !visibility.get(new IntVector(location).toId(region))) { if(entities.add(entity)) { for(Player player : players) BlockIdWrapper.impl.untrackEntity(player, entity.getEntityId()); @@ -142,7 +146,7 @@ public class Hull { 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(region.inRegion(location) && !visibility.get(new IntVector(location).toId(region))) { if(rentities.add(entity)) entity.hide(true); } else { @@ -158,11 +162,7 @@ public class Hull { public void initialize() { visibility.clear(); occluding.clear(); - uncoveredSurface.clear(); - for (Map direction : blockVisibility.values()) { - for (BitSet set : direction.values()) - set.clear(); - } + visibilityDirections.clear(); long start = System.currentTimeMillis(); region.forEach((x, y, z) -> { @@ -170,12 +170,15 @@ public class Hull { 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()); - } - }); + forEachBorder((root, direction) -> updateBlocks(new NullList<>(), root, direction)); FightSystem.getPlugin().getLogger().log(Level.INFO, () -> "[HullHider] initialisation finished: " + (System.currentTimeMillis() - start) + " ms, visible blocks: " + visibility.cardinality()); + + if(DEBUG) { + region.forEach((x, y, 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_GLASS : AIR) : GLASS); + }); + } } public void updateBlockVisibility(Block b, Material changedType) { @@ -187,15 +190,15 @@ public class Hull { 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()); - } - } + if(!visibility.get(id)) + return; + + List uncovered = new ArrayList<>(); + int directions = visibilityDirections.remove(id); + for(IntVector direction : DIRECTIONS) { + if((directionId(direction) & directions) != 0) + updateBlocks(uncovered, root, direction); } if(uncovered.isEmpty()) @@ -205,7 +208,7 @@ public class Hull { Iterator it = entities.iterator(); while(it.hasNext()) { Entity entity = it.next(); - if(uncoveredSet.contains(new IntVector(entity.getLocation()))) { //TODO more precise + if(uncoveredSet.contains(new IntVector(entity.getLocation()))) { it.remove(); for(Player player : players) BlockIdWrapper.impl.trackEntity(player, entity.getEntityId()); @@ -215,7 +218,7 @@ public class Hull { 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 + if(uncoveredSet.contains(new IntVector(new Location(Config.world, entity.getX(), entity.getY(), entity.getZ())))) { rit.remove(); entity.hide(false); } @@ -266,48 +269,33 @@ public class Hull { } } - private void checkBlock(List uncovered, IntVector block, IntVector direction, IntVector quadrant, BitSet quadVisibility) { + private void updateBlocks(List uncovered, IntVector block, IntVector direction) { 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)) + if (occluding.get(id)) { + visibilityDirections.compute(id, (pos, v) -> (v == null ? 0 : v) + directionId(direction)); + return; + } + + updateBlocks(uncovered, block.add(direction), direction); + if(direction.x*direction.x + direction.y*direction.y + direction.z*direction.z > 1) // If direction diagonal 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)); + for(IntVector branchDirection : DIRECTIONS) { + if(!branchDirection.equals(direction) && direction.x*branchDirection.x + direction.y*branchDirection.y + direction.z*branchDirection.z == 1) // If branch direction diagonal pointing towards direction + updateBlocks(uncovered, block.add(branchDirection), branchDirection); } - - 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 int directionId(IntVector v) { + return 9*(v.z+1) + 3*(v.y+1) + (v.x+1); }