diff --git a/core/src/main/java/com/volmit/iris/core/IrisWorlds.java b/core/src/main/java/com/volmit/iris/core/IrisWorlds.java new file mode 100644 index 000000000..9c8302102 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/core/IrisWorlds.java @@ -0,0 +1,79 @@ +package com.volmit.iris.core; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.volmit.iris.Iris; +import com.volmit.iris.engine.data.cache.AtomicCache; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.io.IO; +import org.bukkit.Bukkit; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.lang.reflect.Type; +import java.util.Objects; +import java.util.stream.Stream; + +public class IrisWorlds { + private static final AtomicCache cache = new AtomicCache<>(); + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + private static final Type TYPE = TypeToken.getParameterized(KMap.class, String.class, String.class).getType(); + private final KMap worlds; + private volatile boolean dirty = false; + + private IrisWorlds(KMap worlds) { + this.worlds = worlds; + save(); + } + + public static IrisWorlds get() { + return cache.aquire(() -> { + File file = Iris.instance.getDataFile("worlds.json"); + if (!file.exists()) { + return new IrisWorlds(new KMap<>()); + } + + try { + String json = IO.readAll(file); + KMap worlds = GSON.fromJson(json, TYPE); + return new IrisWorlds(Objects.requireNonNullElseGet(worlds, KMap::new)); + } catch (Throwable e) { + Iris.error("Failed to load worlds.json!"); + e.printStackTrace(); + Iris.reportError(e); + } + + return new IrisWorlds(new KMap<>()); + }); + } + + public void put(String name, String type) { + String old = worlds.put(name, type); + if (!type.equals(old)) + dirty = true; + save(); + } + + public Stream getFolders() { + return worlds.keySet().stream().map(k -> new File(Bukkit.getWorldContainer(), k)); + } + + public void clean() { + dirty = worlds.entrySet().removeIf(entry -> !new File(Bukkit.getWorldContainer(), entry.getKey() + "/iris/pack/dimensions/" + entry.getValue() + ".json").exists()); + } + + public synchronized void save() { + clean(); + if (!dirty) return; + try { + IO.write(Iris.instance.getDataFile("worlds.json"), OutputStreamWriter::new, writer -> GSON.toJson(worlds, TYPE, writer)); + dirty = false; + } catch (IOException e) { + Iris.error("Failed to save worlds.json!"); + e.printStackTrace(); + Iris.reportError(e); + } + } +} diff --git a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java index f039f3b6d..79261d63d 100644 --- a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java +++ b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java @@ -226,8 +226,8 @@ public class ServerConfigurator { } public static Stream allPacks() { - return Stream.concat(listFiles(new File("plugins/Iris/packs")), - listFiles(Bukkit.getWorldContainer()).map(w -> new File(w, "iris/pack"))) + return Stream.concat(listFiles(Iris.instance.getDataFolder("packs")), + IrisWorlds.get().getFolders().map(w -> new File(w, "iris/pack"))) .filter(File::isDirectory) .filter( base -> { var content = new File(base, "dimensions").listFiles(); diff --git a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java index e1c598fed..2e6035534 100644 --- a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java +++ b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java @@ -19,9 +19,9 @@ package com.volmit.iris.engine.platform; import com.volmit.iris.Iris; +import com.volmit.iris.core.IrisWorlds; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.nms.INMS; -import com.volmit.iris.core.nms.container.AutoClosing; import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.engine.IrisEngine; import com.volmit.iris.engine.data.cache.AtomicCache; @@ -62,7 +62,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; -import java.lang.reflect.Field; import java.util.List; import java.util.Random; import java.util.concurrent.CompletableFuture; @@ -115,35 +114,35 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun @EventHandler(priority = EventPriority.LOWEST) public void onWorldInit(WorldInitEvent event) { - try { - if (initialized || !world.name().equals(event.getWorld().getName())) - return; - AutoClosing.closeContext(); - world.setRawWorldSeed(event.getWorld().getSeed()); - Engine engine = getEngine(event.getWorld()); - if (engine == null) { - Iris.warn("Failed to get Engine!"); - J.s(() -> { - Engine engine1 = getEngine(event.getWorld()); - if (engine1 != null) { - try { - INMS.get().inject(event.getWorld().getSeed(), engine1, event.getWorld()); - Iris.info("Injected Iris Biome Source into " + event.getWorld().getName()); - initialized = true; - } catch (Throwable e) { - e.printStackTrace(); - } - } - }, 10); - } else { - INMS.get().inject(event.getWorld().getSeed(), engine, event.getWorld()); - Iris.info("Injected Iris Biome Source into " + event.getWorld().getName()); - spawnChunks.complete(INMS.get().getSpawnChunkCount(event.getWorld())); - initialized = true; + if (initialized || !world.name().equals(event.getWorld().getName())) + return; + world.setRawWorldSeed(event.getWorld().getSeed()); + if (initialize(event.getWorld())) return; + + Iris.warn("Failed to get Engine for " + event.getWorld().getName() + " re-trying..."); + J.s(() -> { + if (!initialize(event.getWorld())) { + Iris.error("Failed to get Engine for " + event.getWorld().getName() + "!"); } + }, 10); + } + + private boolean initialize(World world) { + Engine engine = getEngine(world); + if (engine == null) return false; + try { + INMS.get().inject(world.getSeed(), engine, world); + Iris.info("Injected Iris Biome Source into " + world.getName()); } catch (Throwable e) { + Iris.reportError(e); + Iris.error("Failed to inject biome source into " + world.getName()); e.printStackTrace(); } + spawnChunks.complete(INMS.get().getSpawnChunkCount(world)); + Iris.instance.unregisterListener(this); + initialized = true; + IrisWorlds.get().put(world.getName(), dimensionKey); + return true; } @Nullable diff --git a/core/src/main/java/com/volmit/iris/util/io/IO.java b/core/src/main/java/com/volmit/iris/util/io/IO.java index 281f08096..61deb3670 100644 --- a/core/src/main/java/com/volmit/iris/util/io/IO.java +++ b/core/src/main/java/com/volmit/iris/util/io/IO.java @@ -1643,7 +1643,7 @@ public class IO { return (ch2 == -1); } - public static void write(File file, IOFunction builder, IOConsumer action) throws IOException { + public static void write(File file, IOFunction builder, IOConsumer action) throws IOException { File dir = new File(file.getParentFile(), ".tmp"); dir.mkdirs(); dir.deleteOnExit();