diff --git a/src/main/java/com/volmit/iris/Iris.java b/src/main/java/com/volmit/iris/Iris.java index bfd31ef4e..b56533dba 100644 --- a/src/main/java/com/volmit/iris/Iris.java +++ b/src/main/java/com/volmit/iris/Iris.java @@ -41,14 +41,14 @@ import com.volmit.iris.util.Permission; import com.volmit.iris.util.RollingSequence; import com.volmit.iris.util.ScoreDirection; -public class Iris extends MortarPlugin implements BoardProvider { +public class Iris extends MortarPlugin implements BoardProvider +{ public static KList executors = new KList<>(); public static Iris instance; public static IrisDataManager globaldata; public static ProjectManager proj; public static IrisHotloadManager hotloader; public static WandController wand; - private static String last = ""; private BoardManager manager; private String mem = "..."; private ChronoLatch cl = new ChronoLatch(1000); @@ -65,27 +65,31 @@ public class Iris extends MortarPlugin implements BoardProvider { @com.volmit.iris.util.Command public CommandIris commandIris; - public Iris() { + public Iris() + { IO.delete(new File("iris")); } @Override - public void start() { + public void start() + { } @Override - public void stop() { + public void stop() + { } @Override - public String getTag(String subTag) { - return ChatColor.BOLD + "" + ChatColor.DARK_GRAY + "[" + ChatColor.BOLD + "" + ChatColor.GREEN + "Iris" - + ChatColor.BOLD + ChatColor.DARK_GRAY + "]" + ChatColor.RESET + "" + ChatColor.GRAY + ": "; + public String getTag(String subTag) + { + return ChatColor.BOLD + "" + ChatColor.DARK_GRAY + "[" + ChatColor.BOLD + "" + ChatColor.GREEN + "Iris" + ChatColor.BOLD + ChatColor.DARK_GRAY + "]" + ChatColor.RESET + "" + ChatColor.GRAY + ": "; } - public void onEnable() { + public void onEnable() + { lock = new IrisLock("Iris"); instance = this; hotloader = new IrisHotloadManager(); @@ -93,22 +97,25 @@ public class Iris extends MortarPlugin implements BoardProvider { wand = new WandController(); postProcessors = loadPostProcessors(); proj = new ProjectManager(); - manager = new BoardManager(this, - BoardSettings.builder().boardProvider(this).scoreDirection(ScoreDirection.UP).build()); + manager = new BoardManager(this, BoardSettings.builder().boardProvider(this).scoreDirection(ScoreDirection.UP).build()); super.onEnable(); } - public void onDisable() { + public void onDisable() + { lock.unlock(); proj.close(); - for (GroupedExecutor i : executors) { + for(GroupedExecutor i : executors) + { i.close(); } - for (World i : Bukkit.getWorlds()) { - if (i.getGenerator() instanceof IrisChunkGenerator) { + for(World i : Bukkit.getWorlds()) + { + if(i.getGenerator() instanceof IrisChunkGenerator) + { ((IrisChunkGenerator) i).close(); } } @@ -121,23 +128,28 @@ public class Iris extends MortarPlugin implements BoardProvider { } @Override - public String getTitle(Player player) { + public String getTitle(Player player) + { return ChatColor.GREEN + "Iris"; } @Override - public List getLines(Player player) { - if (!clf.flip()) { + public List getLines(Player player) + { + if(!clf.flip()) + { return lines; } World world = player.getWorld(); lines.clear(); - if (world.getGenerator() instanceof IrisChunkGenerator) { + if(world.getGenerator() instanceof IrisChunkGenerator) + { IrisChunkGenerator g = (IrisChunkGenerator) world.getGenerator(); - if (cl.flip()) { + if(cl.flip()) + { mem = Form.memSize(g.guessMemoryUsage(), 2); } @@ -150,23 +162,21 @@ public class Iris extends MortarPlugin implements BoardProvider { tp.put(g.getMetrics().getSpeed()); lines.add("&7&m-----------------"); - lines.add(ChatColor.GREEN + "Speed" + ChatColor.GRAY + ": " + ChatColor.BOLD + "" + ChatColor.GRAY - + Form.f(g.getMetrics().getPerSecond().getAverage(), 0) + "/s " - + Form.duration(g.getMetrics().getTotal().getAverage(), 1) + ""); + lines.add(ChatColor.GREEN + "Speed" + ChatColor.GRAY + ": " + ChatColor.BOLD + "" + ChatColor.GRAY + Form.f(g.getMetrics().getPerSecond().getAverage(), 0) + "/s " + Form.duration(g.getMetrics().getTotal().getAverage(), 1) + ""); lines.add(ChatColor.GREEN + "Generators" + ChatColor.GRAY + ": " + Form.f(CNG.creates)); lines.add(ChatColor.GREEN + "Noise" + ChatColor.GRAY + ": " + Form.f((int) hits.getAverage())); - lines.add(ChatColor.GREEN + "Parallax Chunks" + ChatColor.GRAY + ": " - + Form.f((int) g.getParallaxMap().getLoadedChunks().size())); - lines.add(ChatColor.GREEN + "Objects" + ChatColor.GRAY + ": " - + Form.f(g.getData().getObjectLoader().count())); + lines.add(ChatColor.GREEN + "Parallax Chunks" + ChatColor.GRAY + ": " + Form.f((int) g.getParallaxMap().getLoadedChunks().size())); + lines.add(ChatColor.GREEN + "Objects" + ChatColor.GRAY + ": " + Form.f(g.getData().getObjectLoader().count())); lines.add(ChatColor.GREEN + "Memory" + ChatColor.GRAY + ": " + mem); - if (er != null && b != null) { + if(er != null && b != null) + { lines.add(ChatColor.GREEN + "Biome" + ChatColor.GRAY + ": " + b.getName()); lines.add(ChatColor.GREEN + "File" + ChatColor.GRAY + ": " + b.getLoadKey()); } - if (st != null) { + if(st != null) + { lines.add(ChatColor.GREEN + "Structure" + ChatColor.GRAY + ": " + st.getStructure().getName()); lines.add(ChatColor.GREEN + "Tile" + ChatColor.GRAY + ": " + st.getTile().toString()); } @@ -174,14 +184,16 @@ public class Iris extends MortarPlugin implements BoardProvider { lines.add("&7&m-----------------"); } - else { + else + { lines.add(ChatColor.GREEN + "Join an Iris World!"); } return lines; } - private static KList> loadPostProcessors() { + private static KList> loadPostProcessors() + { KList> g = new KList>(); g.add(PostFloatingNibDeleter.class); @@ -195,55 +207,57 @@ public class Iris extends MortarPlugin implements BoardProvider { } @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) + { return super.onCommand(sender, command, label, args); } - public void imsg(CommandSender s, String msg) { - s.sendMessage(ChatColor.GREEN + "[" + ChatColor.DARK_GRAY + "Iris" + ChatColor.GREEN + "]" + ChatColor.GRAY - + ": " + msg); + public void imsg(CommandSender s, String msg) + { + s.sendMessage(ChatColor.GREEN + "[" + ChatColor.DARK_GRAY + "Iris" + ChatColor.GREEN + "]" + ChatColor.GRAY + ": " + msg); } @Override - public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) { - return new IrisChunkGenerator(16); + public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) + { + return new IrisChunkGenerator(IrisSettings.get().threads); } - public static void msg(String string) { + public static void msg(String string) + { lock.lock(); String msg = ChatColor.GREEN + "[Iris]: " + ChatColor.GRAY + string; - - if (last.equals(msg)) { - lock.unlock(); - return; - } - - last = msg; Bukkit.getConsoleSender().sendMessage(msg); lock.unlock(); } - public static void warn(String string) { + public static void warn(String string) + { msg(ChatColor.YELLOW + string); } - public static void error(String string) { + public static void error(String string) + { msg(ChatColor.RED + string); } - public static void verbose(String string) { + public static void verbose(String string) + { msg(ChatColor.GRAY + string); } - public static void success(String string) { + public static void success(String string) + { msg(ChatColor.GREEN + string); } - public static void info(String string) { + public static void info(String string) + { msg(ChatColor.WHITE + string); } - public void hit(long hits2) { + public void hit(long hits2) + { hits.put(hits2); } } diff --git a/src/main/java/com/volmit/iris/IrisDataManager.java b/src/main/java/com/volmit/iris/IrisDataManager.java index 926cb547e..352c0bacc 100644 --- a/src/main/java/com/volmit/iris/IrisDataManager.java +++ b/src/main/java/com/volmit/iris/IrisDataManager.java @@ -43,12 +43,14 @@ public class IrisDataManager File packs = this.packs.getName().equals("packs") ? this.packs : dataFolder; packs.mkdirs(); + this.regionLoader = new ResourceLoader<>(packs, "regions", "Region", IrisRegion.class); this.biomeLoader = new ResourceLoader<>(packs, "biomes", "Biome", IrisBiome.class); this.dimensionLoader = new ResourceLoader<>(packs, "dimensions", "Dimension", IrisDimension.class); this.structureLoader = new ResourceLoader<>(packs, "structures", "Structure", IrisStructure.class); this.generatorLoader = new ResourceLoader<>(packs, "generators", "Generator", IrisGenerator.class); this.objectLoader = new ObjectResourceLoader(packs, "objects", "Object"); + if(packs.getName().equals("packs")) { writeExamples(); @@ -164,4 +166,13 @@ public class IrisDataManager generatorLoader.preferFolder(name); structureLoader.preferFolder(name); } + + public void clearLists() + { + biomeLoader.clearList(); + regionLoader.clearList(); + dimensionLoader.clearList(); + generatorLoader.clearList(); + structureLoader.clearList(); + } } \ No newline at end of file diff --git a/src/main/java/com/volmit/iris/IrisHotloadManager.java b/src/main/java/com/volmit/iris/IrisHotloadManager.java index 7e1fa0cdb..8dbcbd37b 100644 --- a/src/main/java/com/volmit/iris/IrisHotloadManager.java +++ b/src/main/java/com/volmit/iris/IrisHotloadManager.java @@ -3,19 +3,20 @@ package com.volmit.iris; import java.io.File; import org.bukkit.Bukkit; +import org.bukkit.entity.Player; import com.volmit.iris.util.ChronoLatch; -import com.volmit.iris.util.FileWatcher; -import com.volmit.iris.util.KSet; +import com.volmit.iris.util.FolderWatcher; public class IrisHotloadManager { private ChronoLatch latch; - private KSet watchers; + + private FolderWatcher w; public IrisHotloadManager() { - watchers = new KSet<>(); + w = new FolderWatcher(Iris.instance.getDataFolder("packs")); latch = new ChronoLatch(3000); } @@ -33,13 +34,87 @@ public class IrisHotloadManager try { - for(FileWatcher i : watchers) + if(w.checkModified()) { - if(i.checkModified()) + for(File i : w.getCreated()) { - c++; - Iris.info("File Modified: " + i.getFile().getPath()); + if(i.isDirectory()) + { + continue; + } + + if(i.getPath().contains(".git")) + { + continue; + } + + if(i.getPath().contains("_docs")) + { + continue; + } + + if(i.getName().endsWith(".code-workspace")) + { + continue; + } + modified = true; + c++; + Iris.verbose("File Created: " + i.getPath()); + } + + for(File i : w.getDeleted()) + { + if(i.isDirectory()) + { + continue; + } + + if(i.getPath().contains("_docs")) + { + continue; + } + + if(i.getPath().contains(".git")) + { + continue; + } + + if(i.getName().endsWith(".code-workspace")) + { + continue; + } + + modified = true; + c++; + Iris.verbose("File Deleted: " + i.getPath()); + } + + for(File i : w.getChanged()) + { + if(i.isDirectory()) + { + continue; + } + + if(i.getPath().contains(".git")) + { + continue; + } + + if(i.getPath().contains("_docs")) + { + continue; + } + + if(i.getName().endsWith(".code-workspace")) + { + continue; + } + + modified = true; + c++; + Iris.verbose("File Modified: " + i.getPath()); } } } @@ -51,8 +126,14 @@ public class IrisHotloadManager if(modified) { - watchers.clear(); - Iris.success("Hotloading Iris (" + c + " File" + (c == 1 ? "" : "s") + " changed)"); + String m = "Hotloaded " + c + " File" + (c == 1 ? "" : "s"); + + for(Player i : Bukkit.getOnlinePlayers()) + { + i.sendMessage(Iris.instance.getTag("Studio") + m); + } + + Bukkit.getConsoleSender().sendMessage(Iris.instance.getTag("Studio") + m); Iris.globaldata.hotloaded(); ch.onHotloaded(); } @@ -61,6 +142,6 @@ public class IrisHotloadManager public void track(File file) { - watchers.add(new FileWatcher(file)); + } } diff --git a/src/main/java/com/volmit/iris/IrisSettings.java b/src/main/java/com/volmit/iris/IrisSettings.java index 2e6c85132..2dfb98b3c 100644 --- a/src/main/java/com/volmit/iris/IrisSettings.java +++ b/src/main/java/com/volmit/iris/IrisSettings.java @@ -1,14 +1,21 @@ package com.volmit.iris; +import java.io.File; +import java.io.IOException; + +import com.google.gson.Gson; import com.volmit.iris.util.Desc; import com.volmit.iris.util.DontObfuscate; +import com.volmit.iris.util.IO; +import com.volmit.iris.util.JSONException; +import com.volmit.iris.util.JSONObject; public class IrisSettings { public static transient IrisSettings settings; @DontObfuscate - @Desc("Iris generator threads (must be 2 or higher).") + @Desc("Iris generator threads (must be 2 or higher). Threads in iris are not a perfect scale for performance as a lot of data has to be shared. 16 Threads is a good rule of thumb. Use 8 threads on a quad core processor.") public int threads = 16; @DontObfuscate @@ -17,14 +24,67 @@ public class IrisSettings @DontObfuscate @Desc("Compression level (0-9) lower is faster, but is not as good compression. Best results around 3-5") - public int parallaxCompressionLevel = 3; + public int parallaxCompressionLevel = 2; + + @DontObfuscate + @Desc("If A is a child of B, and B is a child of A, how deep should iris follow the children in biomes. Lower is faster gen.") + public int maxBiomeChildDepth = 5; + + @DontObfuscate + @Desc("When enabled, The cache is shared for all chunks and cleared periodically instead of per chunk. This uses more memory but provides a ~15% speedup.") + public boolean sharedCaching = true; + + @DontObfuscate + @Desc("Allows configs to be changed and hotloaded without reloading.") + public boolean hotloading = true; public static IrisSettings get() { if(settings == null) { settings = new IrisSettings(); - // TODO LOAD + + File s = Iris.instance.getDataFile("settings.json"); + + if(!s.exists()) + { + try + { + IO.writeAll(s, new JSONObject(new Gson().toJson(settings)).toString(4)); + } + + catch(JSONException | IOException e) + { + e.printStackTrace(); + } + } + + else + { + try + { + settings = new Gson().fromJson(IO.readAll(s), IrisSettings.class); + } + + catch(JSONException | IOException e) + { + e.printStackTrace(); + s.delete(); + } + } + + if(!s.exists()) + { + try + { + IO.writeAll(s, new JSONObject(new Gson().toJson(settings)).toString(4)); + } + + catch(JSONException | IOException e) + { + e.printStackTrace(); + } + } } return settings; diff --git a/src/main/java/com/volmit/iris/ProjectManager.java b/src/main/java/com/volmit/iris/ProjectManager.java index 74481f791..b419375a3 100644 --- a/src/main/java/com/volmit/iris/ProjectManager.java +++ b/src/main/java/com/volmit/iris/ProjectManager.java @@ -6,6 +6,7 @@ import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.UUID; +import java.util.concurrent.locks.ReentrantLock; import org.bukkit.Bukkit; import org.bukkit.GameMode; @@ -56,7 +57,15 @@ import com.volmit.iris.util.MaxNumber; import com.volmit.iris.util.MinNumber; import com.volmit.iris.util.MortarSender; import com.volmit.iris.util.O; +import com.volmit.iris.util.RegistryListBiome; +import com.volmit.iris.util.RegistryListDimension; +import com.volmit.iris.util.RegistryListGenerator; +import com.volmit.iris.util.RegistryListObject; +import com.volmit.iris.util.RegistryListRegion; +import com.volmit.iris.util.RegistryListStructure; import com.volmit.iris.util.Required; +import com.volmit.iris.util.TaskExecutor; +import com.volmit.iris.util.TaskExecutor.TaskGroup; import lombok.Data; @@ -64,6 +73,8 @@ import lombok.Data; public class ProjectManager { private IrisChunkGenerator currentProject; + private TaskExecutor tx = new TaskExecutor(8, Thread.MIN_PRIORITY, "Iris Compiler"); + private ReentrantLock lock = new ReentrantLock(); public ProjectManager() { @@ -522,7 +533,7 @@ public class ProjectManager IO.writeAll(Iris.instance.getDataFile("packs", dimension.getLoadKey(), "biomes", exampleShore1.getLoadKey() + ".json"), new JSONObject(new Gson().toJson(exampleShore1)).toString(4)); IO.writeAll(Iris.instance.getDataFile("packs", dimension.getLoadKey(), "biomes", exampleOcean1.getLoadKey() + ".json"), new JSONObject(new Gson().toJson(exampleOcean1)).toString(4)); IO.writeAll(Iris.instance.getDataFile("packs", dimension.getLoadKey(), "generators", gen.getLoadKey() + ".json"), new JSONObject(new Gson().toJson(gen)).toString(4)); - IO.writeAll(Iris.instance.getDataFile("packs", dimension.getLoadKey(), dimension.getLoadKey() + ".code-workspace"), ws.toString(4)); + IO.writeAll(Iris.instance.getDataFile("packs", dimension.getLoadKey(), dimension.getLoadKey() + ".code-workspace"), ws.toString(0)); Iris.proj.open(sender, dimension.getName()); } @@ -535,6 +546,7 @@ public class ProjectManager private JSONObject newWorkspaceConfig() { + Iris.globaldata.clearLists(); JSONObject ws = new JSONObject(); JSONArray folders = new JSONArray(); JSONObject folder = new JSONObject(); @@ -549,7 +561,26 @@ public class ProjectManager settings.put("workbench.tree.indent", 24); settings.put("files.autoSave", "onFocusChange"); - JSONArray schemas = buildSchemas(); + JSONObject jc = new JSONObject(); + jc.put("editor.autoIndent", "brackets"); + jc.put("editor.acceptSuggestionOnEnter", "smart"); + jc.put("editor.cursorSmoothCaretAnimation", true); + jc.put("editor.dragAndDrop", false); + jc.put("files.trimTrailingWhitespace", true); + jc.put("diffEditor.ignoreTrimWhitespace", true); + jc.put("files.trimFinalNewlines", true); + jc.put("editor.suggest.showKeywords", false); + jc.put("editor.suggest.showSnippets", false); + jc.put("editor.suggest.showWords", false); + jc.put("json.maxItemsComputed", 50000); + JSONObject st = new JSONObject(); + st.put("strings", true); + jc.put("editor.quickSuggestions", st); + jc.put("editor.suggest.insertMode", "replace"); + settings.put("[json]", jc); + settings.put("json.maxItemsComputed", 50000); + + JSONArray schemas = buildSchemas(Iris.globaldata); settings.put("json.schemas", schemas); ws.put("settings", settings); @@ -565,29 +596,11 @@ public class ProjectManager { try { + Iris.info("Updating Workspace: " + ws.getPath()); J.attemptAsync(() -> writeDocs(ws.getParentFile())); - JSONObject j = new JSONObject(IO.readAll(ws)); - JSONObject s = j.getJSONObject("settings"); - JSONObject jc = new JSONObject(); - jc.put("editor.autoIndent", "brackets"); - jc.put("editor.acceptSuggestionOnEnter", "smart"); - jc.put("editor.cursorSmoothCaretAnimation", true); - jc.put("editor.dragAndDrop", false); - jc.put("files.trimTrailingWhitespace", true); - jc.put("diffEditor.ignoreTrimWhitespace", true); - jc.put("files.trimFinalNewlines", true); - jc.put("editor.suggest.showKeywords", false); - jc.put("editor.suggest.showSnippets", false); - jc.put("editor.suggest.showWords", false); - JSONObject st = new JSONObject(); - st.put("strings", true); - jc.put("editor.quickSuggestions", st); - jc.put("editor.suggest.insertMode", "replace"); - s.put("[json]", jc); - s.put("json.schemas", buildSchemas()); - j.put("settings", s); + JSONObject j = newWorkspaceConfig(); IO.writeAll(ws, j.toString(4)); - Iris.info("Updating Project " + ws.getAbsolutePath()); + Iris.info("Updated Workspace: " + ws.getPath()); } catch(Throwable e) @@ -606,30 +619,43 @@ public class ProjectManager } } - private JSONArray buildSchemas() + private void ex(JSONArray schemas, Class c, IrisDataManager dat, String v) + { + JSONObject o = getSchemaEntry(c, dat, v); + lock.lock(); + schemas.put(o); + lock.unlock(); + } + + private JSONArray buildSchemas(IrisDataManager dat) { JSONArray schemas = new JSONArray(); - schemas.put(getSchemaEntry(IrisDimension.class, "/dimensions/*.json")); - schemas.put(getSchemaEntry(IrisBiome.class, "/biomes/*.json")); - schemas.put(getSchemaEntry(IrisRegion.class, "/regions/*.json")); - schemas.put(getSchemaEntry(IrisGenerator.class, "/generators/*.json")); - schemas.put(getSchemaEntry(IrisStructure.class, "/structures/*.json")); + TaskGroup g = tx.startWork(); + g.queue(() -> ex(schemas, IrisDimension.class, dat, "/dimensions/*.json")); + g.queue(() -> ex(schemas, IrisBiome.class, dat, "/biomes/*.json")); + g.queue(() -> ex(schemas, IrisRegion.class, dat, "/regions/*.json")); + g.queue(() -> ex(schemas, IrisGenerator.class, dat, "/generators/*.json")); + g.queue(() -> ex(schemas, IrisStructure.class, dat, "/structures/*.json")); + g.execute(); + return schemas; } - public JSONObject getSchemaEntry(Class i, String... fileMatch) + public JSONObject getSchemaEntry(Class i, IrisDataManager dat, String... fileMatch) { + Iris.verbose("Processing Folder " + i.getSimpleName() + " " + fileMatch[0]); JSONObject o = new JSONObject(); o.put("fileMatch", new JSONArray(fileMatch)); - o.put("schema", getSchemaFor(i)); + o.put("schema", getSchemaFor(i, dat)); return o; } - public JSONObject getSchemaFor(Class i) + public JSONObject getSchemaFor(Class i, IrisDataManager dat) { + Iris.verbose("Processing " + i.getSimpleName()); KMap def = new KMap<>(); - JSONObject s = getSchemaFor(i, 7, def); + JSONObject s = getSchemaFor(i, 7, def, dat); JSONObject defx = new JSONObject(); for(String v : def.k()) { @@ -641,7 +667,7 @@ public class ProjectManager return s; } - public JSONObject getSchemaFor(Class i, int step, KMap def) + public JSONObject getSchemaFor(Class i, int step, KMap def, IrisDataManager dat) { if(step <= 0) { @@ -670,7 +696,6 @@ public class ProjectManager JSONObject prop = new JSONObject(); if(k.isAnnotationPresent(Desc.class)) { - if(k.isAnnotationPresent(DependsOn.class)) { deps.put(k.getName(), new JSONArray(k.getDeclaredAnnotation(DependsOn.class).value())); @@ -726,11 +751,36 @@ public class ProjectManager { prop.put("maxLength", (int) k.getDeclaredAnnotation(MaxNumber.class).value()); } - } - if(k.getType().equals(String.class)) - { - tp = "string"; + if(k.isAnnotationPresent(RegistryListBiome.class)) + { + prop.put("enum", new JSONArray(getBiomeList(dat))); + } + + if(k.isAnnotationPresent(RegistryListDimension.class)) + { + prop.put("enum", new JSONArray(getDimensionList(dat))); + } + + if(k.isAnnotationPresent(RegistryListGenerator.class)) + { + prop.put("enum", new JSONArray(getGeneratorList(dat))); + } + + if(k.isAnnotationPresent(RegistryListObject.class)) + { + prop.put("enum", new JSONArray(getObjectList(dat))); + } + + if(k.isAnnotationPresent(RegistryListRegion.class)) + { + prop.put("enum", new JSONArray(getRegionList(dat))); + } + + if(k.isAnnotationPresent(RegistryListStructure.class)) + { + prop.put("enum", new JSONArray(getStructureList(dat))); + } } if(k.getType().isEnum()) @@ -774,7 +824,7 @@ public class ProjectManager if(k.getType().isAnnotationPresent(Desc.class)) { prop.put("additionalProperties", false); - prop.put("properties", getSchemaFor(k.getType(), step - 1, def).getJSONObject("properties")); + prop.put("properties", getSchemaFor(k.getType(), step - 1, def, Iris.globaldata).getJSONObject("properties")); } } @@ -782,6 +832,11 @@ public class ProjectManager { ArrayType t = k.getDeclaredAnnotation(ArrayType.class); + if(t == null) + { + Iris.warn("Expected " + ArrayType.class.getSimpleName() + " in " + k.getName() + " in " + i.getSimpleName()); + } + if(t.min() > 0) { prop.put("minItems", t.min()); @@ -809,6 +864,136 @@ public class ProjectManager if(t.type().equals(String.class)) { tx = "string"; + + if(k.isAnnotationPresent(MinNumber.class)) + { + prop.put("minLength", (int) k.getDeclaredAnnotation(MinNumber.class).value()); + } + + if(k.isAnnotationPresent(MaxNumber.class)) + { + prop.put("maxLength", (int) k.getDeclaredAnnotation(MaxNumber.class).value()); + } + + if(k.isAnnotationPresent(RegistryListBiome.class)) + { + String name = "enbiom" + t.type().getSimpleName().toLowerCase(); + if(!def.containsKey(name)) + { + JSONObject deff = new JSONObject(); + deff.put("type", tx); + deff.put("enum", new JSONArray(getBiomeList(dat))); + def.put(name, deff); + } + + JSONObject items = new JSONObject(); + items.put("$ref", "#/definitions/" + name); + prop.put("items", items); + prop.put("description", k.getAnnotation(Desc.class).value()); + prop.put("type", tp); + properties.put(k.getName(), prop); + continue; + } + + if(k.isAnnotationPresent(RegistryListDimension.class)) + { + String name = "endim" + t.type().getSimpleName().toLowerCase(); + if(!def.containsKey(name)) + { + JSONObject deff = new JSONObject(); + deff.put("type", tx); + deff.put("enum", new JSONArray(getDimensionList(dat))); + def.put(name, deff); + } + + JSONObject items = new JSONObject(); + items.put("$ref", "#/definitions/" + name); + prop.put("items", items); + prop.put("description", k.getAnnotation(Desc.class).value()); + prop.put("type", tp); + properties.put(k.getName(), prop); + continue; + } + + if(k.isAnnotationPresent(RegistryListGenerator.class)) + { + String name = "engen" + t.type().getSimpleName().toLowerCase(); + if(!def.containsKey(name)) + { + JSONObject deff = new JSONObject(); + deff.put("type", tx); + deff.put("enum", new JSONArray(getGeneratorList(dat))); + def.put(name, deff); + } + + JSONObject items = new JSONObject(); + items.put("$ref", "#/definitions/" + name); + prop.put("items", items); + prop.put("description", k.getAnnotation(Desc.class).value()); + prop.put("type", tp); + properties.put(k.getName(), prop); + continue; + } + + if(k.isAnnotationPresent(RegistryListObject.class)) + { + String name = "enobj" + t.type().getSimpleName().toLowerCase(); + if(!def.containsKey(name)) + { + JSONObject deff = new JSONObject(); + deff.put("type", tx); + deff.put("enum", new JSONArray(getObjectList(dat))); + def.put(name, deff); + } + + JSONObject items = new JSONObject(); + items.put("$ref", "#/definitions/" + name); + prop.put("items", items); + prop.put("description", k.getAnnotation(Desc.class).value()); + prop.put("type", tp); + properties.put(k.getName(), prop); + continue; + } + + if(k.isAnnotationPresent(RegistryListRegion.class)) + { + String name = "enreg" + t.type().getSimpleName().toLowerCase(); + if(!def.containsKey(name)) + { + JSONObject deff = new JSONObject(); + deff.put("type", tx); + deff.put("enum", new JSONArray(getRegionList(dat))); + def.put(name, deff); + } + + JSONObject items = new JSONObject(); + items.put("$ref", "#/definitions/" + name); + prop.put("items", items); + prop.put("description", k.getAnnotation(Desc.class).value()); + prop.put("type", tp); + properties.put(k.getName(), prop); + continue; + } + + if(k.isAnnotationPresent(RegistryListStructure.class)) + { + String name = "enstruct" + t.type().getSimpleName().toLowerCase(); + if(!def.containsKey(name)) + { + JSONObject deff = new JSONObject(); + deff.put("type", tx); + deff.put("enum", new JSONArray(getStructureList(dat))); + def.put(name, deff); + } + + JSONObject items = new JSONObject(); + items.put("$ref", "#/definitions/" + name); + prop.put("items", items); + prop.put("description", k.getAnnotation(Desc.class).value()); + prop.put("type", tp); + properties.put(k.getName(), prop); + continue; + } } if(t.type().isEnum()) @@ -834,6 +1019,10 @@ public class ProjectManager JSONObject items = new JSONObject(); items.put("$ref", "#/definitions/" + name); prop.put("items", items); + prop.put("description", k.getAnnotation(Desc.class).value()); + prop.put("type", tp); + properties.put(k.getName(), prop); + continue; } if(t.type().isEnum()) @@ -857,7 +1046,7 @@ public class ProjectManager if(!def.containsKey(name)) { JSONObject deff = new JSONObject(); - JSONObject scv = getSchemaFor(t.type(), step - 1, def); + JSONObject scv = getSchemaFor(t.type(), step - 1, def, Iris.globaldata); deff.put("type", tx); deff.put("description", t.type().getDeclaredAnnotation(Desc.class).value()); deff.put("additionalProperties", false); @@ -888,7 +1077,7 @@ public class ProjectManager if(tp.getClass().isAnnotationPresent(Desc.class)) { - prop.put("properties", getSchemaFor(tp.getClass(), step - 1, def).getJSONObject("properties")); + prop.put("properties", getSchemaFor(tp.getClass(), step - 1, def, Iris.globaldata).getJSONObject("properties")); } } @@ -907,6 +1096,36 @@ public class ProjectManager return schema; } + private String[] getBiomeList(IrisDataManager data) + { + return data.getBiomeLoader().getPossibleKeys(); + } + + private String[] getDimensionList(IrisDataManager data) + { + return data.getDimensionLoader().getPossibleKeys(); + } + + private String[] getRegionList(IrisDataManager data) + { + return data.getRegionLoader().getPossibleKeys(); + } + + private String[] getObjectList(IrisDataManager data) + { + return data.getObjectLoader().getPossibleKeys(); + } + + private String[] getStructureList(IrisDataManager data) + { + return data.getStructureLoader().getPossibleKeys(); + } + + private String[] getGeneratorList(IrisDataManager data) + { + return data.getGeneratorLoader().getPossibleKeys(); + } + public KList analyzeFolder(File folder, String fn, Object t) { KList a = new KList(); @@ -941,6 +1160,7 @@ public class ProjectManager try { + Iris.info("Reading " + i.getPath()); j = new JSONObject(IO.readAll(i)); o = new Gson().fromJson(j.toString(), t.getClass()); a.addAll(analyze(o, i)); diff --git a/src/main/java/com/volmit/iris/gen/IrisChunkGenerator.java b/src/main/java/com/volmit/iris/gen/IrisChunkGenerator.java index 508391060..bd4bdd594 100644 --- a/src/main/java/com/volmit/iris/gen/IrisChunkGenerator.java +++ b/src/main/java/com/volmit/iris/gen/IrisChunkGenerator.java @@ -1,6 +1,7 @@ package com.volmit.iris.gen; import java.awt.Color; +import java.io.File; import java.io.IOException; import java.lang.reflect.Method; @@ -12,6 +13,7 @@ import org.bukkit.entity.Player; import com.volmit.iris.Iris; import com.volmit.iris.IrisContext; +import com.volmit.iris.IrisSettings; import com.volmit.iris.gen.atomics.AtomicRegionData; import com.volmit.iris.noise.CNG; import com.volmit.iris.object.IrisBiome; @@ -189,18 +191,29 @@ public class IrisChunkGenerator extends CeilingChunkGenerator implements IrisCon @Override public void onHotloaded() { + if(!IrisSettings.get().hotloading) + { + return; + } + if(!isHotloadable()) { - Iris.warn("Hotload skipped (During Chunk Gen). Retrying."); Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, this::onHotloaded); return; } - + CNG.creates = 0; getData().dump(); + getCache().drop(); + Iris.proj.updateWorkspace(getWorkspaceFile()); onHotload(); } + private File getWorkspaceFile() + { + return new File(getDimension().getLoadFile().getParent(), getDimension().getLoadKey() + ".code-workspace"); + } + public long guessMemoryUsage() { long bytes = 1024 * 1024 * (8 + (getThreads() / 3)); @@ -215,6 +228,7 @@ public class IrisChunkGenerator extends CeilingChunkGenerator implements IrisCon bytes += i.guessMemoryUsage(); } + bytes += getCache().getSize() * 65; bytes += parallaxMap.getLoadedChunks().size() * 256 * 4 * 460; bytes += ceilingParallaxMap.getLoadedChunks().size() * 256 * 4 * 460; bytes += getSliverBuffer() * 220; diff --git a/src/main/java/com/volmit/iris/gen/ParallaxChunkGenerator.java b/src/main/java/com/volmit/iris/gen/ParallaxChunkGenerator.java index 0bcb202f8..23f5e6bbd 100644 --- a/src/main/java/com/volmit/iris/gen/ParallaxChunkGenerator.java +++ b/src/main/java/com/volmit/iris/gen/ParallaxChunkGenerator.java @@ -33,7 +33,8 @@ import lombok.EqualsAndHashCode; @Data @EqualsAndHashCode(callSuper = false) -public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator implements IObjectPlacer { +public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator implements IObjectPlacer +{ protected KMap sliverCache; protected AtomicWorldData parallaxMap; protected KMap ceilingSliverCache; @@ -43,7 +44,8 @@ public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator imple private IrisLock lockq = new IrisLock("ParallaxQueueLock"); private int sliverBuffer; - public ParallaxChunkGenerator(String dimensionName, int threads) { + public ParallaxChunkGenerator(String dimensionName, int threads) + { super(dimensionName, threads); sliverCache = new KMap<>(); ceilingSliverCache = new KMap<>(); @@ -51,41 +53,49 @@ public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator imple masterLock = new MasterLock(); } - public void onInit(World world, RNG rng) { + public void onInit(World world, RNG rng) + { super.onInit(world, rng); parallaxMap = new AtomicWorldData(world, "floor"); ceilingParallaxMap = new AtomicWorldData(world, "ceiling"); } - protected KMap getSliverCache() { + protected KMap getSliverCache() + { return getDimension().isInverted() ? ceilingSliverCache : sliverCache; } - protected void onClose() { + protected void onClose() + { super.onClose(); - try { + try + { parallaxMap.unloadAll(true); ceilingParallaxMap.unloadAll(true); } - catch (IOException e) { + catch(IOException e) + { e.printStackTrace(); } } @Override - public int getHighest(int x, int z) { + public int getHighest(int x, int z) + { return getHighest(x, z, false); } @Override - public int getHighest(int x, int z, boolean ignoreFluid) { - int h = (int) Math - .round(ignoreFluid ? getTerrainHeight(x, z) : getTerrainWaterHeight(x, z)); + public int getHighest(int x, int z, boolean ignoreFluid) + { + int h = (int) Math.round(ignoreFluid ? getTerrainHeight(x, z) : getTerrainWaterHeight(x, z)); - if (getDimension().isCarving() && h >= getDimension().getCarvingMin()) { - while (getGlCarve().isCarved(x, h, z)) { + if(getDimension().isCarving() && h >= getDimension().getCarvingMin()) + { + while(getGlCarve().isCarved(x, h, z)) + { h--; } @@ -96,24 +106,28 @@ public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator imple } @Override - public void set(int x, int y, int z, BlockData d) { + public void set(int x, int y, int z, BlockData d) + { getMasterLock().lock((x >> 4) + "." + (z >> 4)); getParallaxSliver(x, z).set(y, d); getMasterLock().unlock((x >> 4) + "." + (z >> 4)); } @Override - public BlockData get(int x, int y, int z) { + public BlockData get(int x, int y, int z) + { BlockData b = sampleSliver(x, z).getBlock().get(y); return b == null ? AIR : b; } @Override - public boolean isSolid(int x, int y, int z) { + public boolean isSolid(int x, int y, int z) + { return get(x, y, z).getMaterial().isSolid(); } - public AtomicSliver getParallaxSliver(int wx, int wz) { + public AtomicSliver getParallaxSliver(int wx, int wz) + { getMasterLock().lock("gpc"); getMasterLock().lock((wx >> 4) + "." + (wz >> 4)); AtomicSliverMap map = getParallaxChunk(wx >> 4, wz >> 4); @@ -124,24 +138,30 @@ public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator imple return sliver; } - public boolean isParallaxGenerated(int x, int z) { + public boolean isParallaxGenerated(int x, int z) + { return getParallaxChunk(x, z).isParallaxGenerated(); } - public boolean isWorldGenerated(int x, int z) { + public boolean isWorldGenerated(int x, int z) + { return getParallaxChunk(x, z).isWorldGenerated(); } - public AtomicWorldData getParallaxMap() { + public AtomicWorldData getParallaxMap() + { return getDimension().isInverted() ? ceilingParallaxMap : parallaxMap; } - public AtomicSliverMap getParallaxChunk(int x, int z) { - try { + public AtomicSliverMap getParallaxChunk(int x, int z) + { + try + { return getParallaxMap().loadChunk(x, z); } - catch (IOException e) { + catch(IOException e) + { fail(e); } @@ -149,16 +169,18 @@ public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator imple } @Override - protected void onPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, - BiomeMap biomeMap) { - if (getSliverCache().size() > 20000) { + protected void onPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, BiomeMap biomeMap) + { + if(getSliverCache().size() > 20000) + { getSliverCache().clear(); } super.onPostGenerate(random, x, z, data, grid, height, biomeMap); PrecisionStopwatch p = PrecisionStopwatch.start(); - if (getDimension().isPlaceObjects()) { + if(getDimension().isPlaceObjects()) + { onGenerateParallax(random, x, z); getParallaxChunk(x, z).inject(data); setSliverBuffer(getSliverCache().size()); @@ -173,50 +195,58 @@ public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator imple getData().getObjectLoader().clean(); } - public IrisStructureResult getStructure(int x, int y, int z) { + public IrisStructureResult getStructure(int x, int y, int z) + { IrisBiome b = sampleTrueBiome(x, z).getBiome(); IrisRegion r = sampleRegion(x, z); RNG ro = getMasterRandom().nextParallelRNG(496888 + (x >> 4) + (z >> 4)); int h = (int) Math.round(getTerrainHeight(x, z)); KList p = new KList<>(); - for (IrisStructurePlacement i : r.getStructures()) { - if (i.getHeight() > -1) { - if (y >= i.getHeight() && y <= i.getHeight() - + (i.getStructure(this).getGridHeight() * i.getStructure(this).getMaxLayers())) { + for(IrisStructurePlacement i : r.getStructures()) + { + if(i.getHeight() > -1) + { + if(y >= i.getHeight() && y <= i.getHeight() + (i.getStructure(this).getGridHeight() * i.getStructure(this).getMaxLayers())) + { p.add(i); } } - else if (y >= h && y <= i.getStructure(this).getGridHeight() + h) { + else if(y >= h && y <= i.getStructure(this).getGridHeight() + h) + { p.add(i); } } - for (IrisStructurePlacement i : b.getStructures()) { - if (i.getHeight() > -1) { - if (y >= i.getHeight() && y <= i.getHeight() - + (i.getStructure(this).getGridHeight() * i.getStructure(this).getMaxLayers())) { + for(IrisStructurePlacement i : b.getStructures()) + { + if(i.getHeight() > -1) + { + if(y >= i.getHeight() && y <= i.getHeight() + (i.getStructure(this).getGridHeight() * i.getStructure(this).getMaxLayers())) + { p.add(i); } } - else if (y >= h && y <= i.getStructure(this).getGridHeight() + h) { + else if(y >= h && y <= i.getStructure(this).getGridHeight() + h) + { p.add(i); } } - for (IrisStructurePlacement i : p) { - if (!i.hasStructure(ro, x, y, z)) { + for(IrisStructurePlacement i : p) + { + if(!i.hasStructure(ro, x, y, z)) + { continue; } - int hv = (i.getHeight() == -1 ? 0 : i.getHeight()) - + (Math.floorDiv(y, i.getStructure(this).getGridHeight()) * i.getStructure(this).getGridHeight()); - TileResult tile = i.getStructure(this).getTile(ro, Math.floorDiv(i.gridSize(this), x) * i.gridSize(this), - hv, Math.floorDiv(i.gridSize(this), z) * i.gridSize(this)); + int hv = (i.getHeight() == -1 ? 0 : i.getHeight()) + (Math.floorDiv(y, i.getStructure(this).getGridHeight()) * i.getStructure(this).getGridHeight()); + TileResult tile = i.getStructure(this).getTile(ro, Math.floorDiv(i.gridSize(this), x) * i.gridSize(this), hv, Math.floorDiv(i.gridSize(this), z) * i.gridSize(this)); - if (tile != null && tile.getTile() != null) { + if(tile != null && tile.getTile() != null) + { return new IrisStructureResult(tile.getTile(), i.getStructure(this)); } } @@ -224,52 +254,58 @@ public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator imple return null; } - protected void onGenerateParallax(RNG random, int x, int z) { + protected void onGenerateParallax(RNG random, int x, int z) + { String key = "par." + x + "." + "z"; ChunkPosition rad = getDimension().getParallaxSize(this); KList q = new KList<>(); - for (int ii = x - (rad.getX() / 2); ii <= x + (rad.getX() / 2); ii++) { + for(int ii = x - (rad.getX() / 2); ii <= x + (rad.getX() / 2); ii++) + { int i = ii; - for (int jj = z - (rad.getZ() / 2); jj <= z + (rad.getZ() / 2); jj++) { + for(int jj = z - (rad.getZ() / 2); jj <= z + (rad.getZ() / 2); jj++) + { int j = jj; - if (isParallaxGenerated(ii, jj)) { + if(isParallaxGenerated(ii, jj)) + { continue; } - if (isWorldGenerated(ii, jj)) { + if(isWorldGenerated(ii, jj)) + { continue; } - getAccelerant().queue(key, () -> { + getAccelerant().queue(key, () -> + { IrisBiome b = sampleTrueBiome((i * 16) + 7, (j * 16) + 7).getBiome(); RNG ro = getMasterRandom().nextParallelRNG(496888 + i + j); int g = 1; - searching: for (IrisBiomeMutation k : getDimension().getMutations()) { - for (int l = 0; l < k.getChecks(); l++) { - IrisBiome sa = sampleTrueBiome( - ((i * 16) + ro.nextInt(16)) + ro.i(-k.getRadius(), k.getRadius()), - ((j * 16) + ro.nextInt(16)) + ro.i(-k.getRadius(), k.getRadius())).getBiome(); - IrisBiome sb = sampleTrueBiome( - ((i * 16) + ro.nextInt(16)) + ro.i(-k.getRadius(), k.getRadius()), - ((j * 16) + ro.nextInt(16)) + ro.i(-k.getRadius(), k.getRadius())).getBiome(); + searching: for(IrisBiomeMutation k : getDimension().getMutations()) + { + for(int l = 0; l < k.getChecks(); l++) + { + IrisBiome sa = sampleTrueBiome(((i * 16) + ro.nextInt(16)) + ro.i(-k.getRadius(), k.getRadius()), ((j * 16) + ro.nextInt(16)) + ro.i(-k.getRadius(), k.getRadius())).getBiome(); + IrisBiome sb = sampleTrueBiome(((i * 16) + ro.nextInt(16)) + ro.i(-k.getRadius(), k.getRadius()), ((j * 16) + ro.nextInt(16)) + ro.i(-k.getRadius(), k.getRadius())).getBiome(); - if (sa.getLoadKey().equals(sb.getLoadKey())) { + if(sa.getLoadKey().equals(sb.getLoadKey())) + { continue; } - if (k.getRealSideA(this).contains(sa.getLoadKey()) - && k.getRealSideB(this).contains(sb.getLoadKey())) { - for (IrisObjectPlacement m : k.getObjects()) { + if(k.getRealSideA(this).contains(sa.getLoadKey()) && k.getRealSideB(this).contains(sb.getLoadKey())) + { + for(IrisObjectPlacement m : k.getObjects()) + { int gg = g++; lockq.lock(); - q.add(() -> { - placeObject(m, i, j, random.nextParallelRNG( - (34 * ((i * 30) + (j * 30) + gg) * i * j) + i - j + 1569962)); + q.add(() -> + { + placeObject(m, i, j, random.nextParallelRNG((34 * ((i * 30) + (j * 30) + gg) * i * j) + i - j + 1569962)); }); lockq.unlock(); } @@ -281,52 +317,61 @@ public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator imple IrisRegion r = sampleRegion((i * 16) + 7, (j * 16) + 7); - for (IrisStructurePlacement k : r.getStructures()) { + for(IrisStructurePlacement k : r.getStructures()) + { lockq.lock(); - q.add(() -> { + q.add(() -> + { k.place(this, random.nextParallelRNG(2228), i, j); }); lockq.unlock(); } - for (IrisStructurePlacement k : b.getStructures()) { + for(IrisStructurePlacement k : b.getStructures()) + { lockq.lock(); - q.add(() -> { + q.add(() -> + { k.place(this, random.nextParallelRNG(-22228), i, j); }); lockq.unlock(); } - for (IrisObjectPlacement k : b.getObjects()) { + for(IrisObjectPlacement k : b.getObjects()) + { int gg = g++; lockq.lock(); - q.add(() -> { - placeObject(k, i, j, random - .nextParallelRNG((34 * ((i * 30) + (j * 30) + gg) * i * j) + i - j + 3569222)); + q.add(() -> + { + placeObject(k, i, j, random.nextParallelRNG((34 * ((i * 30) + (j * 30) + gg) * i * j) + i - j + 3569222)); }); lockq.unlock(); } - if (getDimension().isCaves()) { + if(getDimension().isCaves()) + { int bx = (i * 16) + ro.nextInt(16); int bz = (j * 16) + ro.nextInt(16); IrisBiome biome = sampleCaveBiome(bx, bz).getBiome(); - if (biome == null) { + if(biome == null) + { return; } - if (biome.getObjects().isEmpty()) { + if(biome.getObjects().isEmpty()) + { return; } - for (IrisObjectPlacement k : biome.getObjects()) { + for(IrisObjectPlacement k : biome.getObjects()) + { int gg = g++; lockq.lock(); - q.add(() -> { - placeCaveObject(k, i, j, random - .nextParallelRNG((34 * ((i * 30) + (j * 30) + gg) * i * j) + i - j + 1869322)); + q.add(() -> + { + placeCaveObject(k, i, j, random.nextParallelRNG((34 * ((i * 30) + (j * 30) + gg) * i * j) + i - j + 1869322)); }); lockq.unlock(); } @@ -340,7 +385,8 @@ public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator imple getAccelerant().waitFor(key); lockq.lock(); - for (NastyRunnable i : q) { + for(NastyRunnable i : q) + { getAccelerant().queue(key + "-obj", i); } lockq.unlock(); @@ -348,34 +394,39 @@ public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator imple getAccelerant().waitFor(key + "-obj"); } - public void placeObject(IrisObjectPlacement o, int x, int z, RNG rng) { - for (int i = 0; i < o.getTriesForChunk(rng); i++) { + public void placeObject(IrisObjectPlacement o, int x, int z, RNG rng) + { + for(int i = 0; i < o.getTriesForChunk(rng); i++) + { rng = rng.nextParallelRNG((i * 3 + 8) - 23040); o.getSchematic(this, rng).place((x * 16) + rng.nextInt(16), (z * 16) + rng.nextInt(16), this, o, rng); } } - public void placeCaveObject(IrisObjectPlacement o, int x, int z, RNG rng) { - for (int i = 0; i < o.getTriesForChunk(rng); i++) { + public void placeCaveObject(IrisObjectPlacement o, int x, int z, RNG rng) + { + for(int i = 0; i < o.getTriesForChunk(rng); i++) + { rng = rng.nextParallelRNG((i * 3 + 8) - 23040); int xx = (x * 16) + rng.nextInt(16); int zz = (z * 16) + rng.nextInt(16); KList res = getCaves(xx, zz); - if (res.isEmpty()) { + if(res.isEmpty()) + { continue; } - o.getSchematic(this, rng).place(xx, - res.get(rng.nextParallelRNG(29345 * (i + 234)).nextInt(res.size())).getFloor() + 2, zz, this, o, - rng); + o.getSchematic(this, rng).place(xx, res.get(rng.nextParallelRNG(29345 * (i + 234)).nextInt(res.size())).getFloor() + 2, zz, this, o, rng); } } - public AtomicSliver sampleSliver(int x, int z) { + public AtomicSliver sampleSliver(int x, int z) + { ChunkPosition key = new ChunkPosition(x, z); - if (getSliverCache().containsKey(key)) { + if(getSliverCache().containsKey(key)) + { return getSliverCache().get(key); } @@ -387,7 +438,8 @@ public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator imple } @Override - public boolean isPreventingDecay() { + public boolean isPreventingDecay() + { return getDimension().isPreventLeafDecay(); } } diff --git a/src/main/java/com/volmit/iris/gen/ParallelChunkGenerator.java b/src/main/java/com/volmit/iris/gen/ParallelChunkGenerator.java index b0243c586..2cfad7565 100644 --- a/src/main/java/com/volmit/iris/gen/ParallelChunkGenerator.java +++ b/src/main/java/com/volmit/iris/gen/ParallelChunkGenerator.java @@ -17,7 +17,8 @@ import lombok.EqualsAndHashCode; @Data @EqualsAndHashCode(callSuper = false) -public abstract class ParallelChunkGenerator extends BiomeChunkGenerator { +public abstract class ParallelChunkGenerator extends BiomeChunkGenerator +{ private GroupedExecutor accelerant; private int threads; protected int cacheX; @@ -25,7 +26,8 @@ public abstract class ParallelChunkGenerator extends BiomeChunkGenerator { private IrisLock genlock; protected boolean cachingAllowed; - public ParallelChunkGenerator(String dimensionName, int threads) { + public ParallelChunkGenerator(String dimensionName, int threads) + { super(dimensionName); cacheX = 0; cacheZ = 0; @@ -34,35 +36,37 @@ public abstract class ParallelChunkGenerator extends BiomeChunkGenerator { cachingAllowed = false; } - public void changeThreadCount(int tc) { + public void changeThreadCount(int tc) + { threads = tc; GroupedExecutor e = accelerant; accelerant = new GroupedExecutor(threads, Thread.NORM_PRIORITY, "Iris Generator - " + world.getName()); Iris.executors.add(accelerant); - if (e != null) { + if(e != null) + { e.close(); } } - protected abstract void onGenerateColumn(int cx, int cz, int wx, int wz, int x, int z, AtomicSliver sliver, - BiomeMap biomeMap, boolean sampled); + protected abstract void onGenerateColumn(int cx, int cz, int wx, int wz, int x, int z, AtomicSliver sliver, BiomeMap biomeMap, boolean sampled); - protected void onGenerateColumn(int cx, int cz, int wx, int wz, int x, int z, AtomicSliver sliver, - BiomeMap biomeMap) { + protected void onGenerateColumn(int cx, int cz, int wx, int wz, int x, int z, AtomicSliver sliver, BiomeMap biomeMap) + { onGenerateColumn(cx, cz, wx, wz, x, z, sliver, biomeMap, false); } protected abstract int onSampleColumnHeight(int cx, int cz, int wx, int wz, int x, int z); - protected abstract void onPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, - BiomeMap biomeMap); + protected abstract void onPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, BiomeMap biomeMap); - protected int sampleHeight(int x, int z) { + protected int sampleHeight(int x, int z) + { return onSampleColumnHeight(x >> 4, z >> 4, x, z, x & 15, z & 15); } - protected void onGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid) { + protected void onGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid) + { genlock.lock(); cacheX = x; cacheZ = z; @@ -74,16 +78,19 @@ public abstract class ParallelChunkGenerator extends BiomeChunkGenerator { BiomeMap biomeMap = new BiomeMap(); int ii, jj; - for (ii = 0; ii < 16; ii++) { + for(ii = 0; ii < 16; ii++) + { int i = ii; int wx = (x * 16) + i; - for (jj = 0; jj < 16; jj++) { + for(jj = 0; jj < 16; jj++) + { int j = jj; int wz = (z * 16) + j; AtomicSliver sliver = map.getSliver(i, j); - accelerant.queue(key, () -> { + accelerant.queue(key, () -> + { onGenerateColumn(x, z, wx, wz, i, j, sliver, biomeMap); }); } @@ -97,18 +104,21 @@ public abstract class ParallelChunkGenerator extends BiomeChunkGenerator { genlock.unlock(); } - protected void onClose() { + protected void onClose() + { accelerant.close(); Iris.executors.remove(accelerant); } - public void onInit(World world, RNG rng) { + public void onInit(World world, RNG rng) + { super.onInit(world, rng); changeThreadCount(threads); } @Override - public boolean isParallelCapable() { + public boolean isParallelCapable() + { return false; } } diff --git a/src/main/java/com/volmit/iris/gen/TerrainChunkGenerator.java b/src/main/java/com/volmit/iris/gen/TerrainChunkGenerator.java index 70141c54d..605e6f73c 100644 --- a/src/main/java/com/volmit/iris/gen/TerrainChunkGenerator.java +++ b/src/main/java/com/volmit/iris/gen/TerrainChunkGenerator.java @@ -2,6 +2,7 @@ package com.volmit.iris.gen; import org.bukkit.Material; import org.bukkit.World; +import org.bukkit.block.Biome; import org.bukkit.block.data.Bisected; import org.bukkit.block.data.Bisected.Half; import org.bukkit.block.data.BlockData; @@ -29,36 +30,42 @@ import lombok.EqualsAndHashCode; @Data @EqualsAndHashCode(callSuper = false) -public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { +public abstract class TerrainChunkGenerator extends ParallelChunkGenerator +{ private long lastUpdateRequest = M.ms(); private long lastChunkLoad = M.ms(); private GenLayerCave glCave; private GenLayerCarve glCarve; private RNG rockRandom; - public TerrainChunkGenerator(String dimensionName, int threads) { + public TerrainChunkGenerator(String dimensionName, int threads) + { super(dimensionName, threads); } - public void onInit(World world, RNG rng) { + public void onInit(World world, RNG rng) + { super.onInit(world, rng); rockRandom = getMasterRandom().nextParallelRNG(2858678); glCave = new GenLayerCave(this, rng.nextParallelRNG(238948)); glCarve = new GenLayerCarve(this, rng.nextParallelRNG(968346576)); } - public KList getCaves(int x, int z) { + public KList getCaves(int x, int z) + { return glCave.genCaves(x, z, x & 15, z & 15, null); } @Override - protected void onGenerateColumn(int cx, int cz, int rx, int rz, int x, int z, AtomicSliver sliver, - BiomeMap biomeMap, boolean sampled) { - if (x > 15 || x < 0 || z > 15 || z < 0) { + protected void onGenerateColumn(int cx, int cz, int rx, int rz, int x, int z, AtomicSliver sliver, BiomeMap biomeMap, boolean sampled) + { + if(x > 15 || x < 0 || z > 15 || z < 0) + { throw new RuntimeException("Invalid OnGenerate call: x:" + x + " z:" + z); } - try { + try + { int highestPlaced = 0; BlockData block; @@ -75,27 +82,29 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { BiomeResult biomeResult = sampleTrueBiome(rx, rz, noise); IrisBiome biome = biomeResult.getBiome(); - if (biome == null) { + if(biome == null) + { throw new RuntimeException("Null Biome!"); } KList layers = biome.generateLayers(rx, rz, masterRandom, height, height - getFluidHeight()); - KList seaLayers = biome.isSea() - ? biome.generateSeaLayers(rx, rz, masterRandom, fluidHeight - height) - : new KList<>(); + KList seaLayers = biome.isSea() ? biome.generateSeaLayers(rx, rz, masterRandom, fluidHeight - height) : new KList<>(); boolean caverning = false; KList cavernHeights = new KList<>(); int lastCavernHeight = -1; + boolean bxx = false; // From Height to Bedrock - for (int k = Math.max(height, fluidHeight); k >= 0; k--) { + for(int k = Math.max(height, fluidHeight); k >= 0; k--) + { boolean cavernSurface = false; // Bedrock - if (k == 0) { - if (biomeMap != null) { + if(k == 0) + { + if(biomeMap != null) + { sliver.set(k, biome.getDerivative()); - biomeMap.setBiome(x, z, biome); } sliver.set(k, BEDROCK); @@ -103,10 +112,11 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { } // Carving - if (carvable && glCarve.isCarved(rx, k, rz)) { - if (biomeMap != null) { + if(carvable && glCarve.isCarved(rx, k, rz)) + { + if(biomeMap != null) + { sliver.set(k, biome.getDerivative()); - biomeMap.setBiome(x, z, biome); } sliver.set(k, CAVE_AIR); @@ -114,7 +124,8 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { continue; } - else if (carvable && caverning) { + else if(carvable && caverning) + { lastCavernHeight = k; cavernSurface = true; cavernHeights.add(k); @@ -124,24 +135,35 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { boolean underwater = k > height && k <= fluidHeight; // Set Biome - if (biomeMap != null) { + if(!bxx && biomeMap != null) + { + bxx = true; sliver.set(k, biome.getGroundBiome(masterRandom, rz, k, rx)); biomeMap.setBiome(x, z, biome); + + for(int kv = Math.max(height, fluidHeight); kv < Math.min(Math.max(height, fluidHeight) + 16, 255); kv++) + { + Biome skyBiome = biome.getSkyBiome(masterRandom, rz, kv, rx); + sliver.set(kv, biome.getDerivative()); + sliver.set(k, skyBiome); + } } // Set Sea Material (water/lava) - if (underwater) { - block = seaLayers.hasIndex(fluidHeight - k) ? layers.get(depth) - : getDimension().getFluid(rockRandom, wx, k, wz); + if(underwater) + { + block = seaLayers.hasIndex(fluidHeight - k) ? layers.get(depth) : getDimension().getFluid(rockRandom, wx, k, wz); } // Set Surface Material for cavern layer surfaces - else if (layers.hasIndex(lastCavernHeight - k)) { + else if(layers.hasIndex(lastCavernHeight - k)) + { block = layers.get(lastCavernHeight - k); } // Set Surface Material for true surface - else { + else + { block = layers.hasIndex(depth) ? layers.get(depth) : getDimension().getRock(rockRandom, wx, k, wz); depth++; } @@ -151,13 +173,14 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { highestPlaced = Math.max(highestPlaced, k); // Decorate underwater surface - if (!cavernSurface && (k == height && block.getMaterial().isSolid() && k < fluidHeight)) { + if(!cavernSurface && (k == height && B.isSolid(block.getMaterial()) && k < fluidHeight)) + { decorateUnderwater(biome, sliver, wx, k, wz, rx, rz, block); } // Decorate Cavern surfaces, but not the true surface - if ((carvable && cavernSurface) && !(k == Math.max(height, fluidHeight) && block.getMaterial().isSolid() - && k < 255 && k >= fluidHeight)) { + if((carvable && cavernSurface) && !(k == Math.max(height, fluidHeight) && block.getMaterial().isSolid() && k < 255 && k >= fluidHeight)) + { decorateLand(biome, sliver, wx, k, wz, rx, rz, block); } } @@ -167,31 +190,36 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { IrisBiome caveBiome = glBiome.generateData(InferredType.CAVE, wx, wz, rx, rz, region).getBiome(); // Decorate Cave Biome Height Sections - if (caveBiome != null) { - for (CaveResult i : caveResults) { - for (int j = i.getFloor(); j <= i.getCeiling(); j++) { + if(caveBiome != null) + { + for(CaveResult i : caveResults) + { + for(int j = i.getFloor(); j <= i.getCeiling(); j++) + { sliver.set(j, caveBiome); sliver.set(j, caveBiome.getGroundBiome(masterRandom, rz, j, rx)); } - KList floor = caveBiome.generateLayers(wx, wz, rockRandom, i.getFloor() - 2, - i.getFloor() - 2); - KList ceiling = caveBiome.generateLayers(wx + 256, wz + 256, rockRandom, - height - i.getCeiling() - 2, height - i.getCeiling() - 2); + KList floor = caveBiome.generateLayers(wx, wz, rockRandom, i.getFloor() - 2, i.getFloor() - 2); + KList ceiling = caveBiome.generateLayers(wx + 256, wz + 256, rockRandom, height - i.getCeiling() - 2, height - i.getCeiling() - 2); BlockData blockc = null; - for (int j = 0; j < floor.size(); j++) { - if (j == 0) { + for(int j = 0; j < floor.size(); j++) + { + if(j == 0) + { blockc = floor.get(j); } sliver.set(i.getFloor() - j, floor.get(j)); } - for (int j = ceiling.size() - 1; j > 0; j--) { + for(int j = ceiling.size() - 1; j > 0; j--) + { sliver.set(i.getCeiling() + j, ceiling.get(j)); } - if (blockc != null && !sliver.isSolid(i.getFloor() + 1)) { + if(blockc != null && !sliver.isSolid(i.getFloor() + 1)) + { decorateCave(caveBiome, sliver, wx, i.getFloor(), wz, rx, rz, blockc); } } @@ -200,76 +228,91 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { block = sliver.get(Math.max(height, fluidHeight)); // Decorate True Surface - if (block.getMaterial().isSolid()) { + if(block.getMaterial().isSolid()) + { decorateLand(biome, sliver, wx, Math.max(height, fluidHeight), wz, rx, rz, block); } } - catch (Throwable e) { + catch(Throwable e) + { fail(e); } } @Override - protected void onGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid) { + protected void onGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid) + { super.onGenerate(random, x, z, data, grid); RNG ro = random.nextParallelRNG((x * x * x) - z); IrisRegion region = sampleRegion((x * 16) + 7, (z * 16) + 7); IrisBiome biome = sampleTrueBiome((x * 16) + 7, (z * 16) + 7).getBiome(); - for (IrisDepositGenerator k : getDimension().getDeposits()) { + for(IrisDepositGenerator k : getDimension().getDeposits()) + { k.generate(data, ro, this); } - for (IrisDepositGenerator k : region.getDeposits()) { - for (int l = 0; l < ro.i(k.getMinPerChunk(), k.getMaxPerChunk()); l++) { + for(IrisDepositGenerator k : region.getDeposits()) + { + for(int l = 0; l < ro.i(k.getMinPerChunk(), k.getMaxPerChunk()); l++) + { k.generate(data, ro, this); } } - for (IrisDepositGenerator k : biome.getDeposits()) { - for (int l = 0; l < ro.i(k.getMinPerChunk(), k.getMaxPerChunk()); l++) { + for(IrisDepositGenerator k : biome.getDeposits()) + { + for(int l = 0; l < ro.i(k.getMinPerChunk(), k.getMaxPerChunk()); l++) + { k.generate(data, ro, this); } } } - private void decorateLand(IrisBiome biome, AtomicSliver sliver, double wx, int k, double wz, int rx, int rz, - BlockData block) { - if (!getDimension().isDecorate()) { + private void decorateLand(IrisBiome biome, AtomicSliver sliver, double wx, int k, double wz, int rx, int rz, BlockData block) + { + if(!getDimension().isDecorate()) + { return; } int j = 0; - for (IrisBiomeDecorator i : biome.getDecorators()) { - if (i.getPartOf().equals(DecorationPart.SHORE_LINE) && (!touchesSea(rx, rz) || k != getFluidHeight())) { + for(IrisBiomeDecorator i : biome.getDecorators()) + { + if(i.getPartOf().equals(DecorationPart.SHORE_LINE) && (!touchesSea(rx, rz) || k != getFluidHeight())) + { continue; } - BlockData d = i.getBlockData(getMasterRandom() - .nextParallelRNG((int) (38888 + biome.getRarity() + biome.getName().length() + j++)), rx, rz); + BlockData d = i.getBlockData(getMasterRandom().nextParallelRNG((int) (38888 + biome.getRarity() + biome.getName().length() + j++)), rx, rz); - if (d != null) { - if (!B.canPlaceOnto(d.getMaterial(), block.getMaterial())) { + if(d != null) + { + if(!B.canPlaceOnto(d.getMaterial(), block.getMaterial())) + { continue; } - if (d.getMaterial().equals(Material.CACTUS)) { - if (!block.getMaterial().equals(Material.SAND) && !block.getMaterial().equals(Material.RED_SAND)) { + if(d.getMaterial().equals(Material.CACTUS)) + { + if(!block.getMaterial().equals(Material.SAND) && !block.getMaterial().equals(Material.RED_SAND)) + { sliver.set(k, B.getBlockData("RED_SAND")); } } - if (d.getMaterial().equals(Material.WHEAT) || d.getMaterial().equals(Material.CARROTS) - || d.getMaterial().equals(Material.POTATOES) || d.getMaterial().equals(Material.MELON_STEM) - || d.getMaterial().equals(Material.PUMPKIN_STEM)) { - if (!block.getMaterial().equals(Material.FARMLAND)) { + if(d.getMaterial().equals(Material.WHEAT) || d.getMaterial().equals(Material.CARROTS) || d.getMaterial().equals(Material.POTATOES) || d.getMaterial().equals(Material.MELON_STEM) || d.getMaterial().equals(Material.PUMPKIN_STEM)) + { + if(!block.getMaterial().equals(Material.FARMLAND)) + { sliver.set(k, B.getBlockData("FARMLAND")); } } - if (d instanceof Bisected && k < 254) { + if(d instanceof Bisected && k < 254) + { Bisected t = ((Bisected) d.clone()); t.setHalf(Half.TOP); Bisected b = ((Bisected) d.clone()); @@ -278,17 +321,19 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { sliver.set(k + 2, t); } - else { - int stack = i.getHeight(getMasterRandom().nextParallelRNG( - (int) (39456 + (10000 * i.getChance()) + i.getStackMax() + i.getStackMin() + i.getZoom())), - rx, rz); + else + { + int stack = i.getHeight(getMasterRandom().nextParallelRNG((int) (39456 + (10000 * i.getChance()) + i.getStackMax() + i.getStackMin() + i.getZoom())), rx, rz); - if (stack == 1) { + if(stack == 1) + { sliver.set(k + 1, d); } - else if (k < 255 - stack) { - for (int l = 0; l < stack; l++) { + else if(k < 255 - stack) + { + for(int l = 0; l < stack; l++) + { sliver.set(k + l + 1, d); } } @@ -299,31 +344,36 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { } } - private void decorateCave(IrisBiome biome, AtomicSliver sliver, double wx, int k, double wz, int rx, int rz, - BlockData block) { - if (!getDimension().isDecorate()) { + private void decorateCave(IrisBiome biome, AtomicSliver sliver, double wx, int k, double wz, int rx, int rz, BlockData block) + { + if(!getDimension().isDecorate()) + { return; } int j = 0; - for (IrisBiomeDecorator i : biome.getDecorators()) { - BlockData d = i.getBlockData( - getMasterRandom().nextParallelRNG(2333877 + biome.getRarity() + biome.getName().length() + +j++), - rx, rz); + for(IrisBiomeDecorator i : biome.getDecorators()) + { + BlockData d = i.getBlockData(getMasterRandom().nextParallelRNG(2333877 + biome.getRarity() + biome.getName().length() + +j++), rx, rz); - if (d != null) { - if (!B.canPlaceOnto(d.getMaterial(), block.getMaterial())) { + if(d != null) + { + if(!B.canPlaceOnto(d.getMaterial(), block.getMaterial())) + { continue; } - if (d.getMaterial().equals(Material.CACTUS)) { - if (!block.getMaterial().equals(Material.SAND) && !block.getMaterial().equals(Material.RED_SAND)) { + if(d.getMaterial().equals(Material.CACTUS)) + { + if(!block.getMaterial().equals(Material.SAND) && !block.getMaterial().equals(Material.RED_SAND)) + { sliver.set(k, B.getBlockData("SAND")); } } - if (d instanceof Bisected && k < 254) { + if(d instanceof Bisected && k < 254) + { Bisected t = ((Bisected) d.clone()); t.setHalf(Half.TOP); Bisected b = ((Bisected) d.clone()); @@ -332,17 +382,21 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { sliver.set(k + 2, t); } - else { - int stack = i.getHeight(getMasterRandom() - .nextParallelRNG((int) (39456 + (1000 * i.getChance()) + i.getZoom() * 10)), rx, rz); + else + { + int stack = i.getHeight(getMasterRandom().nextParallelRNG((int) (39456 + (1000 * i.getChance()) + i.getZoom() * 10)), rx, rz); - if (stack == 1) { + if(stack == 1) + { sliver.set(k + 1, d); } - else if (k < 255 - stack) { - for (int l = 0; l < stack; l++) { - if (sliver.isSolid(k + l + 1)) { + else if(k < 255 - stack) + { + for(int l = 0; l < stack; l++) + { + if(sliver.isSolid(k + l + 1)) + { break; } @@ -356,35 +410,38 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { } } - private void decorateUnderwater(IrisBiome biome, AtomicSliver sliver, double wx, int y, double wz, int rx, int rz, - BlockData block) { - if (!getDimension().isDecorate()) { + private void decorateUnderwater(IrisBiome biome, AtomicSliver sliver, double wx, int y, double wz, int rx, int rz, BlockData block) + { + if(!getDimension().isDecorate()) + { return; } int j = 0; - for (IrisBiomeDecorator i : biome.getDecorators()) { - if (biome.getInferredType().equals(InferredType.SHORE)) { + for(IrisBiomeDecorator i : biome.getDecorators()) + { + if(biome.getInferredType().equals(InferredType.SHORE)) + { continue; } - BlockData d = i.getBlockData( - getMasterRandom().nextParallelRNG(2555 + biome.getRarity() + biome.getName().length() + j++), rx, - rz); + BlockData d = i.getBlockData(getMasterRandom().nextParallelRNG(2555 + biome.getRarity() + biome.getName().length() + j++), rx, rz); - if (d != null) { - int stack = i.getHeight(getMasterRandom().nextParallelRNG((int) (239456 + i.getStackMax() - + i.getStackMin() + i.getVerticalZoom() + i.getZoom() + i.getBlockData().size() + j)), rx, rz); + if(d != null) + { + int stack = i.getHeight(getMasterRandom().nextParallelRNG((int) (239456 + i.getStackMax() + i.getStackMin() + i.getVerticalZoom() + i.getZoom() + i.getBlockData().size() + j)), rx, rz); - if (stack == 1) { + if(stack == 1) + { sliver.set(i.getPartOf().equals(DecorationPart.SEA_SURFACE) ? (getFluidHeight() + 1) : (y + 1), d); } - else if (y < getFluidHeight() - stack) { - for (int l = 0; l < stack; l++) { - sliver.set(i.getPartOf().equals(DecorationPart.SEA_SURFACE) ? (getFluidHeight() + 1 + l) - : (y + l + 1), d); + else if(y < getFluidHeight() - stack) + { + for(int l = 0; l < stack; l++) + { + sliver.set(i.getPartOf().equals(DecorationPart.SEA_SURFACE) ? (getFluidHeight() + 1 + l) : (y + l + 1), d); } } @@ -394,22 +451,23 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { } @Override - protected void onPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, - BiomeMap biomeMap) { + protected void onPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, BiomeMap biomeMap) + { onPreParallaxPostGenerate(random, x, z, data, grid, height, biomeMap); } - protected void onPreParallaxPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, - BiomeMap biomeMap) { + protected void onPreParallaxPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, BiomeMap biomeMap) + { } - protected void onPostParallaxPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, - HeightMap height, BiomeMap biomeMap) { + protected void onPostParallaxPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, BiomeMap biomeMap) + { } - private double getNoiseHeight(int rx, int rz) { + private double getNoiseHeight(int rx, int rz) + { double wx = getZoomed(rx); double wz = getZoomed(rz); double h = getBiomeHeight(wx, wz, rx, rz); @@ -417,8 +475,10 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { return h; } - public BiomeResult sampleTrueBiomeBase(int x, int z, int height) { - if (!getDimension().getFocus().equals("")) { + public BiomeResult sampleTrueBiomeBase(int x, int z, int height) + { + if(!getDimension().getFocus().equals("")) + { return focus(); } @@ -428,42 +488,51 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { double sh = region.getShoreHeight(wx, wz); IrisBiome current = sampleBiome(x, z).getBiome(); - if (current.isShore() && height > sh) { + if(current.isShore() && height > sh) + { return glBiome.generateData(InferredType.LAND, wx, wz, x, z, region); } - if (current.isShore() || current.isLand() && height <= getDimension().getFluidHeight()) { + if(current.isShore() || current.isLand() && height <= getDimension().getFluidHeight()) + { return glBiome.generateData(InferredType.SEA, wx, wz, x, z, region); } - if (current.isSea() && height > getDimension().getFluidHeight()) { + if(current.isSea() && height > getDimension().getFluidHeight()) + { return glBiome.generateData(InferredType.LAND, wx, wz, x, z, region); } - if (height <= getDimension().getFluidHeight()) { + if(height <= getDimension().getFluidHeight()) + { return glBiome.generateData(InferredType.SEA, wx, wz, x, z, region); } - if (height <= getDimension().getFluidHeight() + sh) { + if(height <= getDimension().getFluidHeight() + sh) + { return glBiome.generateData(InferredType.SHORE, wx, wz, x, z, region); } return glBiome.generateRegionData(wx, wz, x, z, region); } - public BiomeResult sampleCaveBiome(int x, int z) { + public BiomeResult sampleCaveBiome(int x, int z) + { double wx = getModifiedX(x, z); double wz = getModifiedZ(x, z); return glBiome.generateData(InferredType.CAVE, wx, wz, x, z, sampleRegion(x, z)); } - public BiomeResult sampleTrueBiome(int x, int y, int z) { - if (y < getTerrainHeight(x, z)) { + public BiomeResult sampleTrueBiome(int x, int y, int z) + { + if(y < getTerrainHeight(x, z)) + { double wx = getModifiedX(x, z); double wz = getModifiedZ(x, z); BiomeResult r = glBiome.generateData(InferredType.CAVE, wx, wz, x, z, sampleRegion(x, z)); - if (r.getBiome() != null) { + if(r.getBiome() != null) + { return r; } } @@ -471,21 +540,26 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { return sampleTrueBiome(x, z); } - public BiomeResult sampleTrueBiome(int x, int z) { + public BiomeResult sampleTrueBiome(int x, int z) + { return sampleTrueBiome(x, z, getTerrainHeight(x, z)); } @Override - public IrisRegion sampleRegion(int x, int z) { + public IrisRegion sampleRegion(int x, int z) + { return getCache().getRegion(x, z, () -> super.sampleRegion(x, z)); } - public BiomeResult sampleTrueBiome(int x, int z, double noise) { - if (!getDimension().getFocus().equals("")) { + public BiomeResult sampleTrueBiome(int x, int z, double noise) + { + if(!getDimension().getFocus().equals("")) + { return focus(); } - return getCache().getBiome(x, z, () -> { + return getCache().getBiome(x, z, () -> + { double wx = getModifiedX(x, z); double wz = getModifiedZ(x, z); IrisRegion region = sampleRegion(x, z); @@ -494,7 +568,8 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { BiomeResult res = sampleTrueBiomeBase(x, z, height); IrisBiome current = res.getBiome(); - if (current.isSea() && height > getDimension().getFluidHeight() - sh) { + if(current.isSea() && height > getDimension().getFluidHeight() - sh) + { return glBiome.generateData(InferredType.SHORE, wx, wz, x, z, region); } @@ -503,32 +578,38 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { } @Override - protected int onSampleColumnHeight(int cx, int cz, int rx, int rz, int x, int z) { + protected int onSampleColumnHeight(int cx, int cz, int rx, int rz, int x, int z) + { return (int) Math.round(getTerrainHeight(rx, rz)); } - private boolean touchesSea(int rx, int rz) { - return isFluidAtHeight(rx + 1, rz) || isFluidAtHeight(rx - 1, rz) || isFluidAtHeight(rx, rz - 1) - || isFluidAtHeight(rx, rz + 1); + private boolean touchesSea(int rx, int rz) + { + return isFluidAtHeight(rx + 1, rz) || isFluidAtHeight(rx - 1, rz) || isFluidAtHeight(rx, rz - 1) || isFluidAtHeight(rx, rz + 1); } - public boolean isUnderwater(int x, int z) { + public boolean isUnderwater(int x, int z) + { return isFluidAtHeight(x, z); } - public boolean isFluidAtHeight(int x, int z) { + public boolean isFluidAtHeight(int x, int z) + { return Math.round(getTerrainHeight(x, z)) < getFluidHeight(); } - public int getFluidHeight() { + public int getFluidHeight() + { return getDimension().getFluidHeight(); } - public double getTerrainHeight(int x, int z) { + public double getTerrainHeight(int x, int z) + { return getCache().getHeight(x, z, () -> getNoiseHeight(x, z) + getFluidHeight()); } - public double getTerrainWaterHeight(int x, int z) { + public double getTerrainWaterHeight(int x, int z) + { return Math.max(getTerrainHeight(x, z), getFluidHeight()); } } diff --git a/src/main/java/com/volmit/iris/gen/atomics/AtomicMulticache.java b/src/main/java/com/volmit/iris/gen/atomics/AtomicMulticache.java index 09e3eb464..6fe50feb7 100644 --- a/src/main/java/com/volmit/iris/gen/atomics/AtomicMulticache.java +++ b/src/main/java/com/volmit/iris/gen/atomics/AtomicMulticache.java @@ -3,11 +3,13 @@ package com.volmit.iris.gen.atomics; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; +import com.volmit.iris.IrisSettings; import com.volmit.iris.object.IrisRegion; import com.volmit.iris.util.BiomeResult; import com.volmit.iris.util.KMap; -public class AtomicMulticache { +public class AtomicMulticache +{ private final AtomicInteger x; private final AtomicInteger z; private final KMap height; @@ -18,7 +20,8 @@ public class AtomicMulticache { private int w = 0; private int m = 0; - public AtomicMulticache() { + public AtomicMulticache() + { x = new AtomicInteger(0); z = new AtomicInteger(0); height = new KMap(); @@ -27,83 +30,108 @@ public class AtomicMulticache { region = new KMap(); } - public void targetChunk(int x, int z) { + public void targetChunk(int x, int z) + { this.x.set(x); this.z.set(z); + r = 0; + w = 0; + m = 0; + + if(!IrisSettings.get().sharedCaching || getSize() > 42000) + { + drop(); + } + } + + public double getHeight(int x, int z, Supplier g) + { + return height.compute(pos(x, z), (k, v) -> + { + if(v == null) + { + m++; + w++; + return g.get(); + } + + r++; + + return v; + }); + } + + public IrisRegion getRegion(int x, int z, Supplier g) + { + return region.compute(pos(x, z), (k, v) -> + { + if(v == null) + { + m++; + w++; + return g.get(); + } + + r++; + + return v; + }); + } + + public BiomeResult getBiome(int x, int z, Supplier g) + { + return biome.compute(pos(x, z), (k, v) -> + { + if(v == null) + { + m++; + w++; + return g.get(); + } + + r++; + + return v; + }); + } + + public BiomeResult getRawBiome(int x, int z, Supplier g) + { + return rawBiome.compute(pos(x, z), (k, v) -> + { + if(v == null) + { + m++; + w++; + return g.get(); + } + + r++; + + return v; + }); + } + + private long pos(int x, int z) + { + return (((long) x) << 32) | (z & 0xffffffffL); + } + + public void updateHeight(int x, int z, int h) + { + height.put(pos(x, z), (double) h); + } + + public double getSize() + { + return height.size() + region.size() + biome.size() + rawBiome.size(); + } + + public void drop() + { height.clear(); region.clear(); biome.clear(); rawBiome.clear(); - r = 0; - w = 0; - m = 0; - } - - public double getHeight(int x, int z, Supplier g) { - return height.compute(pos(x, z), (k, v) -> { - if (v == null) { - m++; - w++; - return g.get(); - } - - r++; - - return v; - }); - } - - public IrisRegion getRegion(int x, int z, Supplier g) { - return region.compute(pos(x, z), (k, v) -> { - if (v == null) { - m++; - w++; - return g.get(); - } - - r++; - - return v; - }); - } - - public BiomeResult getBiome(int x, int z, Supplier g) { - return biome.compute(pos(x, z), (k, v) -> { - if (v == null) { - m++; - w++; - return g.get(); - } - - r++; - - return v; - }); - } - - public BiomeResult getRawBiome(int x, int z, Supplier g) { - return rawBiome.compute(pos(x, z), (k, v) -> { - if (v == null) { - m++; - w++; - return g.get(); - } - - r++; - - return v; - }); - } - - private long pos(int x, int z) { - return (((long) x) << 32) | (z & 0xffffffffL); - } - - public void updateHeight(int x, int z, int h) { - height.put(pos(x, z), (double) h); - } - - public double getSize() { - return height.size(); } } diff --git a/src/main/java/com/volmit/iris/gen/layer/GenLayerBiome.java b/src/main/java/com/volmit/iris/gen/layer/GenLayerBiome.java index e9c3f62ad..f18c857fa 100644 --- a/src/main/java/com/volmit/iris/gen/layer/GenLayerBiome.java +++ b/src/main/java/com/volmit/iris/gen/layer/GenLayerBiome.java @@ -1,6 +1,7 @@ package com.volmit.iris.gen.layer; import com.volmit.iris.Iris; +import com.volmit.iris.IrisSettings; import com.volmit.iris.gen.DimensionChunkGenerator; import com.volmit.iris.noise.CNG; import com.volmit.iris.object.InferredType; @@ -144,7 +145,7 @@ public class GenLayerBiome extends GenLayer { public BiomeResult implode(double bx, double bz, IrisRegion regionData, CNG parentCell, BiomeResult parent, int hits) { - if (hits > 9) { + if (hits > IrisSettings.get().maxBiomeChildDepth) { return parent; } diff --git a/src/main/java/com/volmit/iris/object/IrisBiome.java b/src/main/java/com/volmit/iris/object/IrisBiome.java index 3331353e0..f4d164f38 100644 --- a/src/main/java/com/volmit/iris/object/IrisBiome.java +++ b/src/main/java/com/volmit/iris/object/IrisBiome.java @@ -17,6 +17,7 @@ import com.volmit.iris.util.KSet; import com.volmit.iris.util.MaxNumber; import com.volmit.iris.util.MinNumber; import com.volmit.iris.util.RNG; +import com.volmit.iris.util.RegistryListBiome; import com.volmit.iris.util.Required; import lombok.Data; @@ -85,6 +86,7 @@ public class IrisBiome extends IrisRegistrant implements IRare @Desc("If this biome has children biomes, and the gen layer chooses one of this biomes children, How will it be shaped?") private IrisGeneratorStyle childStyle = NoiseStyle.CELLULAR_IRIS_DOUBLE.style(); + @RegistryListBiome @ArrayType(min = 1, type = String.class) @DontObfuscate @Desc("List any biome names (file names without.json) here as children. Portions of this biome can sometimes morph into their children. Iris supports cyclic relationships such as A > B > A > B. Iris will stop checking 9 biomes down the tree.") diff --git a/src/main/java/com/volmit/iris/object/IrisBiomeGeneratorLink.java b/src/main/java/com/volmit/iris/object/IrisBiomeGeneratorLink.java index a5754a009..350ac80af 100644 --- a/src/main/java/com/volmit/iris/object/IrisBiomeGeneratorLink.java +++ b/src/main/java/com/volmit/iris/object/IrisBiomeGeneratorLink.java @@ -9,18 +9,21 @@ import com.volmit.iris.util.DontObfuscate; import com.volmit.iris.util.IrisInterpolation; import com.volmit.iris.util.MaxNumber; import com.volmit.iris.util.MinNumber; +import com.volmit.iris.util.RegistryListGenerator; import com.volmit.iris.util.Required; import lombok.Data; @Desc("This represents a link to a generator for a biome") @Data -public class IrisBiomeGeneratorLink { +public class IrisBiomeGeneratorLink +{ + @RegistryListGenerator @DontObfuscate @Desc("The generator id") private String generator = "default"; - @DependsOn({ "min", "max" }) + @DependsOn({"min", "max"}) @Required @MinNumber(-256) @MaxNumber(256) @@ -28,7 +31,7 @@ public class IrisBiomeGeneratorLink { @Desc("The min block value (value + fluidHeight)") private int min = 0; - @DependsOn({ "min", "max" }) + @DependsOn({"min", "max"}) @Required @MinNumber(-256) @MaxNumber(256) @@ -38,16 +41,19 @@ public class IrisBiomeGeneratorLink { private transient AtomicCache gen = new AtomicCache<>(); - public IrisBiomeGeneratorLink() { + public IrisBiomeGeneratorLink() + { } - public IrisGenerator getCachedGenerator(ContextualChunkGenerator g) { - return gen.aquire(() -> { - IrisGenerator gen = g != null ? g.loadGenerator(getGenerator()) - : Iris.globaldata.getGeneratorLoader().load(getGenerator()); + public IrisGenerator getCachedGenerator(ContextualChunkGenerator g) + { + return gen.aquire(() -> + { + IrisGenerator gen = g != null ? g.loadGenerator(getGenerator()) : Iris.globaldata.getGeneratorLoader().load(getGenerator()); - if (gen == null) { + if(gen == null) + { gen = new IrisGenerator(); } @@ -55,7 +61,8 @@ public class IrisBiomeGeneratorLink { }); } - public double getHeight(ContextualChunkGenerator xg, double x, double z, long seed) { + public double getHeight(ContextualChunkGenerator xg, double x, double z, long seed) + { double g = getCachedGenerator(xg).getHeight(x, z, seed); g = g < 0 ? 0 : g; g = g > 1 ? 1 : g; diff --git a/src/main/java/com/volmit/iris/object/IrisBiomeMutation.java b/src/main/java/com/volmit/iris/object/IrisBiomeMutation.java index 3097143b6..ec353e595 100644 --- a/src/main/java/com/volmit/iris/object/IrisBiomeMutation.java +++ b/src/main/java/com/volmit/iris/object/IrisBiomeMutation.java @@ -9,6 +9,8 @@ import com.volmit.iris.util.KList; import com.volmit.iris.util.KSet; import com.volmit.iris.util.MaxNumber; import com.volmit.iris.util.MinNumber; +import com.volmit.iris.util.RegistryListBiome; +import com.volmit.iris.util.RegistryListObject; import com.volmit.iris.util.Required; import lombok.Data; @@ -17,12 +19,14 @@ import lombok.Data; @Data public class IrisBiomeMutation { + @RegistryListBiome @Required @ArrayType(min = 1, type = String.class) @DontObfuscate @Desc("One of The following biomes or regions must show up") private KList sideA = new KList<>(); + @RegistryListBiome @Required @ArrayType(min = 1, type = String.class) @DontObfuscate @@ -43,6 +47,7 @@ public class IrisBiomeMutation @Desc("How many tries per chunk to check for this mutation") private int checks = 2; + @RegistryListObject @ArrayType(min = 1, type = IrisObjectPlacement.class) @DontObfuscate @Desc("Objects define what schematics (iob files) iris will place in this biome mutation") diff --git a/src/main/java/com/volmit/iris/object/IrisDimension.java b/src/main/java/com/volmit/iris/object/IrisDimension.java index 99efbaf9f..69b20dcde 100644 --- a/src/main/java/com/volmit/iris/object/IrisDimension.java +++ b/src/main/java/com/volmit/iris/object/IrisDimension.java @@ -21,6 +21,9 @@ import com.volmit.iris.util.KSet; import com.volmit.iris.util.MaxNumber; import com.volmit.iris.util.MinNumber; import com.volmit.iris.util.RNG; +import com.volmit.iris.util.RegistryListBiome; +import com.volmit.iris.util.RegistryListDimension; +import com.volmit.iris.util.RegistryListRegion; import com.volmit.iris.util.Required; import lombok.Data; @@ -160,6 +163,7 @@ public class IrisDimension extends IrisRegistrant @Desc("Compatability filters") private KList compatability = getDefaultCompatability(); + @RegistryListDimension @DontObfuscate @Desc("The ceiling dimension. Leave blank for normal sky.") private String ceiling = ""; @@ -173,6 +177,7 @@ public class IrisDimension extends IrisRegistrant @Desc("The world environment") private Environment environment = Environment.NORMAL; + @RegistryListRegion @Required @ArrayType(min = 1, type = String.class) @DontObfuscate @@ -186,6 +191,7 @@ public class IrisDimension extends IrisRegistrant @Desc("The fluid height for this dimension") private int fluidHeight = 63; + @RegistryListBiome @DontObfuscate @Desc("Keep this either undefined or empty. Setting any biome name into this will force iris to only generate the specified biome. Great for testing.") private String focus = ""; diff --git a/src/main/java/com/volmit/iris/object/IrisObject.java b/src/main/java/com/volmit/iris/object/IrisObject.java index 1d5f0d9fd..af7664c66 100644 --- a/src/main/java/com/volmit/iris/object/IrisObject.java +++ b/src/main/java/com/volmit/iris/object/IrisObject.java @@ -12,6 +12,7 @@ import java.io.OutputStream; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Waterlogged; import org.bukkit.block.data.type.Leaves; import org.bukkit.util.BlockVector; @@ -26,21 +27,19 @@ import lombok.EqualsAndHashCode; @Data @EqualsAndHashCode(callSuper = false) -public class IrisObject extends IrisRegistrant { +public class IrisObject extends IrisRegistrant +{ private static final Material SNOW = Material.SNOW; private static final BlockData AIR = B.getBlockData("CAVE_AIR"); - private static final BlockData[] SNOW_LAYERS = new BlockData[] { B.getBlockData("minecraft:snow[layers=1]"), - B.getBlockData("minecraft:snow[layers=2]"), B.getBlockData("minecraft:snow[layers=3]"), - B.getBlockData("minecraft:snow[layers=4]"), B.getBlockData("minecraft:snow[layers=5]"), - B.getBlockData("minecraft:snow[layers=6]"), B.getBlockData("minecraft:snow[layers=7]"), - B.getBlockData("minecraft:snow[layers=8]") }; + private static final BlockData[] SNOW_LAYERS = new BlockData[] {B.getBlockData("minecraft:snow[layers=1]"), B.getBlockData("minecraft:snow[layers=2]"), B.getBlockData("minecraft:snow[layers=3]"), B.getBlockData("minecraft:snow[layers=4]"), B.getBlockData("minecraft:snow[layers=5]"), B.getBlockData("minecraft:snow[layers=6]"), B.getBlockData("minecraft:snow[layers=7]"), B.getBlockData("minecraft:snow[layers=8]")}; private KMap blocks; private int w; private int d; private int h; private transient BlockVector center; - public IrisObject(int w, int h, int d) { + public IrisObject(int w, int h, int d) + { blocks = new KMap<>(); this.w = w; this.h = h; @@ -48,7 +47,8 @@ public class IrisObject extends IrisRegistrant { center = new BlockVector(w / 2, h / 2, d / 2); } - public static BlockVector sampleSize(File file) throws IOException { + public static BlockVector sampleSize(File file) throws IOException + { FileInputStream in = new FileInputStream(file); DataInputStream din = new DataInputStream(in); BlockVector bv = new BlockVector(din.readInt(), din.readInt(), din.readInt()); @@ -56,7 +56,8 @@ public class IrisObject extends IrisRegistrant { return bv; } - public void read(InputStream in) throws IOException { + public void read(InputStream in) throws IOException + { DataInputStream din = new DataInputStream(in); this.w = din.readInt(); this.h = din.readInt(); @@ -64,32 +65,36 @@ public class IrisObject extends IrisRegistrant { center = new BlockVector(w / 2, h / 2, d / 2); int s = din.readInt(); - for (int i = 0; i < s; i++) { - blocks.put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), - B.getBlockData(din.readUTF())); + for(int i = 0; i < s; i++) + { + blocks.put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), B.getBlockData(din.readUTF())); } } - public void read(File file) throws IOException { + public void read(File file) throws IOException + { FileInputStream fin = new FileInputStream(file); read(fin); fin.close(); } - public void write(File file) throws IOException { + public void write(File file) throws IOException + { file.getParentFile().mkdirs(); FileOutputStream out = new FileOutputStream(file); write(out); out.close(); } - public void write(OutputStream o) throws IOException { + public void write(OutputStream o) throws IOException + { DataOutputStream dos = new DataOutputStream(o); dos.writeInt(w); dos.writeInt(h); dos.writeInt(d); dos.writeInt(blocks.size()); - for (BlockVector i : blocks.k()) { + for(BlockVector i : blocks.k()) + { dos.writeShort(i.getBlockX()); dos.writeShort(i.getBlockY()); dos.writeShort(i.getBlockZ()); @@ -97,68 +102,102 @@ public class IrisObject extends IrisRegistrant { } } - public void setUnsigned(int x, int y, int z, BlockData block) { - if (x >= w || y >= h || z >= d) { + public void setUnsigned(int x, int y, int z, BlockData block) + { + if(x >= w || y >= h || z >= d) + { throw new RuntimeException(x + " " + y + " " + z + " exceeds limit of " + w + " " + h + " " + d); } BlockVector v = new BlockVector(x, y, z).subtract(center).toBlockVector(); - if (block == null) { + if(block == null) + { blocks.remove(v); } - else { + else + { blocks.put(v, block); } } - public void place(int x, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng) { + public void place(int x, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng) + { place(x, -1, z, placer, config, rng); } - public void place(int x, int yv, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng) { + public void place(int x, int yv, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng) + { int spinx = rng.imax() / 1000; int spiny = rng.imax() / 1000; int spinz = rng.imax() / 1000; - int y = yv < 0 ? placer.getHighest(x, z, config.isUnderwater()) + config.getRotation() - .rotate(new BlockVector(0, getCenter().getBlockY(), 0), spinx, spiny, spinz).getBlockY() : yv; + int rty = config.getRotation().rotate(new BlockVector(0, getCenter().getBlockY(), 0), spinx, spiny, spinz).getBlockY(); + int ty = config.getTranslate().translate(new BlockVector(0, getCenter().getBlockY(), 0), config.getRotation(), spinx, spiny, spinz).getBlockY(); + int y = yv < 0 ? placer.getHighest(x, z, config.isUnderwater()) + rty : yv; - if (yv >= 0 && config.isBottom()) { + if(yv >= 0 && config.isBottom()) + { y += Math.floorDiv(h, 2); } KMap heightmap = config.getSnow() > 0 ? new KMap<>() : null; - if (yv < 0) { - if (!config.isUnderwater() && !config.isOnwater() && placer.isUnderwater(x, z)) { + if(yv < 0) + { + if(!config.isUnderwater() && !config.isOnwater() && placer.isUnderwater(x, z)) + { return; } } - if (config.isBore()) { - for (int i = x - Math.floorDiv(w, 2); i <= x + Math.floorDiv(w, 2) - (w % 2 == 0 ? 1 : 0); i++) { - for (int j = y - Math.floorDiv(h, 2); j <= y + Math.floorDiv(h, 2) - (h % 2 == 0 ? 1 : 0); j++) { - for (int k = z - Math.floorDiv(d, 2); k <= z + Math.floorDiv(d, 2) - (d % 2 == 0 ? 1 : 0); k++) { + if(config.isUnderwater() && y + rty + ty >= placer.getFluidHeight()) + { + return; + } + + if(!config.getClamp().canPlace(y + rty + ty, y - rty + ty)) + { + return; + } + + if(config.isBore()) + { + for(int i = x - Math.floorDiv(w, 2); i <= x + Math.floorDiv(w, 2) - (w % 2 == 0 ? 1 : 0); i++) + { + for(int j = y - Math.floorDiv(h, 2); j <= y + Math.floorDiv(h, 2) - (h % 2 == 0 ? 1 : 0); j++) + { + for(int k = z - Math.floorDiv(d, 2); k <= z + Math.floorDiv(d, 2) - (d % 2 == 0 ? 1 : 0); k++) + { placer.set(i, j, k, AIR); } } } } - for (BlockVector g : blocks.keySet()) { + for(BlockVector g : blocks.keySet()) + { BlockVector i = g.clone(); i = config.getRotation().rotate(i.clone(), spinx, spiny, spinz).clone(); i = config.getTranslate().translate(i.clone(), config.getRotation(), spinx, spiny, spinz).clone(); BlockData data = blocks.get(g).clone(); - if (placer.isPreventingDecay() && data instanceof Leaves && !((Leaves) data).isPersistent()) { + if(placer.isPreventingDecay() && data instanceof Leaves && !((Leaves) data).isPersistent()) + { ((Leaves) data).setPersistent(true); } - for (IrisObjectReplace j : config.getEdit()) { - if (j.isExact() ? j.getFind().matches(data) : j.getFind().getMaterial().equals(data.getMaterial())) { - data = j.getReplace(); + for(IrisObjectReplace j : config.getEdit()) + { + if(j.isExact()) + { + for(BlockData k : j.getFind()) + { + if(j.isExact() ? k.matches(data) : k.getMaterial().equals(data.getMaterial())) + { + data = j.getReplace(rng, i.getX() + x, i.getY() + y, i.getZ() + z).clone(); + } + } } } @@ -167,36 +206,49 @@ public class IrisObject extends IrisRegistrant { int yy = y + (int) Math.round(i.getY()); int zz = z + (int) Math.round(i.getZ()); - if (heightmap != null) { + if(heightmap != null) + { ChunkPosition pos = new ChunkPosition(xx, zz); - if (!heightmap.containsKey(pos)) { + if(!heightmap.containsKey(pos)) + { heightmap.put(pos, yy); } - if (heightmap.get(pos) < yy) { + if(heightmap.get(pos) < yy) + { heightmap.put(pos, yy); } } - if (config.isMeld() && !placer.isSolid(xx, yy, zz)) { + if(config.isMeld() && !placer.isSolid(xx, yy, zz)) + { continue; } + if(yy <= placer.getFluidHeight() && data instanceof Waterlogged) + { + ((Waterlogged) data).setWaterlogged(true); + } + placer.set(xx, yy, zz, data); } - if (heightmap != null) { + if(heightmap != null) + { RNG rngx = rng.nextParallelRNG(3468854); - for (ChunkPosition i : heightmap.k()) { + for(ChunkPosition i : heightmap.k()) + { int vx = i.getX(); int vy = heightmap.get(i); int vz = i.getZ(); - if (config.getSnow() > 0) { + if(config.getSnow() > 0) + { BlockData bd = placer.get(vx, vy, vz); - if (bd != null && bd.getMaterial().equals(SNOW)) { + if(bd != null && bd.getMaterial().equals(SNOW)) + { continue; } @@ -207,8 +259,10 @@ public class IrisObject extends IrisRegistrant { } } - public void place(Location at) { - for (BlockVector i : blocks.keySet()) { + public void place(Location at) + { + for(BlockVector i : blocks.keySet()) + { at.clone().add(0, getCenter().getY(), 0).add(i).getBlock().setBlockData(blocks.get(i), false); } } diff --git a/src/main/java/com/volmit/iris/object/IrisObjectLimit.java b/src/main/java/com/volmit/iris/object/IrisObjectLimit.java new file mode 100644 index 000000000..2e3ad1d1f --- /dev/null +++ b/src/main/java/com/volmit/iris/object/IrisObjectLimit.java @@ -0,0 +1,40 @@ +package com.volmit.iris.object; + +import com.volmit.iris.util.Desc; +import com.volmit.iris.util.DontObfuscate; +import com.volmit.iris.util.MaxNumber; +import com.volmit.iris.util.MinNumber; + +import lombok.Data; + +@Desc("Translate objects") +@Data +public class IrisObjectLimit +{ + @MinNumber(0) + @MaxNumber(255) + @DontObfuscate + @Desc("The minimum height for placement (bottom of object)") + private int minimumHeight = 0; + + @MinNumber(0) + @MaxNumber(255) + @DontObfuscate + @Desc("The maximum height for placement (top of object)") + private int maximumHeight = 255; + + public IrisObjectLimit() + { + + } + + public boolean canPlace(int h, int l) + { + if(h > maximumHeight || l < minimumHeight) + { + return false; + } + + return true; + } +} diff --git a/src/main/java/com/volmit/iris/object/IrisObjectPlacement.java b/src/main/java/com/volmit/iris/object/IrisObjectPlacement.java index 4b0065902..f2e17b6bb 100644 --- a/src/main/java/com/volmit/iris/object/IrisObjectPlacement.java +++ b/src/main/java/com/volmit/iris/object/IrisObjectPlacement.java @@ -9,6 +9,7 @@ import com.volmit.iris.util.KList; import com.volmit.iris.util.MaxNumber; import com.volmit.iris.util.MinNumber; import com.volmit.iris.util.RNG; +import com.volmit.iris.util.RegistryListObject; import com.volmit.iris.util.Required; import lombok.Data; @@ -17,6 +18,7 @@ import lombok.Data; @Data public class IrisObjectPlacement { + @RegistryListObject @Required @ArrayType(min = 1, type = String.class) @DontObfuscate @@ -36,6 +38,10 @@ public class IrisObjectPlacement @Desc("Rotate this objects placement") private IrisObjectRotation rotation = new IrisObjectRotation(); + @DontObfuscate + @Desc("Limit the max height or min height of placement.") + private IrisObjectLimit clamp = new IrisObjectLimit(); + @MinNumber(0) @MaxNumber(1) @DontObfuscate diff --git a/src/main/java/com/volmit/iris/object/IrisObjectReplace.java b/src/main/java/com/volmit/iris/object/IrisObjectReplace.java index 50bd76b67..a8c88b2da 100644 --- a/src/main/java/com/volmit/iris/object/IrisObjectReplace.java +++ b/src/main/java/com/volmit/iris/object/IrisObjectReplace.java @@ -3,9 +3,13 @@ package com.volmit.iris.object; import org.bukkit.block.data.BlockData; import com.volmit.iris.gen.atomics.AtomicCache; +import com.volmit.iris.noise.CNG; +import com.volmit.iris.util.ArrayType; import com.volmit.iris.util.B; import com.volmit.iris.util.Desc; import com.volmit.iris.util.DontObfuscate; +import com.volmit.iris.util.KList; +import com.volmit.iris.util.RNG; import com.volmit.iris.util.Required; import lombok.Data; @@ -14,35 +18,43 @@ import lombok.Data; @Data public class IrisObjectReplace { + @ArrayType(min = 1, type = String.class) @Required @Desc("Find this block") @DontObfuscate - private String find; + private KList find; + @ArrayType(min = 1, type = String.class) @Required @Desc("Replace it with this block") @DontObfuscate - private String replace; + private KList replace; @Desc("Exactly match the block data or not") @DontObfuscate private boolean exact = false; - private transient AtomicCache findData = new AtomicCache<>(); - private transient AtomicCache replaceData = new AtomicCache<>(); + private transient AtomicCache replaceGen = new AtomicCache<>(); + private transient AtomicCache> findData = new AtomicCache<>(); + private transient AtomicCache> replaceData = new AtomicCache<>(); public IrisObjectReplace() { } - public BlockData getFind() + public KList getFind() { return findData.aquire(() -> B.getBlockData(find)); } - public BlockData getReplace() + public KList getReplace() { return replaceData.aquire(() -> B.getBlockData(replace)); } + + public BlockData getReplace(RNG seed, double x, double y, double z) + { + return replaceGen.aquire(() -> NoiseStyle.STATIC.create(seed).bake()).fit(getReplace(), x, y, z); + } } diff --git a/src/main/java/com/volmit/iris/object/IrisRegionRidge.java b/src/main/java/com/volmit/iris/object/IrisRegionRidge.java index 6688a71c8..658415217 100644 --- a/src/main/java/com/volmit/iris/object/IrisRegionRidge.java +++ b/src/main/java/com/volmit/iris/object/IrisRegionRidge.java @@ -7,6 +7,7 @@ import com.volmit.iris.util.DontObfuscate; import com.volmit.iris.util.MaxNumber; import com.volmit.iris.util.MinNumber; import com.volmit.iris.util.RNG; +import com.volmit.iris.util.RegistryListBiome; import com.volmit.iris.util.Required; import lombok.Data; @@ -15,6 +16,7 @@ import lombok.Data; @Data public class IrisRegionRidge { + @RegistryListBiome @Required @DontObfuscate @Desc("The biome name") diff --git a/src/main/java/com/volmit/iris/object/IrisRegionSpot.java b/src/main/java/com/volmit/iris/object/IrisRegionSpot.java index 7c62ba55c..2201b8dc2 100644 --- a/src/main/java/com/volmit/iris/object/IrisRegionSpot.java +++ b/src/main/java/com/volmit/iris/object/IrisRegionSpot.java @@ -6,6 +6,7 @@ import com.volmit.iris.util.Desc; import com.volmit.iris.util.DontObfuscate; import com.volmit.iris.util.MinNumber; import com.volmit.iris.util.RNG; +import com.volmit.iris.util.RegistryListBiome; import com.volmit.iris.util.Required; import lombok.Data; @@ -14,6 +15,7 @@ import lombok.Data; @Data public class IrisRegionSpot { + @RegistryListBiome @Required @DontObfuscate @Desc("The biome to be placed") diff --git a/src/main/java/com/volmit/iris/object/IrisStructurePlacement.java b/src/main/java/com/volmit/iris/object/IrisStructurePlacement.java index 65f3cef64..647874f1a 100644 --- a/src/main/java/com/volmit/iris/object/IrisStructurePlacement.java +++ b/src/main/java/com/volmit/iris/object/IrisStructurePlacement.java @@ -10,6 +10,7 @@ import com.volmit.iris.util.DontObfuscate; import com.volmit.iris.util.MaxNumber; import com.volmit.iris.util.MinNumber; import com.volmit.iris.util.RNG; +import com.volmit.iris.util.RegistryListStructure; import com.volmit.iris.util.Required; import lombok.Data; @@ -18,6 +19,7 @@ import lombok.Data; @Data public class IrisStructurePlacement { + @RegistryListStructure @Required @DontObfuscate @Desc("The structure tileset to use") diff --git a/src/main/java/com/volmit/iris/object/IrisStructureTile.java b/src/main/java/com/volmit/iris/object/IrisStructureTile.java index 9d2f6f9ed..d9afd5527 100644 --- a/src/main/java/com/volmit/iris/object/IrisStructureTile.java +++ b/src/main/java/com/volmit/iris/object/IrisStructureTile.java @@ -4,6 +4,7 @@ import com.volmit.iris.util.ArrayType; import com.volmit.iris.util.Desc; import com.volmit.iris.util.DontObfuscate; import com.volmit.iris.util.KList; +import com.volmit.iris.util.RegistryListObject; import com.volmit.iris.util.Required; import lombok.Data; @@ -45,6 +46,7 @@ public class IrisStructureTile @Desc("Is this structure allowed to place if there is supposed to be a west wall?") private StructureTileCondition west = StructureTileCondition.AGNOSTIC; + @RegistryListObject @Required @ArrayType(min = 1, type = String.class) @DontObfuscate diff --git a/src/main/java/com/volmit/iris/util/B.java b/src/main/java/com/volmit/iris/util/B.java index fd968f237..67a6faf14 100644 --- a/src/main/java/com/volmit/iris/util/B.java +++ b/src/main/java/com/volmit/iris/util/B.java @@ -13,12 +13,23 @@ public class B private static final KMap bdc = new KMap<>(); private static final KList nulls = new KList<>(); private static final IrisDimension defaultCompat = new IrisDimension(); + private static final KMap solid = new KMap<>(); public static BlockData get(String bd) { return getBlockData(bd); } + public static boolean isSolid(Material mat) + { + if(!solid.containsKey(mat)) + { + solid.put(mat, mat.isSolid()); + } + + return solid.get(mat); + } + public static Material mat(String bd) { return getBlockData(bd).getMaterial(); @@ -214,4 +225,21 @@ public class B || m.equals(B.mat("SOUL_TORCH")); //@done } + + public static KList getBlockData(KList find) + { + KList b = new KList<>(); + + for(String i : find) + { + BlockData bd = getBlockData(i); + + if(bd != null) + { + b.add(bd); + } + } + + return b; + } } diff --git a/src/main/java/com/volmit/iris/util/FileWatcher.java b/src/main/java/com/volmit/iris/util/FileWatcher.java index 305988be4..41ceffd76 100644 --- a/src/main/java/com/volmit/iris/util/FileWatcher.java +++ b/src/main/java/com/volmit/iris/util/FileWatcher.java @@ -2,14 +2,9 @@ package com.volmit.iris.util; import java.io.File; -import lombok.Data; -import lombok.Getter; - -@Data public class FileWatcher { - @Getter - private final File file; + protected final File file; private boolean exists; private long lastModified; private long size; @@ -20,11 +15,11 @@ public class FileWatcher readProperties(); } - private void readProperties() + protected void readProperties() { exists = file.exists(); lastModified = exists ? file.lastModified() : -1; - size = exists ? file.length() : -1; + size = exists ? file.isDirectory() ? -2 : file.length() : -1; } public boolean checkModified() diff --git a/src/main/java/com/volmit/iris/util/FolderWatcher.java b/src/main/java/com/volmit/iris/util/FolderWatcher.java new file mode 100644 index 000000000..5fa6d720a --- /dev/null +++ b/src/main/java/com/volmit/iris/util/FolderWatcher.java @@ -0,0 +1,122 @@ +package com.volmit.iris.util; + +import java.io.File; + +public class FolderWatcher extends FileWatcher +{ + private KMap watchers; + private KList changed; + private KList created; + private KList deleted; + + public FolderWatcher(File file) + { + super(file); + } + + protected void readProperties() + { + if(watchers == null) + { + watchers = new KMap<>(); + changed = new KList<>(); + created = new KList<>(); + deleted = new KList<>(); + } + + if(file.isDirectory()) + { + for(File i : file.listFiles()) + { + if(!watchers.containsKey(i)) + { + watchers.put(i, new FolderWatcher(i)); + } + } + + if(watchers == null) + { + System.out.print("wtf"); + } + + for(File i : watchers.k()) + { + if(!i.exists()) + { + watchers.remove(i); + } + } + } + + else + { + super.readProperties(); + } + } + + public boolean checkModified() + { + changed.clear(); + created.clear(); + deleted.clear(); + + if(file.isDirectory()) + { + KMap w = watchers.copy(); + readProperties(); + + for(File i : w.k()) + { + if(!watchers.containsKey(i)) + { + deleted.add(i); + } + } + + for(File i : watchers.k()) + { + if(!w.containsKey(i)) + { + created.add(i); + } + + else + { + FolderWatcher fw = watchers.get(i); + if(fw.checkModified()) + { + changed.add(fw.file); + } + + changed.addAll(fw.getChanged()); + created.addAll(fw.getCreated()); + deleted.addAll(fw.getDeleted()); + } + } + + return !changed.isEmpty() || !created.isEmpty() || !deleted.isEmpty(); + } + + return super.checkModified(); + } + + public KMap getWatchers() + { + return watchers; + } + + public KList getChanged() + { + return changed; + } + + public KList getCreated() + { + return created; + } + + public KList getDeleted() + { + return deleted; + } +} diff --git a/src/main/java/com/volmit/iris/util/IObjectPlacer.java b/src/main/java/com/volmit/iris/util/IObjectPlacer.java index a5a13465f..626baf200 100644 --- a/src/main/java/com/volmit/iris/util/IObjectPlacer.java +++ b/src/main/java/com/volmit/iris/util/IObjectPlacer.java @@ -2,7 +2,8 @@ package com.volmit.iris.util; import org.bukkit.block.data.BlockData; -public interface IObjectPlacer { +public interface IObjectPlacer +{ public int getHighest(int x, int z); public int getHighest(int x, int z, boolean ignoreFluid); @@ -16,4 +17,6 @@ public interface IObjectPlacer { public boolean isSolid(int x, int y, int z); public boolean isUnderwater(int x, int z); + + public int getFluidHeight(); } diff --git a/src/main/java/com/volmit/iris/util/ObjectResourceLoader.java b/src/main/java/com/volmit/iris/util/ObjectResourceLoader.java index 4e514dd58..8aa3821e0 100644 --- a/src/main/java/com/volmit/iris/util/ObjectResourceLoader.java +++ b/src/main/java/com/volmit/iris/util/ObjectResourceLoader.java @@ -100,6 +100,43 @@ public class ObjectResourceLoader extends ResourceLoader } } + public String[] getPossibleKeys() + { + if(possibleKeys != null) + { + return possibleKeys; + } + + Iris.info("Building " + resourceTypeName + " Possibility Lists"); + KSet m = new KSet<>(); + + for(File i : getFolders()) + { + for(File j : i.listFiles()) + { + if(j.isFile() && j.getName().endsWith(".iob")) + { + m.add(j.getName().replaceAll("\\Q.json\\E", "")); + } + + else if(j.isDirectory()) + { + for(File k : j.listFiles()) + { + if(k.isFile() && k.getName().endsWith(".iob")) + { + m.add(j.getName() + "/" + k.getName().replaceAll("\\Q.iob\\E", "")); + } + } + } + } + } + + KList v = new KList<>(m); + possibleKeys = v.toArray(new String[v.size()]); + return possibleKeys; + } + public File findFile(String name) { lock.lock(); diff --git a/src/main/java/com/volmit/iris/util/RegistryListBiome.java b/src/main/java/com/volmit/iris/util/RegistryListBiome.java new file mode 100644 index 000000000..36c838c39 --- /dev/null +++ b/src/main/java/com/volmit/iris/util/RegistryListBiome.java @@ -0,0 +1,14 @@ +package com.volmit.iris.util; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target({PARAMETER, TYPE, FIELD}) +public @interface RegistryListBiome +{ + +} diff --git a/src/main/java/com/volmit/iris/util/RegistryListDimension.java b/src/main/java/com/volmit/iris/util/RegistryListDimension.java new file mode 100644 index 000000000..70e730d68 --- /dev/null +++ b/src/main/java/com/volmit/iris/util/RegistryListDimension.java @@ -0,0 +1,14 @@ +package com.volmit.iris.util; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target({PARAMETER, TYPE, FIELD}) +public @interface RegistryListDimension +{ + +} diff --git a/src/main/java/com/volmit/iris/util/RegistryListGenerator.java b/src/main/java/com/volmit/iris/util/RegistryListGenerator.java new file mode 100644 index 000000000..fefd8cd2c --- /dev/null +++ b/src/main/java/com/volmit/iris/util/RegistryListGenerator.java @@ -0,0 +1,14 @@ +package com.volmit.iris.util; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target({PARAMETER, TYPE, FIELD}) +public @interface RegistryListGenerator +{ + +} diff --git a/src/main/java/com/volmit/iris/util/RegistryListObject.java b/src/main/java/com/volmit/iris/util/RegistryListObject.java new file mode 100644 index 000000000..52cac3729 --- /dev/null +++ b/src/main/java/com/volmit/iris/util/RegistryListObject.java @@ -0,0 +1,14 @@ +package com.volmit.iris.util; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target({PARAMETER, TYPE, FIELD}) +public @interface RegistryListObject +{ + +} diff --git a/src/main/java/com/volmit/iris/util/RegistryListRegion.java b/src/main/java/com/volmit/iris/util/RegistryListRegion.java new file mode 100644 index 000000000..4b89eda7c --- /dev/null +++ b/src/main/java/com/volmit/iris/util/RegistryListRegion.java @@ -0,0 +1,14 @@ +package com.volmit.iris.util; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target({PARAMETER, TYPE, FIELD}) +public @interface RegistryListRegion +{ + +} diff --git a/src/main/java/com/volmit/iris/util/RegistryListStructure.java b/src/main/java/com/volmit/iris/util/RegistryListStructure.java new file mode 100644 index 000000000..fdd7fed1f --- /dev/null +++ b/src/main/java/com/volmit/iris/util/RegistryListStructure.java @@ -0,0 +1,14 @@ +package com.volmit.iris.util; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target({PARAMETER, TYPE, FIELD}) +public @interface RegistryListStructure +{ + +} diff --git a/src/main/java/com/volmit/iris/util/ResourceLoader.java b/src/main/java/com/volmit/iris/util/ResourceLoader.java index bcda74e60..85da231c2 100644 --- a/src/main/java/com/volmit/iris/util/ResourceLoader.java +++ b/src/main/java/com/volmit/iris/util/ResourceLoader.java @@ -21,6 +21,7 @@ public class ResourceLoader protected String cname; protected IrisLock lock; protected String preferredFolder = null; + protected String[] possibleKeys = null; public ResourceLoader(File root, String folderName, String resourceTypeName, Class objectClass) { @@ -34,6 +35,43 @@ public class ResourceLoader loadCache = new KMap<>(); } + public String[] getPossibleKeys() + { + if(possibleKeys != null) + { + return possibleKeys; + } + + Iris.info("Building " + resourceTypeName + " Possibility Lists"); + KSet m = new KSet<>(); + + for(File i : getFolders()) + { + for(File j : i.listFiles()) + { + if(j.isFile() && j.getName().endsWith(".json")) + { + m.add(j.getName().replaceAll("\\Q.json\\E", "")); + } + + else if(j.isDirectory()) + { + for(File k : j.listFiles()) + { + if(k.isFile() && k.getName().endsWith(".json")) + { + m.add(j.getName() + "/" + k.getName().replaceAll("\\Q.json\\E", "")); + } + } + } + } + } + + KList v = new KList<>(m); + possibleKeys = v.toArray(new String[v.size()]); + return possibleKeys; + } + public long count() { return loadCache.size(); @@ -155,6 +193,7 @@ public class ResourceLoader public void clearCache() { + possibleKeys = null; loadCache.clear(); folderCache = null; } @@ -191,4 +230,10 @@ public class ResourceLoader { preferredFolder = name; } + + public void clearList() + { + folderCache = null; + possibleKeys = null; + } }