diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/Region.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/Region.java
index bd44975d..52acdac4 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/Region.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/Region.java
@@ -24,6 +24,7 @@ import de.steamwar.bausystem.utils.FlatteningWrapper;
import de.steamwar.bausystem.utils.PasteBuilder;
import de.steamwar.sql.GameModeConfig;
import lombok.NonNull;
+import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
@@ -82,6 +83,9 @@ public interface Region extends RegionDataStore {
interface Area {
+ int WORLD_MIN_Y = Bukkit.getWorlds().get(0).getMinHeight();
+ int WORLD_MAX_Y = Bukkit.getWorlds().get(0).getMaxHeight();
+
Area EMPTY = new Area() {
@Override
public boolean isEmpty() {
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/RegionData.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/RegionData.java
index 3e0ff06c..285d11b5 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/RegionData.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/RegionData.java
@@ -41,7 +41,7 @@ public abstract class RegionData {
protected RegionData(RegionDataStore store) {
this.store = store;
initialize();
- store.loadRegion();
+ store.loadRegion(this);
}
public final void setStore(RegionDataStore store) {
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/RegionDataStore.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/RegionDataStore.java
index 4784ad72..3523f193 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/RegionDataStore.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/RegionDataStore.java
@@ -21,7 +21,7 @@ package de.steamwar.bausystem.region;
public interface RegionDataStore {
void saveRegion();
- void loadRegion();
+ void loadRegion(RegionData regionData);
default void deleteRegion() {
}
}
diff --git a/BauSystem/BauSystem_RegionDynamic/build.gradle.kts b/BauSystem/BauSystem_RegionDynamic/build.gradle.kts
index b4cccb47..d94d9de5 100644
--- a/BauSystem/BauSystem_RegionDynamic/build.gradle.kts
+++ b/BauSystem/BauSystem_RegionDynamic/build.gradle.kts
@@ -32,6 +32,7 @@ java {
dependencies {
compileOnly(libs.classindex)
+ annotationProcessor(libs.classindex)
compileOnly(project(":BauSystem:BauSystem_Main", "default"))
compileOnly(project(":SpigotCore", "default"))
diff --git a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionCommand.java b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionCommand.java
new file mode 100644
index 00000000..ab53c48e
--- /dev/null
+++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionCommand.java
@@ -0,0 +1,66 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2020 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 .
+ */
+
+package de.steamwar.bausystem.region;
+
+import de.steamwar.bausystem.features.region.RegionCommand;
+import de.steamwar.bausystem.region.dynamic.DynamicRegion;
+import de.steamwar.bausystem.region.dynamic.Tile;
+import de.steamwar.bausystem.region.dynamic.path.PathRegion;
+import de.steamwar.bausystem.region.dynamic.path.PathRegionData;
+import de.steamwar.bausystem.utils.PasteBuilder;
+import de.steamwar.command.AbstractSWCommand;
+import de.steamwar.command.SWCommand;
+import org.bukkit.entity.Player;
+
+import java.util.Optional;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+@AbstractSWCommand.PartOf(RegionCommand.class)
+public class DynamicRegionCommand extends SWCommand {
+
+ public DynamicRegionCommand() {
+ super("");
+ }
+
+ @Register({"dynamic", "place"})
+ public void placeRegion(Player player) {
+ Region region = DynamicRegionSystem.INSTANCE.get(player.getLocation());
+ if (!region.getType().isGlobal()) return;
+ Optional optionalTile = Tile.fromLocation(player.getLocation());
+ if (optionalTile.isEmpty()) return;
+ Tile tile = optionalTile.get();
+
+ // TODO: Replace!
+ PathRegion dynamicRegion = new PathRegion(UUID.randomUUID(), tile.getMinX(), tile.getMinZ());
+ dynamicRegion.setRegionData(new PathRegionData(dynamicRegion));
+
+ dynamicRegion.getArea().reset(new PasteBuilder(new PasteBuilder.FileProvider(dynamicRegion.getArea().getResetFile())), false);
+ DynamicRegionSystem.INSTANCE.getNeighbours(dynamicRegion).collect(Collectors.toList())
+ .forEach(r -> r.update(dynamicRegion));
+ }
+
+ @Register({"dynamic", "delete"})
+ public void deleteRegion(Player player) {
+ Region region = DynamicRegionSystem.INSTANCE.get(player.getLocation());
+ if (region.getType().isCannotDelete()) return;
+ ((DynamicRegion) region).delete();
+ }
+}
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 b38f73d1..89d22d6c 100644
--- a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionSystem.java
+++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionSystem.java
@@ -28,7 +28,8 @@ import de.steamwar.bausystem.region.dynamic.global.GlobalRegion;
import lombok.NonNull;
import org.bukkit.Location;
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -55,7 +56,7 @@ public class DynamicRegionSystem implements RegionSystem {
public void remove(DynamicRegion region) {
regionCache.clear();
- regionMap.remove(region.getId());
+ regionMap.remove(region.getID());
regionTypeMap.getOrDefault(region.getType(), Collections.emptySet()).remove(region);
}
@@ -84,6 +85,7 @@ public class DynamicRegionSystem implements RegionSystem {
.collect(Collectors.toUnmodifiableMap(entry -> entry.getValue().identifier(), Map.Entry::getKey));
DynamicRegionRepository.loadRegions();
+ new DynamicRegionCommand();
}
@Override
@@ -151,8 +153,10 @@ public class DynamicRegionSystem implements RegionSystem {
return neighbours.stream();
}
- public Stream getNeighbours(Region region) {
- return getNeighbours(region, false, true, regionMap.values());
+ public Stream getNeighbours(Region region) {
+ return getNeighbours(region, false, true, regionMap.values())
+ .filter(DynamicRegion.class::isInstance)
+ .map(DynamicRegion.class::cast);
}
public Stream getConnectedRegions(Region region) {
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 334f5a94..83e3e2df 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
@@ -19,17 +19,24 @@
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.regions.CuboidRegion;
+import com.sk89q.worldedit.world.block.BlockTypes;
import de.steamwar.bausystem.region.DynamicRegionSystem;
+import de.steamwar.bausystem.region.Point;
import de.steamwar.bausystem.region.Region;
import de.steamwar.bausystem.region.RegionData;
import lombok.Getter;
import lombok.NonNull;
+import org.bukkit.Bukkit;
import java.util.UUID;
+import java.util.stream.Collectors;
public abstract class DynamicRegion implements Region {
- @Getter
protected final UUID id;
protected final int minX;
protected final int minZ;
@@ -42,20 +49,42 @@ public abstract class DynamicRegion implements Region {
this.minX = minX;
this.minZ = minZ;
DynamicRegionSystem.INSTANCE.add(this);
- // TODO: Implement further
}
public void update(DynamicRegion updateFrom) {
+ // TODO: Implement further
}
public void setRegionData(@NonNull RegionData regionData) {
- regionData.setStore(this);
this.regionData = regionData;
+ regionData.setStore(this);
}
public void delete() {
if (getType().isCannotDelete()) return;
DynamicRegionSystem.INSTANCE.remove(this);
- // TODO: Implement!
+ DynamicRegionRepository.deleteRegion(this);
+
+ 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();
+
+ DynamicRegionSystem.INSTANCE.getNeighbours(this).collect(Collectors.toList())
+ .forEach(r -> r.update(this));
+ }
+
+ @Override
+ public @NonNull UUID getID() {
+ return id;
}
}
diff --git a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/DynamicRegionRepository.java b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/DynamicRegionRepository.java
index f6df631a..823dc68d 100644
--- a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/DynamicRegionRepository.java
+++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/DynamicRegionRepository.java
@@ -35,7 +35,6 @@ import org.bukkit.Location;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Parameter;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -156,48 +155,22 @@ public class DynamicRegionRepository {
continue;
}
- Class extends RegionData> regionDataClass = constructorData.regionDataClass();
- Constructor extends RegionData> regionDataConstructor = null;
- for (Constructor> constructor : regionDataClass.getConstructors()) {
- if (constructor.getParameters().length != 1) continue;
- Parameter parameter = constructor.getParameters()[0];
- if (parameter.getType().isAssignableFrom(regionClass)) {
- regionDataConstructor = (Constructor extends RegionData>) constructor;
- break;
- }
- }
- if (regionDataConstructor == null) {
- RegionSystem.LOGGER.log(Level.SEVERE, "Failed to read region metadata file (region data constructor not found)");
- continue;
- }
-
- DynamicRegion dynamicRegion;
try {
- dynamicRegion = regionConstructor.newInstance(regionUUID, minTileLocation.getBlockX(), minTileLocation.getBlockZ());
+ regionConstructor.newInstance(regionUUID, minTileLocation.getBlockX(), minTileLocation.getBlockZ());
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException |
InvocationTargetException e) {
RegionSystem.LOGGER.log(Level.SEVERE, "Failed to read region metadata file (invalid data)");
- continue;
}
-
- RegionData regionData;
- try {
- regionData = regionDataConstructor.newInstance(dynamicRegion);
- } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
- RegionSystem.LOGGER.log(Level.SEVERE, "Failed to instantiate region data (invalid data)");
- continue;
- }
- dynamicRegion.setRegionData(regionData);
}
}
- public static void loadRegionData(Region region) {
+ public static void loadRegionData(Region region, RegionData regionData) {
File regionDirectory = new File(REGION_DATA_FOLDER, region.getID().toString());
if (!regionDirectory.exists()) return;
- loadRegionData(regionDirectory, region.getRegionData());
+ loadRegionData(regionDirectory, regionData);
}
- public static void loadRegionData(Region region, RegionBackups.Backup backup) {
+ public static void loadRegionData(Region region, RegionBackups.Backup backup, RegionData regionData) {
File regionDirectory = new File(REGION_DATA_FOLDER, region.getID().toString());
if (!regionDirectory.exists()) return;
File backupsDirectory = new File(regionDirectory, BACKUPS_DIR_NAME);
@@ -206,7 +179,7 @@ public class DynamicRegionRepository {
if (!backupsTypeDirectory.exists()) return;
File backupDirectory = new File(backupsTypeDirectory, backup.getName());
if (!backupDirectory.exists()) return;
- loadRegionData(backupDirectory, backup.getRegionData());
+ loadRegionData(backupDirectory, regionData);
}
private static void loadRegionData(File regionDirectory, RegionData regionData) {
@@ -281,27 +254,26 @@ public class DynamicRegionRepository {
@SneakyThrows
private static void writeFlagsFile(File regionDirectory, RegionData regionData) {
- @Cleanup
JsonWriter jsonWriter = new JsonWriter(new FileWriter(new File(regionDirectory, FLAG_FILE_NAME)));
jsonWriter.setIndent(" ");
jsonWriter.beginObject();
- {
- jsonWriter.name(FLAGS_KEY);
- jsonWriter.beginObject();
- for (Flag> flag : Flag.getFlags()) {
- if (!regionData.has(flag).isApplicable()) continue;
- jsonWriter.name(flag.name());
- jsonWriter.value(regionData.get(flag).nameWithDefault());
- }
- jsonWriter.endObject();
- }
- {
- jsonWriter.name(PROPERTIES_KEY);
- jsonWriter.beginObject();
- // TODO: Write out needed properties!
- jsonWriter.endObject();
+
+ jsonWriter.name(FLAGS_KEY);
+ jsonWriter.beginObject();
+ for (Flag> flag : Flag.getFlags()) {
+ if (!regionData.has(flag).isApplicable()) continue;
+ jsonWriter.name(flag.name());
+ jsonWriter.value(regionData.get(flag).nameWithDefault());
}
jsonWriter.endObject();
+
+ jsonWriter.name(PROPERTIES_KEY);
+ jsonWriter.beginObject();
+ // TODO: Write out needed properties!
+ jsonWriter.endObject();
+
+ jsonWriter.endObject();
+ jsonWriter.close();
}
public static void deleteRegion(Region region) {
diff --git a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/RegionConstructorData.java b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/RegionConstructorData.java
index 4468dd78..483241e1 100644
--- a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/RegionConstructorData.java
+++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/RegionConstructorData.java
@@ -19,7 +19,6 @@
package de.steamwar.bausystem.region.dynamic;
-import de.steamwar.bausystem.region.RegionData;
import org.atteo.classindex.IndexAnnotated;
import java.lang.annotation.ElementType;
@@ -35,5 +34,4 @@ public @interface RegionConstructorData {
int widthX();
int widthZ();
boolean placeable() default true;
- Class extends RegionData> regionDataClass();
}
diff --git a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/Tile.java b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/Tile.java
index a9f26176..b3594eb6 100644
--- a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/Tile.java
+++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/Tile.java
@@ -28,7 +28,7 @@ import java.util.Optional;
@Getter
public class Tile {
- public static final int tileSize = 19;
+ public static final int tileSize = 21;
public static final int tileOffset = tileSize / 2;
public static final int maxTile = 1023;
public static final int minTile = -maxTile;
@@ -78,6 +78,22 @@ public class Tile {
return getMinZ(tileZ);
}
+ public static int getMaxX(int tileX) {
+ return tileX * tileSize + tileOffset;
+ }
+
+ public int getMaxX() {
+ return getMaxX(tileX);
+ }
+
+ public static int getMaxZ(int tileZ) {
+ return tileZ * tileSize + tileOffset;
+ }
+
+ public int getMaxZ() {
+ return getMaxZ(tileZ);
+ }
+
public static Location getMinLocation(int tileX, int tileZ) {
return new Location(null, getMinX(tileX), 0, getMinZ(tileZ));
}
@@ -86,6 +102,22 @@ public class Tile {
return getMinLocation(tileX, tileZ);
}
+ public static Location getMaxLocation(int tileX, int tileZ) {
+ return new Location(null, getMaxX(tileX), 0, getMaxZ(tileZ));
+ }
+
+ public Location getMaxLocation() {
+ return getMaxLocation(tileX, tileZ);
+ }
+
+ public static Location getCenterLocation(int tileX, int tileZ) {
+ return new Location(null, tileX * tileSize, 0, tileZ * tileSize);
+ }
+
+ public Location getCenterLocation() {
+ return getCenterLocation(tileX, tileZ);
+ }
+
public Optional add(int offsetX, int offsetZ) {
return fromTile(tileX + offsetX, tileZ + offsetZ);
}
diff --git a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/VariantSelector.java b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/VariantSelector.java
new file mode 100644
index 00000000..63c1b720
--- /dev/null
+++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/VariantSelector.java
@@ -0,0 +1,94 @@
+/*
+ * 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 .
+ */
+
+package de.steamwar.bausystem.region.dynamic;
+
+import lombok.NonNull;
+
+import java.io.File;
+import java.time.LocalDate;
+import java.time.Month;
+import java.util.*;
+
+public abstract class VariantSelector {
+
+ private static final Random RANDOM = new Random();
+ public static final VariantSelector EMPTY = new VariantSelector() {
+ @Override
+ public Optional select(UUID regionID, int drift) {
+ return Optional.empty();
+ }
+ };
+
+ private VariantSelector() {
+ }
+
+ public abstract Optional select(UUID regionID, int drift);
+
+ public final VariantSelector or(VariantSelector other) {
+ if (this == EMPTY) return other;
+ VariantSelector self = this;
+ return new VariantSelector() {
+ @Override
+ public Optional select(UUID regionID, int drift) {
+ return self.select(regionID, drift).or(() -> other.select(regionID, drift));
+ }
+ };
+ }
+
+ public final VariantSelector atDate(int day, Month month) {
+ if (this == EMPTY) return this;
+ VariantSelector self = this;
+ return new VariantSelector() {
+ @Override
+ public Optional select(UUID regionID, int drift) {
+ LocalDate date = LocalDate.now();
+ if (date.getDayOfMonth() == day && date.getMonth() == month) {
+ return self.select(regionID, drift);
+ } else {
+ return Optional.empty();
+ }
+ }
+ };
+ }
+
+ public static VariantSelector Get(@NonNull File directory) {
+ final File[] files = directory.listFiles();
+ if (files == null || files.length == 0) return EMPTY;
+ if (files.length == 1) {
+ final File file = files[0];
+ return new VariantSelector() {
+ @Override
+ public Optional select(UUID regionID, int drift) {
+ return Optional.of(file);
+ }
+ };
+ }
+
+ Arrays.sort(files, Comparator.comparing(File::getName));
+ final int filesCount = files.length;
+ return new VariantSelector() {
+ @Override
+ public Optional select(UUID regionID, int drift) {
+ RANDOM.setSeed(regionID.getLeastSignificantBits() ^ regionID.getMostSignificantBits() ^ drift);
+ return Optional.of(files[RANDOM.nextInt(filesCount)]);
+ }
+ };
+ }
+}
diff --git a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/global/GlobalRegion.java b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/global/GlobalRegion.java
index 5f281176..78679a52 100644
--- a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/global/GlobalRegion.java
+++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/global/GlobalRegion.java
@@ -140,7 +140,7 @@ public class GlobalRegion implements Region {
}
@Override
- public void loadRegion() {
- DynamicRegionRepository.loadRegionData(this);
+ public void loadRegion(RegionData regionData) {
+ DynamicRegionRepository.loadRegionData(this, regionData);
}
}
diff --git a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/global/GlobalRegionData.java b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/global/GlobalRegionData.java
index be9b957b..86c9957f 100644
--- a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/global/GlobalRegionData.java
+++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/global/GlobalRegionData.java
@@ -21,7 +21,6 @@ package de.steamwar.bausystem.region.dynamic.global;
import de.steamwar.bausystem.region.RegionData;
import de.steamwar.bausystem.region.RegionFlagPolicy;
-import de.steamwar.bausystem.region.flags.ColorMode;
import de.steamwar.bausystem.region.flags.Flag;
import de.steamwar.bausystem.region.flags.ProtectMode;
import de.steamwar.bausystem.region.flags.TNTMode;
@@ -37,13 +36,12 @@ public class GlobalRegionData extends RegionData {
@Override
protected void initialize() {
flagMap.put(Flag.TNT, TNTMode.DENY);
- flagMap.put(Flag.COLOR, ColorMode.YELLOW);
flagMap.put(Flag.PROTECT, ProtectMode.INACTIVE);
}
@Override
public @NonNull & Flag.Value> RegionFlagPolicy has(@NonNull Flag flag) {
- if (flag.oneOf(Flag.COLOR, Flag.PROTECT)) {
+ if (flag.oneOf(Flag.PROTECT)) {
return RegionFlagPolicy.READ_ONLY;
}
if (flag.oneOf(Flag.ITEMS) && Core.getVersion() >= 20) {
diff --git a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/path/PathArea.java b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/path/PathArea.java
new file mode 100644
index 00000000..7d4e74b7
--- /dev/null
+++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/path/PathArea.java
@@ -0,0 +1,238 @@
+/*
+ * 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 .
+ */
+
+package de.steamwar.bausystem.region.dynamic.path;
+
+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 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.Tile;
+import de.steamwar.bausystem.region.dynamic.VariantSelector;
+import de.steamwar.bausystem.utils.FlatteningWrapper;
+import de.steamwar.bausystem.utils.PasteBuilder;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+import org.bukkit.Bukkit;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.util.Optional;
+import java.util.UUID;
+
+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"));
+
+ @RequiredArgsConstructor
+ private enum Side {
+ North(0, -1, 7, 0, 0),
+ South(0, 1, 7, 14, 180),
+ West(-1, 0, 0, 7, 90),
+ East(1, 0, 14, 7, 270),
+ ;
+
+ private final int tileOffsetX;
+ private final int tileOffsetZ;
+ private final int pasteOffsetX;
+ private final int pasteOffsetZ;
+ private final int rotate;
+ }
+
+ @RequiredArgsConstructor
+ private 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;
+ private final int pasteOffsetX;
+ private final int pasteOffsetZ;
+ private final int rotate;
+ private final int rotateCorrection;
+ }
+
+ private final UUID regionIdentifier;
+ private final Tile tile;
+ private final Point minPoint;
+ private final Point maxPoint;
+ private final Point copyPoint;
+
+ public PathArea(Tile tile, PathRegion region) {
+ this.regionIdentifier = region.getID();
+ this.tile = tile;
+
+ minPoint = Point.fromLocation(tile.getMinLocation()).setY(WORLD_MIN_Y);
+ maxPoint = Point.fromLocation(tile.getMaxLocation()).setY(WORLD_MAX_Y);
+ copyPoint = Point.fromLocation(tile.getCenterLocation());
+ }
+
+ @Override
+ public @NonNull Point getMinPoint(boolean extension) {
+ return minPoint;
+ }
+
+ @Override
+ public @NonNull Point getMaxPoint(boolean extension) {
+ return maxPoint;
+ }
+
+ @Override
+ public @NonNull Point getCopyPoint() {
+ return copyPoint;
+ }
+
+ @Override
+ public @Nullable File getResetFile() {
+ return null; // I know what I do!
+ }
+
+ @Override
+ public void reset(PasteBuilder pasteBuilder, boolean extension) {
+ if (surroundedByPath()) {
+ // TODO: Implement Garden case!
+ }
+
+ File resetFile = CENTER_NORMAL.select(regionIdentifier, 0).orElse(null);
+ if (resetFile != null) {
+ paste(resetFile, minPoint.add(7, 0, 7), 0);
+ }
+
+ 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;
+ }
+
+ resetFile = selector.select(regionIdentifier, side.ordinal() + side.rotate).orElse(null);
+ if (resetFile == null) {
+ continue;
+ }
+
+ 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 = 0;
+ }
+ if (selector == null) {
+ continue;
+ }
+
+ resetFile = selector.select(regionIdentifier, corner.side1.ordinal() * corner.side2.ordinal() + corner.side1.rotate * corner.side2.rotate).orElse(null);
+ if (resetFile == null) {
+ continue;
+ }
+
+ paste(resetFile, minPoint.add(corner.pasteOffsetX, 0, corner.pasteOffsetZ), rotate);
+ }
+ }
+
+ private boolean surroundedByPath() {
+ for (int x = -1; x <= 1; x++) {
+ for (int z = -1; z <= 1; z++) {
+ if (x == 0 && z == 0) continue;
+ Optional optionalTile = this.tile.add(x, z);
+ if (optionalTile.isEmpty()) {
+ return false;
+ }
+ if (DynamicRegionSystem.INSTANCE.get(optionalTile.get().getCenterLocation()).getType() != RegionType.PATH) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private RegionType.ConnectionType getConnectionType(Side side, Side optionalSide) {
+ Optional optionalTile = this.tile.add(side.tileOffsetX, side.tileOffsetZ);
+ if (optionalSide != null) {
+ optionalTile = optionalTile.flatMap(tile -> tile.add(optionalSide.tileOffsetX, optionalSide.tileOffsetZ));
+ }
+ return optionalTile.map(tile -> DynamicRegionSystem.INSTANCE.get(tile.getCenterLocation()).getType().getConnectionType())
+ .orElse(RegionType.ConnectionType.Global);
+ }
+
+ private void paste(File file, Point minPoint, int rotate) {
+ Clipboard clipboard = FlatteningWrapper.impl.loadSchematic(file);
+ BlockVector3 offset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin());
+ BlockVector3 to = minPoint.toBlockVector3().subtract(offset);
+ clipboard.paste(BukkitAdapter.adapt(Bukkit.getWorlds().get(0)), to, false, true, new AffineTransform().rotateY(rotate));
+ }
+}
diff --git a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/path/PathRegion.java b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/path/PathRegion.java
new file mode 100644
index 00000000..9e3ce322
--- /dev/null
+++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/path/PathRegion.java
@@ -0,0 +1,101 @@
+/*
+ * 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 .
+ */
+
+package de.steamwar.bausystem.region.dynamic.path;
+
+import de.steamwar.bausystem.region.RegionBackups;
+import de.steamwar.bausystem.region.RegionData;
+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.DynamicRegionRepository;
+import de.steamwar.bausystem.region.dynamic.RegionConstructorData;
+import de.steamwar.bausystem.region.dynamic.Tile;
+import de.steamwar.sql.GameModeConfig;
+import lombok.NonNull;
+import org.bukkit.Material;
+
+import java.util.UUID;
+
+@RegionConstructorData(
+ identifier = "path",
+ widthX = Tile.tileSize,
+ widthZ = Tile.tileSize
+)
+public class PathRegion extends DynamicRegion {
+
+ private final PathArea area;
+
+ public PathRegion(UUID id, int minX, int minZ) {
+ super(id, minX, minZ);
+ area = new PathArea(Tile.fromXZ(minX, minZ).orElseThrow(), this);
+ regionData = new PathRegionData(this);
+ }
+
+ @Override
+ public void update(DynamicRegion updateFrom) {
+ // TODO: Improve
+ area.reset(null, false);
+ }
+
+ @Override
+ public @NonNull RegionType getType() {
+ return RegionType.PATH;
+ }
+
+ @Override
+ public @NonNull Area getArea() {
+ return area;
+ }
+
+ @Override
+ public @NonNull Area getBuildArea() {
+ return Area.EMPTY;
+ }
+
+ @Override
+ public @NonNull Area getTestblockArea() {
+ return Area.EMPTY;
+ }
+
+ @Override
+ public @NonNull GameModeConfig getGameModeConfig() {
+ return GameModeConfig.getDefaults();
+ }
+
+ @Override
+ public @NonNull RegionHistory getHistory() {
+ return RegionHistory.EMPTY;
+ }
+
+ @Override
+ public @NonNull RegionBackups getBackups() {
+ return RegionBackups.EMPTY;
+ }
+
+ @Override
+ public void saveRegion() {
+ DynamicRegionRepository.saveRegion(this);
+ }
+
+ @Override
+ public void loadRegion(RegionData regionData) {
+ DynamicRegionRepository.loadRegionData(this, regionData);
+ }
+}
diff --git a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/path/PathRegionData.java b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/path/PathRegionData.java
new file mode 100644
index 00000000..1f04d83c
--- /dev/null
+++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/path/PathRegionData.java
@@ -0,0 +1,57 @@
+/*
+ * 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 .
+ */
+
+package de.steamwar.bausystem.region.dynamic.path;
+
+import de.steamwar.bausystem.region.RegionData;
+import de.steamwar.bausystem.region.RegionFlagPolicy;
+import de.steamwar.bausystem.region.flags.FireMode;
+import de.steamwar.bausystem.region.flags.Flag;
+import de.steamwar.bausystem.region.flags.ProtectMode;
+import de.steamwar.bausystem.region.flags.TNTMode;
+import de.steamwar.core.Core;
+import lombok.NonNull;
+
+public class PathRegionData extends RegionData {
+
+ public PathRegionData(PathRegion pathRegion) {
+ super(pathRegion);
+ }
+
+ @Override
+ protected void initialize() {
+ flagMap.put(Flag.TNT, TNTMode.DENY);
+ flagMap.put(Flag.FIRE, FireMode.DENY);
+ flagMap.put(Flag.PROTECT, ProtectMode.INACTIVE);
+ }
+
+ @Override
+ public @NonNull & Flag.Value> RegionFlagPolicy has(@NonNull Flag flag) {
+ if (flag.oneOf(Flag.TNT, Flag.FIRE, Flag.PROTECT)) {
+ return RegionFlagPolicy.READ_ONLY;
+ }
+ if (flag.oneOf(Flag.ITEMS) && Core.getVersion() >= 20) {
+ return RegionFlagPolicy.WRITABLE;
+ }
+ if (flag.oneOf(Flag.FREEZE)) {
+ return RegionFlagPolicy.WRITABLE;
+ }
+ return RegionFlagPolicy.NOT_APPLICABLE;
+ }
+}
diff --git a/BauSystem/BauSystem_RegionFixed/src/de/steamwar/bausystem/region/fixed/FixedGlobalRegion.java b/BauSystem/BauSystem_RegionFixed/src/de/steamwar/bausystem/region/fixed/FixedGlobalRegion.java
index 3f31baa8..3f9d21e8 100644
--- a/BauSystem/BauSystem_RegionFixed/src/de/steamwar/bausystem/region/fixed/FixedGlobalRegion.java
+++ b/BauSystem/BauSystem_RegionFixed/src/de/steamwar/bausystem/region/fixed/FixedGlobalRegion.java
@@ -147,7 +147,7 @@ public final class FixedGlobalRegion implements Region {
}
@Override
- public void loadRegion() {
+ public void loadRegion(RegionData regionData) {
FixedRegionDataUtils.loadRegionData("global", FLAG_STORAGE);
}
}
diff --git a/BauSystem/BauSystem_RegionFixed/src/de/steamwar/bausystem/region/fixed/FixedRegion.java b/BauSystem/BauSystem_RegionFixed/src/de/steamwar/bausystem/region/fixed/FixedRegion.java
index d9c8c06b..f19e46ec 100644
--- a/BauSystem/BauSystem_RegionFixed/src/de/steamwar/bausystem/region/fixed/FixedRegion.java
+++ b/BauSystem/BauSystem_RegionFixed/src/de/steamwar/bausystem/region/fixed/FixedRegion.java
@@ -143,7 +143,7 @@ public class FixedRegion implements Region {
}
@Override
- public void loadRegion() {
+ public void loadRegion(RegionData regionData) {
}
@Override
@@ -407,7 +407,7 @@ public class FixedRegion implements Region {
}
@Override
- public void loadRegion() {
+ public void loadRegion(RegionData regionData) {
FixedRegionDataUtils.loadRegionData(name, flagStorage);
}
}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index a5a193b4..53f6b7da 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -166,7 +166,7 @@ include(
"BauSystem",
"BauSystem:BauSystem_Main",
"BauSystem:BauSystem_RegionDynamic",
- "BauSystem:BauSystem_RegionDynamic2",
+ // "BauSystem:BauSystem_RegionDynamic2",
"BauSystem:BauSystem_RegionFixed"
)