From 1b3b563fd3dabfbaefa29489543ae391f530757e Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Wed, 25 Mar 2026 21:05:26 +0100 Subject: [PATCH] Improve DynamicRegionSystem.getNeighbours --- .../bausystem/region/DynamicRegionSystem.java | 109 ++++++++++++------ .../region/dynamic/DynamicRegion.java | 34 +++--- 2 files changed, 89 insertions(+), 54 deletions(-) diff --git a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionSystem.java b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionSystem.java index ceb5be96..22e0f8c8 100644 --- a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionSystem.java +++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionSystem.java @@ -23,8 +23,9 @@ import de.steamwar.bausystem.BauSystem; import de.steamwar.bausystem.features.region.WireframeCommand; import de.steamwar.bausystem.region.dynamic.*; import de.steamwar.bausystem.region.dynamic.global.GlobalRegion; -import de.steamwar.bausystem.shared.Pair; import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.ToString; import org.bukkit.Bukkit; import org.bukkit.Location; import org.jetbrains.annotations.NotNull; @@ -117,21 +118,18 @@ public class DynamicRegionSystem implements RegionSystem { } public @NonNull Region get(@Nullable Tile tile) { - if (tile == null) return getGlobalRegion(); - return get(tile.getCenterLocation().getBlockX(), tile.getCenterLocation().getBlockZ(), true, regionMap.values()); + return get(tile, true, regionMap.values()); } - private Region get(int x, int z, boolean fastCache, Collection regions) { - Tile tile = Tile.fromXZ(x, z).orElse(null); - if (tile == null) { - return getGlobalRegion(); - } + private Region get(@Nullable Tile tile, boolean fastCache, Collection regions) { + if (tile == null) return getGlobalRegion(); if (regionCache.containsKey(tile.getId())) { Region region = regionCache.get(tile.getId()); if (fastCache || regions.contains(region)) return region; } + Location location = tile.getCenterLocation(); Region region = regions.stream() - .filter(rg -> rg.getArea().inRegion(x, z, false)) + .filter(rg -> rg.getArea().inRegion(location, false)) .findFirst() .orElseGet(this::getGlobalRegion); if (fastCache || regions.contains(region)) { @@ -140,9 +138,14 @@ public class DynamicRegionSystem implements RegionSystem { return region; } + private Region get(int x, int z, boolean fastCache, Collection regions) { + Tile tile = Tile.fromXZ(x, z).orElse(null); + return get(tile, fastCache, regions); + } + @Override public @NonNull Region get(@NonNull Location location) { - return get(location.getBlockX(), location.getBlockZ(), true, regionMap.values()); + return get(Tile.fromLocation(location).orElse(null), true, regionMap.values()); } @Override @@ -159,40 +162,76 @@ public class DynamicRegionSystem implements RegionSystem { return regionTypeMap.getOrDefault(type, Collections.emptySet()).stream(); } - private Stream> getNeighbours(Region region, boolean noCorners, boolean fastCache, Collection regions) { - Point minPoint = region.getArea().getMinPoint(false).subtract(TILE_SIZE_ADJUSTED, 0, TILE_SIZE_ADJUSTED); - Point maxPoint = region.getArea().getMaxPoint(false).add(Tile.tileSize, 0, Tile.tileSize); - Set> neighbours = new HashSet<>(); + @RequiredArgsConstructor + @ToString + public static class Neighbour { + public final T region; + public final Tile tile; + public final NeighbourDirection direction; - for (int x = minPoint.getX() + (noCorners ? TILE_SIZE_ADJUSTED : 0); x <= maxPoint.getX() - (noCorners ? Tile.tileSize : 0); x += Tile.tileSize) { - NeighbourDirection minZ = NeighbourDirection.North; - if (!noCorners) { - if (x == minPoint.getX()) minZ = NeighbourDirection.NorthWest; - if (x > maxPoint.getX() - TILE_SIZE_ADJUSTED) minZ = NeighbourDirection.NorthEast; + public Neighbour as(Class clazz) { + if (!clazz.isInstance(region)) { + return null; + } else { + return (Neighbour) this; } - neighbours.add(new Pair<>(get(x, minPoint.getZ(), fastCache, regions), minZ)); - - NeighbourDirection maxZ = NeighbourDirection.South; - if (!noCorners) { - if (x == minPoint.getX()) maxZ = NeighbourDirection.SouthWest; - if (x > maxPoint.getX() - TILE_SIZE_ADJUSTED) maxZ = NeighbourDirection.SouthEast; - } - neighbours.add(new Pair<>(get(x, maxPoint.getZ(), fastCache, regions), maxZ)); } - for (int z = minPoint.getZ() + TILE_SIZE_ADJUSTED; z <= maxPoint.getZ() - Tile.tileSize; z += Tile.tileSize) { - neighbours.add(new Pair<>(get(minPoint.getX(), z, fastCache, regions), NeighbourDirection.West)); - neighbours.add(new Pair<>(get(maxPoint.getX(), z, fastCache, regions), NeighbourDirection.East)); + @Override + public boolean equals(Object o) { + if (!(o instanceof Neighbour neighbour)) return false; + return Objects.equals(tile, neighbour.tile) && direction == neighbour.direction; } - neighbours.removeIf(data -> data.getKey().getType().isGlobal()); + @Override + public int hashCode() { + return Objects.hash(tile, direction); + } + } + + private Stream> getNeighbours(Region region, boolean noCorners, boolean fastCache, Collection regions) { + Tile minTile = Tile.fromPoint(region.getArea().getMinPoint(false)).orElse(null); + Tile maxTile = Tile.fromPoint(region.getArea().getMaxPoint(false)).orElse(null); + if (minTile == null || maxTile == null) return Stream.empty(); + + Set> neighbours = new HashSet<>(); + + if (!noCorners) { + neighbours.add(new Neighbour<>(get(minTile.add(-1, -1).orElseThrow(), fastCache, regions), minTile, NeighbourDirection.NorthWest)); + + Tile cornerMinMaxSelf = Tile.fromTile(minTile.getTileX(), maxTile.getTileZ()).orElseThrow(); + neighbours.add(new Neighbour<>(get(cornerMinMaxSelf.add(-1, 1).orElseThrow(), fastCache, regions), cornerMinMaxSelf, NeighbourDirection.SouthWest)); + + Tile cornerMaxMinSelf = Tile.fromTile(maxTile.getTileX(), minTile.getTileZ()).orElseThrow(); + neighbours.add(new Neighbour<>(get(cornerMaxMinSelf.add(1, -1).orElseThrow(), fastCache, regions), cornerMaxMinSelf, NeighbourDirection.NorthEast)); + + neighbours.add(new Neighbour<>(get(maxTile.add(1, 1).orElseThrow(), fastCache, regions), maxTile, NeighbourDirection.SouthEast)); + } + + for (int x = minTile.getTileX(); x <= maxTile.getTileX(); x++) { + Tile tileMinZSelf = Tile.fromTile(x, minTile.getTileZ()).orElseThrow(); + neighbours.add(new Neighbour<>(get(tileMinZSelf.add(0, -1).orElseThrow(), fastCache, regions), tileMinZSelf, NeighbourDirection.North)); + + Tile tileMaxZSelf = Tile.fromTile(x, maxTile.getTileZ()).orElseThrow(); + neighbours.add(new Neighbour<>(get(tileMaxZSelf.add(0, 1).orElseThrow(), fastCache, regions), tileMaxZSelf, NeighbourDirection.South)); + } + + for (int z = minTile.getTileZ(); z <= maxTile.getTileZ(); z++) { + Tile tileMinXSelf = Tile.fromTile(minTile.getTileX(), z).orElseThrow(); + neighbours.add(new Neighbour<>(get(tileMinXSelf.add(-1, 0).orElseThrow(), fastCache, regions), tileMinXSelf, NeighbourDirection.West)); + + Tile tileMaxXSelf = Tile.fromTile(maxTile.getTileX(), z).orElseThrow(); + neighbours.add(new Neighbour<>(get(tileMaxXSelf.add(1, 0).orElseThrow(), fastCache, regions), tileMaxXSelf, NeighbourDirection.East)); + } + + neighbours.removeIf(neighbour -> neighbour.region.getType().isGlobal()); return neighbours.stream(); } - public Stream> getNeighbours(Region region) { + public Stream> getNeighbours(Region region) { return getNeighbours(region, false, true, regionMap.values()) - .filter(data -> data.getKey() instanceof DynamicRegion) - .map(data -> (Pair) (Pair) data); + .map(neighbour -> neighbour.as(DynamicRegion.class)) + .filter(Objects::nonNull); } @Override @@ -208,7 +247,7 @@ public class DynamicRegionSystem implements RegionSystem { Region r = current.removeFirst(); if (!connected.add(r)) continue; getNeighbours(r, true, false, regions) - .map(Pair::getKey) + .map(neighbour -> neighbour.region) .forEach(current::add); } diff --git a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/DynamicRegion.java b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/DynamicRegion.java index 2141e74b..fa58e96d 100644 --- a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/DynamicRegion.java +++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/DynamicRegion.java @@ -26,15 +26,11 @@ import de.steamwar.bausystem.region.Point; import de.steamwar.bausystem.region.Region; import de.steamwar.bausystem.region.RegionData; import de.steamwar.bausystem.region.dynamic.path.PathRegion; -import de.steamwar.bausystem.shared.Pair; import lombok.Getter; import lombok.NonNull; import java.io.IOException; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; +import java.util.*; public abstract class DynamicRegion implements Region { @@ -80,25 +76,25 @@ public abstract class DynamicRegion implements Region { public abstract void writeTileData(JsonWriter writer) throws IOException; public final void updateNeighbours() { - List> list = DynamicRegionSystem.INSTANCE.getNeighbours(this) - .filter(data -> data.getKey() instanceof PathRegion) - .map(data -> (Pair) (Pair) data) + List> list = DynamicRegionSystem.INSTANCE.getNeighbours(this) + .map(neighbour -> neighbour.as(PathRegion.class)) + .filter(Objects::nonNull) .toList(); // Calculate Garden State for all neighbouring PathRegions Set needsFullReset = new HashSet<>(); list.forEach(data -> { - boolean previousGardenState = data.getKey().isGarden(); - data.getKey().calculateGardenState(); - if (data.getKey().isGarden() != previousGardenState) { - needsFullReset.add(data.getKey().getID()); + boolean previousGardenState = data.region.isGarden(); + data.region.calculateGardenState(); + if (data.region.isGarden() != previousGardenState) { + needsFullReset.add(data.region.getID()); } }); // Updating world state for all neighbouring PathRegions list.forEach(data -> { - if (needsFullReset.contains(data.getKey().getID())) { - data.getKey().getArea().reset(null, false); // TODO: Implement! + if (needsFullReset.contains(data.region.getID())) { + data.region.getArea().reset(null, false); // TODO: Implement! } else { - data.getKey().update(this, data.getValue().opposite()); + data.region.update(this, data.direction.opposite()); } }); // All full reset regions need to update their neighbours! @@ -106,11 +102,11 @@ public abstract class DynamicRegion implements Region { Region region = DynamicRegionSystem.INSTANCE.getRegion(uuid).orElse(null); if (!(region instanceof DynamicRegion dynamicRegion)) return; DynamicRegionSystem.INSTANCE.getNeighbours(dynamicRegion) - .filter(data -> data.getKey() instanceof PathRegion) - .map(data -> (Pair) (Pair) data) + .map(neighbour -> neighbour.as(PathRegion.class)) + .filter(Objects::nonNull) .forEach(data -> { - if (data.getKey().isGarden()) return; - data.getKey().update(dynamicRegion, data.getValue().opposite()); + if (data.region.isGarden()) return; + data.region.update(dynamicRegion, data.direction.opposite()); }); }); }