Add CornerInnerGlobal and CornerOuterGlobal

Improve the selecting code
This commit is contained in:
2026-03-06 12:09:57 +01:00
parent 2116e1ee8d
commit 0bfa76e92d
5 changed files with 178 additions and 83 deletions
@@ -71,17 +71,7 @@ public abstract class DynamicRegion implements Region {
Point minPoint = getArea().getMinPoint(false);
Point maxPoint = getArea().getMaxPoint(false);
EditSession editSession = WorldEdit.getInstance()
.newEditSessionBuilder()
.world(BukkitAdapter.adapt(Bukkit.getWorlds().get(0)))
.checkMemory(false)
.allowedRegionsEverywhere()
.limitUnlimited()
.changeSetNull()
.build();
editSession.setBlocks((com.sk89q.worldedit.regions.Region) new CuboidRegion(minPoint.toBlockVector3(), maxPoint.toBlockVector3()), BlockTypes.AIR.getDefaultState());
editSession.close();
PasteUtils.reset(minPoint, maxPoint);
DynamicRegionSystem.INSTANCE.getNeighbours(this).collect(Collectors.toList())
.forEach(r -> r.update(this));
@@ -19,10 +19,14 @@
package de.steamwar.bausystem.region.dynamic;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.world.block.BlockTypes;
import de.steamwar.bausystem.region.Point;
import de.steamwar.bausystem.utils.FlatteningWrapper;
import lombok.experimental.UtilityClass;
@@ -33,6 +37,19 @@ import java.io.File;
@UtilityClass
public class PasteUtils {
public static void reset(Point minPoint, Point maxPoint) {
EditSession editSession = WorldEdit.getInstance()
.newEditSessionBuilder()
.world(BukkitAdapter.adapt(Bukkit.getWorlds().get(0)))
.checkMemory(false)
.allowedRegionsEverywhere()
.limitUnlimited()
.changeSetNull()
.build();
editSession.setBlocks((com.sk89q.worldedit.regions.Region) new CuboidRegion(minPoint.toBlockVector3(), maxPoint.toBlockVector3()), BlockTypes.AIR.getDefaultState());
editSession.close();
}
public static void paste(File file, Point minPoint, int rotate) {
Clipboard clipboard = FlatteningWrapper.impl.loadSchematic(file);
BlockVector3 offset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin());
@@ -26,6 +26,7 @@ import de.steamwar.bausystem.region.RegionType;
import de.steamwar.bausystem.region.dynamic.PasteUtils;
import de.steamwar.bausystem.region.dynamic.Tile;
import de.steamwar.bausystem.region.dynamic.VariantSelector;
import de.steamwar.bausystem.shared.Pair;
import de.steamwar.bausystem.utils.PasteBuilder;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
@@ -36,15 +37,34 @@ import java.io.File;
import java.util.Optional;
import java.util.UUID;
import static de.steamwar.bausystem.region.RegionType.ConnectionType.Global;
import static de.steamwar.bausystem.region.RegionType.ConnectionType.Path;
public class PathArea implements Region.Area {
private static final File PATH_DIR = new File(Bukkit.getWorlds().get(0).getWorldFolder(), "sections/path");
private static final VariantSelector CENTER_NORMAL = VariantSelector.Get(new File(PATH_DIR, "center/normal"));
private static final VariantSelector SIDE_GLOBAL = VariantSelector.Get(new File(PATH_DIR, "side/global"));
private static final VariantSelector CORNER_INNER_GLOBAL = VariantSelector.Get(new File(PATH_DIR, "cinner/global"));
private static final VariantSelector CORNER_OUTER_GLOBAL = VariantSelector.Get(new File(PATH_DIR, "couter/global"));
private static final SelectorSide SELECTOR_SIDE = new SelectorSide()
.Case(Path, CENTER_NORMAL)
.Case(Global, SIDE_GLOBAL);
private static final SelectorCorner SELECTOR_CORNER = new SelectorCorner()
.Case(Path, Global, Global, SIDE_GLOBAL, RotationCorrection.WithCorrection)
.Case(Global, Path, Path, SIDE_GLOBAL)
.Case(Global, Path, Global, SIDE_GLOBAL)
.Case(Path, Global, Path, SIDE_GLOBAL, RotationCorrection.WithCorrection)
.Case(Path, Path, Path, CENTER_NORMAL, RotationCorrection.UsingOrdinal)
.Case(Global, Global, Global, CORNER_OUTER_GLOBAL, RotationCorrection.UsingOrdinal)
.Case(Path, Path, Global, CORNER_INNER_GLOBAL, RotationCorrection.UsingOrdinal)
;
@RequiredArgsConstructor
private enum Side {
protected enum Side {
North(0, -1, 7, 0, 0),
South(0, 1, 7, 14, 180),
West(-1, 0, 0, 7, 90),
@@ -59,21 +79,27 @@ public class PathArea implements Region.Area {
}
@RequiredArgsConstructor
private enum Corner {
protected enum Corner {
NorthEast(Side.North, Side.East, 14, 0, 0, -90),
NorthWest(Side.North, Side.West, 0, 0, 0, 90),
SouthEast(Side.South, Side.East, 14, 14, 180, 90),
SouthWest(Side.South, Side.West, 0, 14, 180, -90),
;
private final Side side1;
private final Side side2;
protected final Side side1;
protected final Side side2;
private final int pasteOffsetX;
private final int pasteOffsetZ;
private final int rotate;
private final int rotateCorrection;
}
protected enum RotationCorrection {
Unchanged,
WithCorrection,
UsingOrdinal,
}
private final UUID regionIdentifier;
private final Tile tile;
private final Point minPoint;
@@ -121,79 +147,34 @@ public class PathArea implements Region.Area {
}
for (Side side : Side.values()) {
RegionType.ConnectionType connectionType = getConnectionType(side, null);
VariantSelector selector = switch (connectionType) {
case Path -> CENTER_NORMAL;
case Water -> null;
case Closed -> null;
case Global -> SIDE_GLOBAL;
};
if (selector == null) {
continue;
}
VariantSelector selector = SELECTOR_SIDE.Select(tile, side);
if (selector == null) continue;
resetFile = selector.select(regionIdentifier, side.ordinal() + side.rotate).orElse(null);
if (resetFile == null) {
continue;
}
if (resetFile == null) continue;
PasteUtils.paste(resetFile, minPoint.add(side.pasteOffsetX, 0, side.pasteOffsetZ), side.rotate);
}
for (Corner corner : Corner.values()) {
RegionType.ConnectionType connectionType1 = getConnectionType(corner.side1, null);
RegionType.ConnectionType connectionType2 = getConnectionType(corner.side2, null);
RegionType.ConnectionType connectionType3 = getConnectionType(corner.side1, corner.side2);
VariantSelector selector = null;
int rotate = corner.rotate;
if (connectionType1 == RegionType.ConnectionType.Path && connectionType2 == connectionType3) {
selector = switch (connectionType2) {
case Global -> SIDE_GLOBAL;
case Closed -> null;
case Water -> null;
case Path -> null;
};
rotate += corner.rotateCorrection;
}
if (connectionType1 == RegionType.ConnectionType.Global && connectionType2 == connectionType3) {
selector = switch (connectionType2) {
case Global -> null;
case Closed -> null;
case Water -> null;
case Path -> SIDE_GLOBAL;
};
}
if (connectionType2 == RegionType.ConnectionType.Path && connectionType1 == connectionType3) {
selector = switch (connectionType1) {
case Global -> SIDE_GLOBAL;
case Closed -> null;
case Water -> null;
case Path -> null;
};
}
if (connectionType2 == RegionType.ConnectionType.Global && connectionType1 == connectionType3) {
selector = switch (connectionType1) {
case Global -> null;
case Closed -> null;
case Water -> null;
case Path -> SIDE_GLOBAL;
};
rotate += corner.rotateCorrection;
}
if (connectionType1 == RegionType.ConnectionType.Path && connectionType1 == connectionType2 && connectionType1 == connectionType3) {
selector = CENTER_NORMAL;
rotate = 90 * corner.ordinal();
}
if (selector == null) {
continue;
}
Pair<VariantSelector, RotationCorrection> pair = SELECTOR_CORNER.Select(tile, corner);
VariantSelector selector = pair.getKey();
if (selector == null) continue;
RotationCorrection rotationCorrection = pair.getValue();
resetFile = selector.select(regionIdentifier, corner.side1.ordinal() * corner.side2.ordinal() + corner.side1.rotate * corner.side2.rotate).orElse(null);
if (resetFile == null) {
continue;
if (resetFile == null) continue;
int rotate = corner.rotate;
switch (rotationCorrection) {
case Unchanged:
break;
case UsingOrdinal:
rotate = corner.ordinal() * 90;
break;
case WithCorrection:
rotate += corner.rotateCorrection;
break;
}
PasteUtils.paste(resetFile, minPoint.add(corner.pasteOffsetX, 0, corner.pasteOffsetZ), rotate);
@@ -216,12 +197,12 @@ public class PathArea implements Region.Area {
return true;
}
private RegionType.ConnectionType getConnectionType(Side side, Side optionalSide) {
Optional<Tile> optionalTile = this.tile.add(side.tileOffsetX, side.tileOffsetZ);
protected static RegionType.ConnectionType getConnectionType(Tile tile, Side side, Side optionalSide) {
Optional<Tile> optionalTile = tile.add(side.tileOffsetX, side.tileOffsetZ);
if (optionalSide != null) {
optionalTile = optionalTile.flatMap(tile -> tile.add(optionalSide.tileOffsetX, optionalSide.tileOffsetZ));
optionalTile = optionalTile.flatMap(t -> t.add(optionalSide.tileOffsetX, optionalSide.tileOffsetZ));
}
return optionalTile.map(tile -> DynamicRegionSystem.INSTANCE.get(tile.getCenterLocation()).getType().getConnectionType())
return optionalTile.map(t -> DynamicRegionSystem.INSTANCE.get(t.getCenterLocation()).getType().getConnectionType())
.orElse(RegionType.ConnectionType.Global);
}
}
@@ -0,0 +1,68 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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 <https://www.gnu.org/licenses/>.
*/
package de.steamwar.bausystem.region.dynamic.path;
import de.steamwar.bausystem.region.RegionType;
import de.steamwar.bausystem.region.dynamic.Tile;
import de.steamwar.bausystem.region.dynamic.VariantSelector;
import de.steamwar.bausystem.shared.Pair;
class SelectorCorner {
private static final int BITS;
private static final int SELECTOR_COUNT;
static {
int values = RegionType.ConnectionType.values().length;
BITS = (int) (Math.log(values) / Math.log(2));
SELECTOR_COUNT = (int) Math.pow(2, BITS * 3);
}
private VariantSelector[] selectors = new VariantSelector[SELECTOR_COUNT];
private PathArea.RotationCorrection[] rotationCorrections = new PathArea.RotationCorrection[SELECTOR_COUNT];
private int getIndex(RegionType.ConnectionType left, RegionType.ConnectionType right, RegionType.ConnectionType diagonal) {
int index = left.ordinal();
index = index << BITS | right.ordinal();
return index << BITS | diagonal.ordinal();
}
public SelectorCorner Case(RegionType.ConnectionType left, RegionType.ConnectionType right, RegionType.ConnectionType diagonal, VariantSelector selector) {
int index = getIndex(left, right, diagonal);
selectors[index] = selector;
rotationCorrections[index] = PathArea.RotationCorrection.Unchanged;
return this;
}
public SelectorCorner Case(RegionType.ConnectionType left, RegionType.ConnectionType right, RegionType.ConnectionType diagonal, VariantSelector selector, PathArea.RotationCorrection rotationCorrection) {
int index = getIndex(left, right, diagonal);
selectors[index] = selector;
rotationCorrections[index] = rotationCorrection;
return this;
}
public Pair<VariantSelector, PathArea.RotationCorrection> Select(Tile tile, PathArea.Corner corner) {
RegionType.ConnectionType left = PathArea.getConnectionType(tile, corner.side1, null);
RegionType.ConnectionType right = PathArea.getConnectionType(tile, corner.side2, null);
RegionType.ConnectionType diagonal = PathArea.getConnectionType(tile, corner.side1, corner.side2);
int index = getIndex(left, right, diagonal);
return new Pair<>(selectors[index], rotationCorrections[index]);
}
}
@@ -0,0 +1,39 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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 <https://www.gnu.org/licenses/>.
*/
package de.steamwar.bausystem.region.dynamic.path;
import de.steamwar.bausystem.region.RegionType;
import de.steamwar.bausystem.region.dynamic.Tile;
import de.steamwar.bausystem.region.dynamic.VariantSelector;
class SelectorSide {
private VariantSelector[] selectors = new VariantSelector[RegionType.ConnectionType.values().length];
protected SelectorSide Case(RegionType.ConnectionType type, VariantSelector selector) {
selectors[type.ordinal()] = selector;
return this;
}
public VariantSelector Select(Tile tile, PathArea.Side side) {
RegionType.ConnectionType type = PathArea.getConnectionType(tile, side, null);
return selectors[type.ordinal()];
}
}