Fix connect behavior towards SpawnRegion

This commit is contained in:
2026-03-29 16:20:54 +02:00
parent 1706fe3372
commit bb85187434
10 changed files with 147 additions and 58 deletions
@@ -178,7 +178,6 @@ public class DynamicRegionEditor implements SWPlayer.Component, Listener {
Vector direction = player.getLocation().getDirection(); Vector direction = player.getLocation().getDirection();
RayAabIntersection intersection = new RayAabIntersection((float) startPos.getX(), (float) startPos.getY(), (float) startPos.getZ(), (float) direction.getX(), (float) direction.getY(), (float) direction.getZ()); RayAabIntersection intersection = new RayAabIntersection((float) startPos.getX(), (float) startPos.getY(), (float) startPos.getZ(), (float) direction.getX(), (float) direction.getY(), (float) direction.getZ());
boolean hide = true;
for (RInteraction interaction : entityServer.getEntitiesByType(RInteraction.class)) { for (RInteraction interaction : entityServer.getEntitiesByType(RInteraction.class)) {
float x = (float) (interaction.getX() - 0.5); float x = (float) (interaction.getX() - 0.5);
float z = (float) (interaction.getZ() - 0.5); float z = (float) (interaction.getZ() - 0.5);
@@ -186,12 +185,14 @@ public class DynamicRegionEditor implements SWPlayer.Component, Listener {
int tileX = (int) x; int tileX = (int) x;
int tileZ = (int) z; int tileZ = (int) z;
if (type.visualize(area, tileX, tileZ)) { if (type.visualize(area, tileX, tileZ)) {
hide = false; area.hide(false);
return;
} else {
break; break;
} }
} }
} }
area.hide(hide); area.hide(true);
} }
@EventHandler @EventHandler
@@ -243,7 +244,7 @@ public class DynamicRegionEditor implements SWPlayer.Component, Listener {
return false; return false;
} }
Region region = DynamicRegionSystem.INSTANCE.get(tile); Region region = DynamicRegionSystem.INSTANCE.get(tile);
if (region.getType().isGlobal()) { if (region.getType().isGlobal() || region.getType().isSpawn()) {
valid = false; valid = false;
return false; return false;
} }
@@ -267,7 +268,7 @@ public class DynamicRegionEditor implements SWPlayer.Component, Listener {
Tile tile = Tile.fromTile(tileX, tileZ).orElse(null); Tile tile = Tile.fromTile(tileX, tileZ).orElse(null);
if (tile == null) return; if (tile == null) return;
Region region = DynamicRegionSystem.INSTANCE.get(tile); Region region = DynamicRegionSystem.INSTANCE.get(tile);
if (region.getType().isGlobal()) return; if (region.getType().isGlobal() || region.getType().isSpawn()) return;
if (region.getType().isPath()) { if (region.getType().isPath()) {
region.delete(); region.delete();
@@ -24,8 +24,6 @@ import de.steamwar.bausystem.features.region.WireframeCommand;
import de.steamwar.bausystem.region.dynamic.*; import de.steamwar.bausystem.region.dynamic.*;
import de.steamwar.bausystem.region.dynamic.global.GlobalRegion; import de.steamwar.bausystem.region.dynamic.global.GlobalRegion;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -158,33 +156,27 @@ public class DynamicRegionSystem implements RegionSystem {
return regionTypeMap.getOrDefault(type, Collections.emptySet()).stream(); return regionTypeMap.getOrDefault(type, Collections.emptySet()).stream();
} }
@RequiredArgsConstructor public record Neighbour<T extends Region>(T region, Tile tile, NeighbourDirection direction) {
@ToString public <O extends Region> Neighbour<O> as(Class<O> clazz) {
public static class Neighbour<T extends Region> { if (!clazz.isInstance(region)) {
public final T region; return null;
public final Tile tile; } else {
public final NeighbourDirection direction; return (Neighbour<O>) this;
}
}
public <O extends Region> Neighbour<O> as(Class<O> clazz) { @Override
if (!clazz.isInstance(region)) { public boolean equals(Object o) {
return null; if (!(o instanceof Neighbour<?> neighbour)) return false;
} else { return Objects.equals(tile, neighbour.tile) && direction == neighbour.direction;
return (Neighbour<O>) this; }
@Override
public int hashCode() {
return Objects.hash(tile, direction);
} }
} }
@Override
public boolean equals(Object o) {
if (!(o instanceof Neighbour<?> neighbour)) return false;
return Objects.equals(tile, neighbour.tile) && direction == neighbour.direction;
}
@Override
public int hashCode() {
return Objects.hash(tile, direction);
}
}
private Stream<Neighbour<Region>> getNeighbours(Region region, boolean noCorners, boolean fastCache, Collection<Region> regions) { private Stream<Neighbour<Region>> getNeighbours(Region region, boolean noCorners, boolean fastCache, Collection<Region> regions) {
Tile minTile = Tile.fromPoint(region.getArea().getMinPoint(false)).orElse(null); Tile minTile = Tile.fromPoint(region.getArea().getMinPoint(false)).orElse(null);
Tile maxTile = Tile.fromPoint(region.getArea().getMaxPoint(false)).orElse(null); Tile maxTile = Tile.fromPoint(region.getArea().getMaxPoint(false)).orElse(null);
@@ -84,18 +84,18 @@ public abstract class DynamicRegion implements Region {
// Calculate Garden State for all neighbouring PathRegions // Calculate Garden State for all neighbouring PathRegions
Set<UUID> needsFullReset = new HashSet<>(); Set<UUID> needsFullReset = new HashSet<>();
list.forEach(data -> { list.forEach(data -> {
boolean previousGardenState = data.region.isGarden(); boolean previousGardenState = data.region().isGarden();
data.region.calculateGardenState(); data.region().calculateGardenState();
if (data.region.isGarden() != previousGardenState) { if (data.region().isGarden() != previousGardenState) {
needsFullReset.add(data.region.getID()); needsFullReset.add(data.region().getID());
} }
}); });
// Updating world state for all neighbouring PathRegions // Updating world state for all neighbouring PathRegions
list.forEach(data -> { list.forEach(data -> {
if (needsFullReset.contains(data.region.getID())) { if (needsFullReset.contains(data.region().getID())) {
data.region.getArea().reset(new PasteBuilder(), false); data.region().getArea().reset(new PasteBuilder(), false);
} else { } else {
data.region.update(this, data.direction.opposite()); data.region().update(this, data.direction().opposite());
} }
}); });
// All full reset regions need to update their neighbours! // All full reset regions need to update their neighbours!
@@ -106,8 +106,8 @@ public abstract class DynamicRegion implements Region {
.map(neighbour -> neighbour.as(PathRegion.class)) .map(neighbour -> neighbour.as(PathRegion.class))
.filter(Objects::nonNull) .filter(Objects::nonNull)
.forEach(data -> { .forEach(data -> {
if (data.region.isGarden()) return; if (data.region().isGarden()) return;
data.region.update(dynamicRegion, data.direction.opposite()); data.region().update(dynamicRegion, data.direction().opposite());
}); });
}); });
} }
@@ -33,6 +33,18 @@ import java.util.stream.Stream;
@EqualsAndHashCode @EqualsAndHashCode
public class Tile { public class Tile {
public static final Tile ZERO = new Tile(0, 0);
public static final Tile TILE_PZ = new Tile(1, 0);
public static final Tile TILE_NZ = new Tile(-1, 0);
public static final Tile TILE_ZP = new Tile(0, 1);
public static final Tile TILE_ZN = new Tile(0, -1);
public static final Tile TILE_PP = new Tile(1, 1);
public static final Tile TILE_PN = new Tile(1, -1);
public static final Tile TILE_NP = new Tile(-1, 1);
public static final Tile TILE_NN = new Tile(-1, -1);
public static final int tileSize = 21; public static final int tileSize = 21;
public static final int tileOffset = tileSize / 2; public static final int tileOffset = tileSize / 2;
public static final int maxTile = 127; public static final int maxTile = 127;
@@ -28,6 +28,7 @@ import de.steamwar.bausystem.region.RegionType;
import de.steamwar.bausystem.region.dynamic.PasteUtils; import de.steamwar.bausystem.region.dynamic.PasteUtils;
import de.steamwar.bausystem.region.dynamic.Tile; import de.steamwar.bausystem.region.dynamic.Tile;
import de.steamwar.bausystem.region.dynamic.VariantSelector; import de.steamwar.bausystem.region.dynamic.VariantSelector;
import de.steamwar.bausystem.region.dynamic.spawn.SpawnRegion;
import de.steamwar.bausystem.shared.Pair; import de.steamwar.bausystem.shared.Pair;
import de.steamwar.bausystem.utils.PasteBuilder; import de.steamwar.bausystem.utils.PasteBuilder;
import lombok.NonNull; import lombok.NonNull;
@@ -220,19 +221,30 @@ public class PathArea extends Region.Area {
} }
} }
protected static RegionType.ConnectionType getConnectionType(Tile tile, PathSide side, PathSide optionalSide) { protected static RegionType.ConnectionType getConnectionType(Tile tile, PathSide side, PathSide optionalSide, RegionType.ConnectionType spawnPathConnection) {
Optional<Tile> optionalTile = tile.add(side.tileOffsetX, side.tileOffsetZ); Optional<Tile> optionalTile = tile.add(side.tileOffsetX, side.tileOffsetZ);
if (optionalSide != null) { if (optionalSide != null) {
optionalTile = optionalTile.flatMap(t -> t.add(optionalSide.tileOffsetX, optionalSide.tileOffsetZ)); optionalTile = optionalTile.flatMap(t -> t.add(optionalSide.tileOffsetX, optionalSide.tileOffsetZ));
} }
if (optionalTile.isEmpty()) { if (optionalTile.isEmpty()) {
return RegionType.ConnectionType.Global; return Global;
} }
tile = optionalTile.get(); tile = optionalTile.get();
Region region = DynamicRegionSystem.INSTANCE.get(tile.getCenterLocation()); Region region = DynamicRegionSystem.INSTANCE.get(tile);
if (region instanceof PathRegion pathRegion) { if (region instanceof PathRegion pathRegion) {
return pathRegion.isGarden() ? Garden : Path; return pathRegion.isGarden() ? Garden : Path;
} }
if (region instanceof SpawnRegion spawnRegion) {
if (optionalSide == null && side.opposite().equals(spawnRegion.getPathSide())) {
return spawnPathConnection;
} else {
return Closed;
}
}
return region.getType().getConnectionType(); return region.getType().getConnectionType();
} }
protected static RegionType.ConnectionType getConnectionType(Tile tile, PathSide side, PathSide optionalSide) {
return getConnectionType(tile, side, optionalSide, Path);
}
} }
@@ -86,12 +86,15 @@ public class PathRegion extends DynamicRegion {
public void calculateGardenState() { public void calculateGardenState() {
garden = false; garden = false;
Set<Tile> neighbours = tile.neighboursRing().collect(Collectors.toSet()); for (PathSide pathSide : PathSide.values()) {
if (neighbours.size() != 8) return; RegionType.ConnectionType connectionType = PathArea.getConnectionType(tile, pathSide, null, null);
garden = neighbours.stream() if (connectionType != RegionType.ConnectionType.Path && connectionType != RegionType.ConnectionType.Garden) return;
.map(DynamicRegionSystem.INSTANCE::get) }
.map(Region::getType) for (PathCorner pathCorner : PathCorner.values()) {
.allMatch(RegionType::isPath); RegionType.ConnectionType connectionType = PathArea.getConnectionType(tile, pathCorner.side1, pathCorner.side2, null);
if (connectionType != RegionType.ConnectionType.Path && connectionType != RegionType.ConnectionType.Garden) return;
}
garden = true;
} }
@Override @Override
@@ -34,4 +34,13 @@ public enum PathSide {
public final int pasteOffsetX; public final int pasteOffsetX;
public final int pasteOffsetZ; public final int pasteOffsetZ;
public final int rotate; public final int rotate;
public PathSide opposite() {
return switch (this) {
case North -> South;
case South -> North;
case East -> West;
case West -> East;
};
}
} }
@@ -59,8 +59,8 @@ class SelectorCorner {
} }
public Pair<VariantSelector, PathArea.RotationCorrection> Select(Tile tile, PathCorner corner) { public Pair<VariantSelector, PathArea.RotationCorrection> Select(Tile tile, PathCorner corner) {
RegionType.ConnectionType left = PathArea.getConnectionType(tile, corner.side1, null); RegionType.ConnectionType left = PathArea.getConnectionType(tile, corner.side1, null, RegionType.ConnectionType.Closed);
RegionType.ConnectionType right = PathArea.getConnectionType(tile, corner.side2, null); RegionType.ConnectionType right = PathArea.getConnectionType(tile, corner.side2, null, RegionType.ConnectionType.Closed);
RegionType.ConnectionType diagonal = PathArea.getConnectionType(tile, corner.side1, corner.side2); RegionType.ConnectionType diagonal = PathArea.getConnectionType(tile, corner.side1, corner.side2);
int index = getIndex(left, right, diagonal); int index = getIndex(left, right, diagonal);
return new Pair<>(selectors[index], rotationCorrections[index]); return new Pair<>(selectors[index], rotationCorrections[index]);
@@ -19,32 +19,56 @@
package de.steamwar.bausystem.region.dynamic.spawn; package de.steamwar.bausystem.region.dynamic.spawn;
import de.steamwar.bausystem.region.DynamicRegionSystem;
import de.steamwar.bausystem.region.Point; import de.steamwar.bausystem.region.Point;
import de.steamwar.bausystem.region.Region; import de.steamwar.bausystem.region.Region;
import de.steamwar.bausystem.region.RegionType;
import de.steamwar.bausystem.region.dynamic.DynamicRegion;
import de.steamwar.bausystem.region.dynamic.Tile;
import de.steamwar.bausystem.utils.PasteBuilder; import de.steamwar.bausystem.utils.PasteBuilder;
import lombok.NonNull; import lombok.NonNull;
import java.util.List;
public class SpawnArea extends Region.Area { public class SpawnArea extends Region.Area {
private final Tile tile;
public SpawnArea(Tile tile) {
this.tile = tile;
}
@Override @Override
public @NonNull Point getMinPoint(boolean extension) { public @NonNull Point getMinPoint(boolean extension) {
return null; return Point.fromLocation(tile.getMinLocation());
} }
@Override @Override
public @NonNull Point getMaxPoint(boolean extension) { public @NonNull Point getMaxPoint(boolean extension) {
return null; return Point.fromLocation(tile.getMaxLocation());
} }
@Override @Override
public @NonNull Point getCopyPoint(boolean extension) { public @NonNull Point getCopyPoint(boolean extension) {
return null; return Point.ZERO;
} }
@Override @Override
public void reset(PasteBuilder pasteBuilder, boolean extension) { public void reset(PasteBuilder pasteBuilder, boolean extension) {
// TODO: Implement! List<DynamicRegion> regions = DynamicRegionSystem.INSTANCE.getNeighbours(DynamicRegionSystem.INSTANCE.get(Tile.ZERO))
super.reset(pasteBuilder, extension); .map(DynamicRegionSystem.Neighbour::region)
.toList();
if (regions.stream().map(DynamicRegion::getType).allMatch(RegionType::isSpawn)) {
// TODO: Implement big spawn!
return;
}
for (DynamicRegion region : regions) {
if (region.getArea() instanceof SpawnArea spawnArea) {
spawnArea.place(new PasteBuilder(), false);
}
}
} }
@Override @Override
@@ -25,20 +25,39 @@ import de.steamwar.bausystem.region.RegionBackups;
import de.steamwar.bausystem.region.RegionHistory; import de.steamwar.bausystem.region.RegionHistory;
import de.steamwar.bausystem.region.RegionType; import de.steamwar.bausystem.region.RegionType;
import de.steamwar.bausystem.region.dynamic.DynamicRegion; import de.steamwar.bausystem.region.dynamic.DynamicRegion;
import de.steamwar.bausystem.region.dynamic.RegionConstructorData;
import de.steamwar.bausystem.region.dynamic.Tile; import de.steamwar.bausystem.region.dynamic.Tile;
import de.steamwar.bausystem.region.dynamic.TileUtils; import de.steamwar.bausystem.region.dynamic.TileUtils;
import de.steamwar.bausystem.region.dynamic.path.PathRegionData; import de.steamwar.bausystem.region.dynamic.path.PathRegionData;
import de.steamwar.bausystem.region.dynamic.path.PathSide;
import de.steamwar.sql.GameModeConfig; import de.steamwar.sql.GameModeConfig;
import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
import org.bukkit.Material; import org.bukkit.Material;
import java.io.IOException; import java.io.IOException;
import java.util.UUID; import java.util.UUID;
@RegionConstructorData(
identifier = "spawn",
name = "Spawn",
widthX = SpawnRegion.TILE_X,
widthZ = SpawnRegion.TILE_Z,
material = Material.LODESTONE,
placeable = false
)
public class SpawnRegion extends DynamicRegion { public class SpawnRegion extends DynamicRegion {
protected static final int TILE_X = 1;
protected static final int TILE_Z = 1;
@Getter
private final Tile tile; private final Tile tile;
@Getter
private final PathSide pathSide;
private final SpawnArea area;
public SpawnRegion(Tile tile) { public SpawnRegion(Tile tile) {
this(UUID.randomUUID(), tile); this(UUID.randomUUID(), tile);
finishCreate(); finishCreate();
@@ -52,8 +71,19 @@ public class SpawnRegion extends DynamicRegion {
private SpawnRegion(UUID id, Tile tile) { private SpawnRegion(UUID id, Tile tile) {
super(id, null); super(id, null);
this.tile = tile; this.tile = tile;
if (tile.equals(Tile.TILE_PZ)) {
pathSide = PathSide.East;
} else if (tile.equals(Tile.TILE_NZ)) {
pathSide = PathSide.West;
} else if (tile.equals(Tile.TILE_ZP)) {
pathSide = PathSide.South;
} else if (tile.equals(Tile.TILE_ZN)) {
pathSide = PathSide.North;
} else {
pathSide = null;
}
area = new SpawnArea(tile);
regionData = PathRegionData.INSTANCE; regionData = PathRegionData.INSTANCE;
// TODO: Initialize
} }
@Override @Override
@@ -63,12 +93,18 @@ public class SpawnRegion extends DynamicRegion {
@Override @Override
public @NonNull RegionType getType() { public @NonNull RegionType getType() {
return RegionType.SPAWN; if (tile.equals(Tile.ZERO)) {
return RegionType.SPAWN;
} else if (pathSide != null) {
return RegionType.SPAWN_PATH;
} else {
return RegionType.SPAWN_EXTENSION;
}
} }
@Override @Override
public @NonNull Area getArea() { public @NonNull Area getArea() {
return null; return area;
} }
@Override @Override