From e35295ab0c21da009e4b35db4cb45cc47813fc0b Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Sat, 28 Feb 2026 13:26:26 +0100 Subject: [PATCH] Add Region loading to DynamicRegionSystem --- .../bausystem/region/RegionSystem.java | 4 + .../flags.json | 4 + .../meta.json | 5 + .../bausystem/region/DynamicRegionSystem.java | 140 +++++++++++++++++- .../region/dynamic/RegionConstructorData.java | 1 + 5 files changed, 146 insertions(+), 8 deletions(-) create mode 100644 BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/00000000-0000-0000-0000-000000000000/flags.json create mode 100644 BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/00000000-0000-0000-0000-000000000000/meta.json diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/RegionSystem.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/RegionSystem.java index 1dbea107..abfa9e27 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/RegionSystem.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/RegionSystem.java @@ -19,6 +19,7 @@ package de.steamwar.bausystem.region; +import de.steamwar.bausystem.BauSystem; import de.steamwar.core.Core; import lombok.NonNull; import org.bukkit.Location; @@ -27,10 +28,13 @@ import javax.annotation.CheckReturnValue; import java.lang.reflect.InvocationTargetException; import java.util.Optional; import java.util.UUID; +import java.util.logging.Logger; import java.util.stream.Stream; public interface RegionSystem { + Logger LOGGER = BauSystem.getInstance().getLogger(); + UUID GLOBAL_REGION_ID = new UUID(0, 0); RegionSystem INSTANCE = init(); diff --git a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/00000000-0000-0000-0000-000000000000/flags.json b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/00000000-0000-0000-0000-000000000000/flags.json new file mode 100644 index 00000000..38df8ecc --- /dev/null +++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/00000000-0000-0000-0000-000000000000/flags.json @@ -0,0 +1,4 @@ +{ + "TNT": "DENY", + "FREEZE": "INACTIVE" +} \ No newline at end of file diff --git a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/00000000-0000-0000-0000-000000000000/meta.json b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/00000000-0000-0000-0000-000000000000/meta.json new file mode 100644 index 00000000..70c78272 --- /dev/null +++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/00000000-0000-0000-0000-000000000000/meta.json @@ -0,0 +1,5 @@ +{ + "region_identifier": "SpawnRegion", + "tile_x": 0, + "tile_z": 0 +} \ No newline at end of file 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 1132f308..3602da91 100644 --- a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionSystem.java +++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionSystem.java @@ -19,21 +19,38 @@ package de.steamwar.bausystem.region; +import com.google.gson.JsonIOException; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; import de.steamwar.bausystem.BauSystem; 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.global.GlobalRegion; import lombok.NonNull; +import org.bukkit.Bukkit; import org.bukkit.Location; -import java.io.BufferedReader; -import java.io.InputStreamReader; +import java.io.*; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Parameter; import java.util.*; +import java.util.function.Function; +import java.util.logging.Level; +import java.util.stream.Collectors; import java.util.stream.Stream; public class DynamicRegionSystem implements RegionSystem { + public static final File REGION_DATA_FOLDER = new File(Bukkit.getWorlds().get(0).getWorldFolder(), "steamwar_regions"); + public static final String META_FILE_NAME = "meta.json"; + + static { + REGION_DATA_FOLDER.mkdirs(); + } + public static DynamicRegionSystem INSTANCE; private static final Map regionCache = new LinkedHashMap<>(16, 0.75f, true) { @@ -57,11 +74,15 @@ public class DynamicRegionSystem implements RegionSystem { regionTypeMap.getOrDefault(region.getType(), Collections.emptySet()).remove(region); } + private static Map, RegionConstructorData> constructorDataMap = new HashMap<>(); + private static Map> identifierDataMap = new HashMap<>(); + @Override public void load() { INSTANCE = this; - new BufferedReader(new InputStreamReader(BauSystem.getInstance().getClass().getResourceAsStream("/META-INF/annotations/de.steamwar.bausystem.region.dynamic.RegionConstructorData"))) + // Loading all Region Constructor Data that are defined inside the Code + constructorDataMap = new BufferedReader(new InputStreamReader(BauSystem.getInstance().getClass().getResourceAsStream("/META-INF/annotations/de.steamwar.bausystem.region.dynamic.RegionConstructorData"))) .lines() .map(s -> { try { @@ -70,11 +91,114 @@ public class DynamicRegionSystem implements RegionSystem { throw new SecurityException(e.getMessage(), e); } }) - .forEach(clazz -> { - RegionConstructorData regionConstructorData = clazz.getAnnotation(RegionConstructorData.class); - if (regionConstructorData == null) return; - // TODO: Save regionConstructorData together with clazz - }); + .filter(DynamicRegion.class::isAssignableFrom) + .map(clazz -> (Class) clazz) + .collect(Collectors.toUnmodifiableMap(Function.identity(), clazz -> clazz.getAnnotation(RegionConstructorData.class))); + identifierDataMap = constructorDataMap.entrySet() + .stream() + .collect(Collectors.toUnmodifiableMap(entry -> entry.getValue().identifier(), Map.Entry::getKey)); + + // Loading all saved regions from the files + File[] regions = REGION_DATA_FOLDER.listFiles(); + for (File region : regions) { + UUID regionUUID; + try { + regionUUID = UUID.fromString(region.getName()); + } catch (IllegalArgumentException e) { + LOGGER.log(Level.WARNING, "Failed to resolve region id: " + region.getName()); + continue; + } + if (regionUUID == GLOBAL_REGION_ID) { + continue; + } + + File metaFile = new File(region, META_FILE_NAME); + if (!metaFile.exists() || !metaFile.isFile()) { + LOGGER.log(Level.WARNING, "Failed to resolve " + region.getName()); + continue; + } + + JsonObject metaData; + try { + metaData = JsonParser.parseReader(new FileReader(metaFile)).getAsJsonObject(); + } catch (JsonIOException e) { + LOGGER.log(Level.SEVERE, "Failed to read region metadata file (unknown)"); + continue; + } catch (JsonSyntaxException | IllegalStateException e) { + LOGGER.log(Level.SEVERE, "Failed to read region metadata file (invalid json)"); + continue; + } catch (FileNotFoundException e) { + LOGGER.log(Level.SEVERE, "Failed to read region metadata file (not found)"); + continue; + } + + int tileX; + int tileZ; + String identifier; + try { + tileX = metaData.getAsJsonPrimitive("tile_x").getAsInt(); + tileZ = metaData.getAsJsonPrimitive("tile_z").getAsInt(); + identifier = metaData.getAsJsonPrimitive("region_identifier").getAsString(); + } catch (ClassCastException | NumberFormatException e) { + LOGGER.log(Level.SEVERE, "Failed to read region metadata file (invalid json)"); + continue; + } + + Class regionClass = identifierDataMap.get(identifier); + if (regionClass == null) { + LOGGER.log(Level.SEVERE, "Failed to read region metadata file (region no longer exists)"); + continue; + } + RegionConstructorData constructorData = constructorDataMap.get(regionClass); + + Optional optionalTile = Tile.fromTile(tileX, tileZ); + if (optionalTile.isEmpty()) { + LOGGER.log(Level.SEVERE, "Failed to read region metadata file (tile is no longer in bounds)"); + continue; + } + Tile tile = optionalTile.get(); + Location minTileLocation = tile.getMinLocation(); + + Constructor regionConstructor; + try { + regionConstructor = regionClass.getConstructor(UUID.class, int.class, int.class); + } catch (NoSuchMethodException e) { + LOGGER.log(Level.SEVERE, "Failed to read region metadata file (region constructor not found)"); + continue; + } + + Class regionDataClass = constructorData.regionDataClass(); + Constructor 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) constructor; + break; + } + } + if (regionDataConstructor == null) { + 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()); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + 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) { + LOGGER.log(Level.SEVERE, "Failed to instantiate region data (invalid data)"); + continue; + } + dynamicRegion.setRegionData(regionData); + } } @Override 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 953f1c60..4468dd78 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 @@ -31,6 +31,7 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface RegionConstructorData { + String identifier(); int widthX(); int widthZ(); boolean placeable() default true;