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