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();
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)) {
float x = (float) (interaction.getX() - 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 tileZ = (int) z;
if (type.visualize(area, tileX, tileZ)) {
hide = false;
area.hide(false);
return;
} else {
break;
}
}
}
area.hide(hide);
area.hide(true);
}
@EventHandler
@@ -243,7 +244,7 @@ public class DynamicRegionEditor implements SWPlayer.Component, Listener {
return false;
}
Region region = DynamicRegionSystem.INSTANCE.get(tile);
if (region.getType().isGlobal()) {
if (region.getType().isGlobal() || region.getType().isSpawn()) {
valid = false;
return false;
}
@@ -267,7 +268,7 @@ public class DynamicRegionEditor implements SWPlayer.Component, Listener {
Tile tile = Tile.fromTile(tileX, tileZ).orElse(null);
if (tile == null) return;
Region region = DynamicRegionSystem.INSTANCE.get(tile);
if (region.getType().isGlobal()) return;
if (region.getType().isGlobal() || region.getType().isSpawn()) return;
if (region.getType().isPath()) {
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.global.GlobalRegion;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
@@ -158,33 +156,27 @@ public class DynamicRegionSystem implements RegionSystem {
return regionTypeMap.getOrDefault(type, Collections.emptySet()).stream();
}
@RequiredArgsConstructor
@ToString
public static class Neighbour<T extends Region> {
public final T region;
public final Tile tile;
public final NeighbourDirection direction;
public record Neighbour<T extends Region>(T region, Tile tile, NeighbourDirection direction) {
public <O extends Region> Neighbour<O> as(Class<O> clazz) {
if (!clazz.isInstance(region)) {
return null;
} else {
return (Neighbour<O>) this;
}
}
public <O extends Region> Neighbour<O> as(Class<O> clazz) {
if (!clazz.isInstance(region)) {
return null;
} else {
return (Neighbour<O>) this;
@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);
}
}
@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) {
Tile minTile = Tile.fromPoint(region.getArea().getMinPoint(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
Set<UUID> needsFullReset = new HashSet<>();
list.forEach(data -> {
boolean previousGardenState = data.region.isGarden();
data.region.calculateGardenState();
if (data.region.isGarden() != previousGardenState) {
needsFullReset.add(data.region.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.region.getID())) {
data.region.getArea().reset(new PasteBuilder(), false);
if (needsFullReset.contains(data.region().getID())) {
data.region().getArea().reset(new PasteBuilder(), false);
} else {
data.region.update(this, data.direction.opposite());
data.region().update(this, data.direction().opposite());
}
});
// 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))
.filter(Objects::nonNull)
.forEach(data -> {
if (data.region.isGarden()) return;
data.region.update(dynamicRegion, data.direction.opposite());
if (data.region().isGarden()) return;
data.region().update(dynamicRegion, data.direction().opposite());
});
});
}
@@ -33,6 +33,18 @@ import java.util.stream.Stream;
@EqualsAndHashCode
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 tileOffset = tileSize / 2;
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.Tile;
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.utils.PasteBuilder;
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);
if (optionalSide != null) {
optionalTile = optionalTile.flatMap(t -> t.add(optionalSide.tileOffsetX, optionalSide.tileOffsetZ));
}
if (optionalTile.isEmpty()) {
return RegionType.ConnectionType.Global;
return Global;
}
tile = optionalTile.get();
Region region = DynamicRegionSystem.INSTANCE.get(tile.getCenterLocation());
Region region = DynamicRegionSystem.INSTANCE.get(tile);
if (region instanceof PathRegion pathRegion) {
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();
}
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() {
garden = false;
Set<Tile> neighbours = tile.neighboursRing().collect(Collectors.toSet());
if (neighbours.size() != 8) return;
garden = neighbours.stream()
.map(DynamicRegionSystem.INSTANCE::get)
.map(Region::getType)
.allMatch(RegionType::isPath);
for (PathSide pathSide : PathSide.values()) {
RegionType.ConnectionType connectionType = PathArea.getConnectionType(tile, pathSide, null, null);
if (connectionType != RegionType.ConnectionType.Path && connectionType != RegionType.ConnectionType.Garden) return;
}
for (PathCorner pathCorner : PathCorner.values()) {
RegionType.ConnectionType connectionType = PathArea.getConnectionType(tile, pathCorner.side1, pathCorner.side2, null);
if (connectionType != RegionType.ConnectionType.Path && connectionType != RegionType.ConnectionType.Garden) return;
}
garden = true;
}
@Override
@@ -34,4 +34,13 @@ public enum PathSide {
public final int pasteOffsetX;
public final int pasteOffsetZ;
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) {
RegionType.ConnectionType left = PathArea.getConnectionType(tile, corner.side1, null);
RegionType.ConnectionType right = PathArea.getConnectionType(tile, corner.side2, null);
RegionType.ConnectionType left = PathArea.getConnectionType(tile, corner.side1, null, RegionType.ConnectionType.Closed);
RegionType.ConnectionType right = PathArea.getConnectionType(tile, corner.side2, null, RegionType.ConnectionType.Closed);
RegionType.ConnectionType diagonal = PathArea.getConnectionType(tile, corner.side1, corner.side2);
int index = getIndex(left, right, diagonal);
return new Pair<>(selectors[index], rotationCorrections[index]);
@@ -19,32 +19,56 @@
package de.steamwar.bausystem.region.dynamic.spawn;
import de.steamwar.bausystem.region.DynamicRegionSystem;
import de.steamwar.bausystem.region.Point;
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 lombok.NonNull;
import java.util.List;
public class SpawnArea extends Region.Area {
private final Tile tile;
public SpawnArea(Tile tile) {
this.tile = tile;
}
@Override
public @NonNull Point getMinPoint(boolean extension) {
return null;
return Point.fromLocation(tile.getMinLocation());
}
@Override
public @NonNull Point getMaxPoint(boolean extension) {
return null;
return Point.fromLocation(tile.getMaxLocation());
}
@Override
public @NonNull Point getCopyPoint(boolean extension) {
return null;
return Point.ZERO;
}
@Override
public void reset(PasteBuilder pasteBuilder, boolean extension) {
// TODO: Implement!
super.reset(pasteBuilder, extension);
List<DynamicRegion> regions = DynamicRegionSystem.INSTANCE.getNeighbours(DynamicRegionSystem.INSTANCE.get(Tile.ZERO))
.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
@@ -25,20 +25,39 @@ import de.steamwar.bausystem.region.RegionBackups;
import de.steamwar.bausystem.region.RegionHistory;
import de.steamwar.bausystem.region.RegionType;
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.TileUtils;
import de.steamwar.bausystem.region.dynamic.path.PathRegionData;
import de.steamwar.bausystem.region.dynamic.path.PathSide;
import de.steamwar.sql.GameModeConfig;
import lombok.Getter;
import lombok.NonNull;
import org.bukkit.Material;
import java.io.IOException;
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 {
protected static final int TILE_X = 1;
protected static final int TILE_Z = 1;
@Getter
private final Tile tile;
@Getter
private final PathSide pathSide;
private final SpawnArea area;
public SpawnRegion(Tile tile) {
this(UUID.randomUUID(), tile);
finishCreate();
@@ -52,8 +71,19 @@ public class SpawnRegion extends DynamicRegion {
private SpawnRegion(UUID id, Tile tile) {
super(id, null);
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;
// TODO: Initialize
}
@Override
@@ -63,12 +93,18 @@ public class SpawnRegion extends DynamicRegion {
@Override
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
public @NonNull Area getArea() {
return null;
return area;
}
@Override