diff --git a/Core/src/main/java/com/plotsquared/core/location/Direction.java b/Core/src/main/java/com/plotsquared/core/location/Direction.java index eecfb6c37..1f66c4481 100644 --- a/Core/src/main/java/com/plotsquared/core/location/Direction.java +++ b/Core/src/main/java/com/plotsquared/core/location/Direction.java @@ -55,6 +55,25 @@ public enum Direction { return NORTH; } + /** + * {@return the opposite direction} + * If this is {@link Direction#ALL}, then {@link Direction#ALL} is returned. + * @since TODO + */ + public Direction opposite() { + return switch (this) { + case ALL -> ALL; + case NORTH -> SOUTH; + case EAST -> WEST; + case SOUTH -> NORTH; + case WEST -> EAST; + case NORTHEAST -> SOUTHWEST; + case SOUTHEAST -> NORTHWEST; + case SOUTHWEST -> NORTHEAST; + case NORTHWEST -> SOUTHEAST; + }; + } + public int getIndex() { return index; } diff --git a/Core/src/main/java/com/plotsquared/core/plot/Plot.java b/Core/src/main/java/com/plotsquared/core/plot/Plot.java index 90e339308..4cd4b18ad 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/Plot.java +++ b/Core/src/main/java/com/plotsquared/core/plot/Plot.java @@ -85,6 +85,7 @@ import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Deque; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -2283,8 +2284,8 @@ public class Plot { } /** - * Gets a set of plots connected (and including) this plot
- * - This result is cached globally + * Gets a set of plots connected (and including) this plot. + * The returned set is immutable. * * @return a Set of Plots connected to this Plot */ @@ -2295,117 +2296,75 @@ public class Plot { if (!this.isMerged()) { return Collections.singleton(this); } + Plot basePlot = getBasePlot(false); + if (this.connectedCache == null && this != basePlot) { + // share cache between connected plots + Set connectedPlots = basePlot.getConnectedPlots(); + this.connectedCache = connectedPlots; + return connectedPlots; + } if (this.connectedCache != null && this.connectedCache.contains(this)) { return this.connectedCache; } - HashSet tmpSet = new HashSet<>(); + Set tmpSet = new HashSet<>(); tmpSet.add(this); - Plot tmp; - HashSet queuecache = new HashSet<>(); + HashSet queueCache = new HashSet<>(); ArrayDeque frontier = new ArrayDeque<>(); - if (this.isMerged(Direction.NORTH)) { - tmp = this.area.getPlotAbs(this.id.getRelative(Direction.NORTH)); - if (!tmp.isMerged(Direction.SOUTH)) { - // invalid merge - if (tmp.isOwnerAbs(this.getOwnerAbs())) { - tmp.getSettings().setMerged(Direction.SOUTH, true); - DBFunc.setMerged(tmp, tmp.getSettings().getMerged()); - } else { - this.getSettings().setMerged(Direction.NORTH, false); - DBFunc.setMerged(this, this.getSettings().getMerged()); - } - } - queuecache.add(tmp); - frontier.add(tmp); - } - if (this.isMerged(Direction.EAST)) { - tmp = this.area.getPlotAbs(this.id.getRelative(Direction.EAST)); - assert tmp != null; - if (!tmp.isMerged(Direction.WEST)) { - // invalid merge - if (tmp.isOwnerAbs(this.getOwnerAbs())) { - tmp.getSettings().setMerged(Direction.WEST, true); - DBFunc.setMerged(tmp, tmp.getSettings().getMerged()); - } else { - this.getSettings().setMerged(Direction.EAST, false); - DBFunc.setMerged(this, this.getSettings().getMerged()); - } - } - queuecache.add(tmp); - frontier.add(tmp); - } - if (this.isMerged(Direction.SOUTH)) { - tmp = this.area.getPlotAbs(this.id.getRelative(Direction.SOUTH)); - assert tmp != null; - if (!tmp.isMerged(Direction.NORTH)) { - // invalid merge - if (tmp.isOwnerAbs(this.getOwnerAbs())) { - tmp.getSettings().setMerged(Direction.NORTH, true); - DBFunc.setMerged(tmp, tmp.getSettings().getMerged()); - } else { - this.getSettings().setMerged(Direction.SOUTH, false); - DBFunc.setMerged(this, this.getSettings().getMerged()); - } - } - queuecache.add(tmp); - frontier.add(tmp); - } - if (this.isMerged(Direction.WEST)) { - tmp = this.area.getPlotAbs(this.id.getRelative(Direction.WEST)); - if (!tmp.isMerged(Direction.EAST)) { - // invalid merge - if (tmp.isOwnerAbs(this.getOwnerAbs())) { - tmp.getSettings().setMerged(Direction.EAST, true); - DBFunc.setMerged(tmp, tmp.getSettings().getMerged()); - } else { - this.getSettings().setMerged(Direction.WEST, false); - DBFunc.setMerged(this, this.getSettings().getMerged()); - } - } - queuecache.add(tmp); - frontier.add(tmp); - } + computeDirectMerged(queueCache, frontier, Direction.NORTH); + computeDirectMerged(queueCache, frontier, Direction.EAST); + computeDirectMerged(queueCache, frontier, Direction.SOUTH); + computeDirectMerged(queueCache, frontier, Direction.WEST); Plot current; while ((current = frontier.poll()) != null) { if (!current.hasOwner() || current.settings == null) { continue; } tmpSet.add(current); - queuecache.remove(current); - if (current.isMerged(Direction.NORTH)) { - tmp = current.area.getPlotAbs(current.id.getRelative(Direction.NORTH)); - if (tmp != null && !queuecache.contains(tmp) && !tmpSet.contains(tmp)) { - queuecache.add(tmp); - frontier.add(tmp); - } - } - if (current.isMerged(Direction.EAST)) { - tmp = current.area.getPlotAbs(current.id.getRelative(Direction.EAST)); - if (tmp != null && !queuecache.contains(tmp) && !tmpSet.contains(tmp)) { - queuecache.add(tmp); - frontier.add(tmp); - } - } - if (current.isMerged(Direction.SOUTH)) { - tmp = current.area.getPlotAbs(current.id.getRelative(Direction.SOUTH)); - if (tmp != null && !queuecache.contains(tmp) && !tmpSet.contains(tmp)) { - queuecache.add(tmp); - frontier.add(tmp); - } - } - if (current.isMerged(Direction.WEST)) { - tmp = current.area.getPlotAbs(current.id.getRelative(Direction.WEST)); - if (tmp != null && !queuecache.contains(tmp) && !tmpSet.contains(tmp)) { - queuecache.add(tmp); - frontier.add(tmp); - } - } + queueCache.remove(current); + addIfIncluded(current, Direction.NORTH, queueCache, tmpSet, frontier); + addIfIncluded(current, Direction.EAST, queueCache, tmpSet, frontier); + addIfIncluded(current, Direction.SOUTH, queueCache, tmpSet, frontier); + addIfIncluded(current, Direction.WEST, queueCache, tmpSet, frontier); } + tmpSet = Set.copyOf(tmpSet); this.connectedCache = tmpSet; return tmpSet; } + private void computeDirectMerged(Set queueCache, Deque frontier, Direction direction) { + if (this.isMerged(direction)) { + Plot tmp = this.area.getPlotAbs(this.id.getRelative(direction)); + assert tmp != null; + if (!tmp.isMerged(direction.opposite())) { + // invalid merge + if (tmp.isOwnerAbs(this.getOwnerAbs())) { + tmp.getSettings().setMerged(direction.opposite(), true); + DBFunc.setMerged(tmp, tmp.getSettings().getMerged()); + } else { + this.getSettings().setMerged(direction, false); + DBFunc.setMerged(this, this.getSettings().getMerged()); + } + } + queueCache.add(tmp); + frontier.add(tmp); + } + } + + private void addIfIncluded( + Plot current, Direction + direction, Set queueCache, Set tmpSet, Deque frontier + ) { + if (!current.isMerged(direction)) { + return; + } + Plot tmp = current.area.getPlotAbs(current.id.getRelative(direction)); + if (tmp != null && !queueCache.contains(tmp) && !tmpSet.contains(tmp)) { + queueCache.add(tmp); + frontier.add(tmp); + } + } + /** * This will combine each plot into effective rectangular regions
* - This result is cached globally