Add Region loading to DynamicRegionSystem
Some checks failed
SteamWarCI Build failed

This commit is contained in:
2026-02-28 13:26:26 +01:00
parent 66c8d2ee34
commit fb7d1570f8
5 changed files with 146 additions and 8 deletions

View File

@@ -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();

View File

@@ -0,0 +1,4 @@
{
"TNT": "DENY",
"FREEZE": "INACTIVE"
}

View File

@@ -0,0 +1,5 @@
{
"region_identifier": "SpawnRegion",
"tile_x": 0,
"tile_z": 0
}

View File

@@ -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<Long, Region> 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<Class<? extends DynamicRegion>, RegionConstructorData> constructorDataMap = new HashMap<>();
private static Map<String, Class<? extends DynamicRegion>> 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<? extends DynamicRegion>) 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<? extends DynamicRegion> 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<Tile> 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<? extends DynamicRegion> 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<? 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) {
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

View File

@@ -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;