diff --git a/src/main/java/com/volmit/iris/core/decrees/CMDIrisStudio.java b/src/main/java/com/volmit/iris/core/decrees/CMDIrisStudio.java index ed71b7620..8e83eea97 100644 --- a/src/main/java/com/volmit/iris/core/decrees/CMDIrisStudio.java +++ b/src/main/java/com/volmit/iris/core/decrees/CMDIrisStudio.java @@ -19,13 +19,35 @@ package com.volmit.iris.core.decrees; import com.volmit.iris.Iris; +import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.core.project.IrisProject; +import com.volmit.iris.core.project.loader.IrisData; +import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.dimensional.IrisDimension; +import com.volmit.iris.engine.object.objects.IrisObject; +import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.decree.DecreeExecutor; +import com.volmit.iris.util.decree.DecreeOrigin; import com.volmit.iris.util.decree.annotations.Decree; import com.volmit.iris.util.decree.annotations.Param; import com.volmit.iris.util.format.C; +import com.volmit.iris.util.io.IO; +import com.volmit.iris.util.json.JSONArray; +import com.volmit.iris.util.json.JSONObject; +import com.volmit.iris.util.parallel.MultiBurst; +import com.volmit.iris.util.scheduling.J; +import com.volmit.iris.util.scheduling.jobs.Job; +import com.volmit.iris.util.scheduling.jobs.JobCollection; +import com.volmit.iris.util.scheduling.jobs.QueueJob; +import com.volmit.iris.util.scheduling.jobs.SingleJob; -@Decree(name = "studio", aliases = {"std", "s"}, description = "Studio Commands", studio = true) +import java.awt.*; +import java.io.File; +import java.io.IOException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +@Decree(name = "studio", aliases = "std", description = "Studio Commands", studio = true) public class CMDIrisStudio implements DecreeExecutor { @Decree(description = "Open a new studio world", aliases = "o", sync = true) @@ -38,6 +60,37 @@ public class CMDIrisStudio implements DecreeExecutor Iris.proj.open(sender(), dimension.getLoadKey()); } + @Decree(description = "Create a new studio project", aliases = "+", sync = true) + public void create( + @Param(name = "name", required = true, description = "The name of this new Iris Project.") + String name, + @Param(name = "template", description = "Copy the contents of an existing project in your packs folder and use it as a template in this new project.") + IrisDimension template) + { + if (template != null) { + Iris.proj.create(sender(), name, template.getLoadKey()); + } else { + Iris.proj.create(sender(), name); + } + } + + @Decree(description = "Edit the biome at your current location", aliases = "eb", sync = true, origin = DecreeOrigin.PLAYER) + public void editBiome() + { + if (!Iris.proj.isProjectOpen()) { + sender().sendMessage(C.RED + "No open studio projects."); + return; + } + ; + try { + Desktop.getDesktop().open(Iris.proj.getActiveProject().getActiveProvider().getEngine().getBiome(sender().player().getLocation()).getLoadFile()); + } catch (Throwable e) { + Iris.reportError(e); + sender().sendMessage("Cant find the file. Are you in an Iris Studio world?"); + } + + } + @Decree(description = "Close an open studio project", aliases = "x", sync = true) public void close() { @@ -50,4 +103,184 @@ public class CMDIrisStudio implements DecreeExecutor Iris.proj.close(); sender().sendMessage(C.YELLOW + "Project Closed"); } + + @Decree(description = "Clean an Iris Project, optionally beautifying JSON & fixing block ids with missing keys. Also rebuilds the vscode schemas. ") + public void clean( + @Param(name = "project", required = true, description = "The project to update") + IrisDimension project, + + @Param(name = "beautify", defaultValue = "true", description = "Filters all valid JSON files with a beautifier (indentation: 4)") + boolean beautify, + + @Param(name = "fix-ids", defaultValue = "true", description = "Fixes any block ids used such as \"dirt\" will be converted to \"minecraft:dirt\"") + boolean fixIds, + + @Param(name = "rewriteObjects", defaultValue = "false", description = "Imports all objects and re-writes them cleaning up positions & block data in the process.") + boolean rewriteObjects + ) { + KList jobs = new KList<>(); + KList files = new KList(); + files(Iris.instance.getDataFolder("packs", project.getLoadKey()), files); + MultiBurst burst = new MultiBurst("Cleaner", Thread.MIN_PRIORITY, Runtime.getRuntime().availableProcessors() * 2); + + jobs.add(new SingleJob("Updating Workspace", () -> { + if (!new IrisProject(Iris.proj.getWorkspaceFolder(project.getLoadKey())).updateWorkspace()) { + sender().sendMessage(C.GOLD + "Invalid project: " + project.getLoadKey() + ". Try deleting the code-workspace file and try again."); + } + J.sleep(250); + })); + + sender().sendMessage("Files: " + files.size()); + + if(fixIds) + { + QueueJob r = new QueueJob<>() { + @Override + public void execute(File f) { + try { + JSONObject p = new JSONObject(IO.readAll(f)); + fixBlocks(p); + J.sleep(1); + IO.writeAll(f, p.toString(4)); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public String getName() { + return "Fixing IDs"; + } + }; + + r.queue(files); + jobs.add(r); + } + + if(beautify) + { + QueueJob r = new QueueJob<>() { + @Override + public void execute(File f) { + try { + JSONObject p = new JSONObject(IO.readAll(f)); + IO.writeAll(f, p.toString(4)); + J.sleep(1); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public String getName() { + return "Beautify"; + } + }; + + r.queue(files); + jobs.add(r); + } + + if(rewriteObjects) + { + QueueJob q = new QueueJob() { + @Override + public void execute(Runnable runnable) { + runnable.run(); + J.sleep(50); + } + + @Override + public String getName() { + return "Rewriting Objects"; + } + }; + + IrisData data = new IrisData(Iris.proj.getWorkspaceFolder(project.getLoadKey())); + for (String f : data.getObjectLoader().getPossibleKeys()) { + CompletableFuture gg = burst.complete(() ->{ + File ff = data.getObjectLoader().findFile(f); + IrisObject oo = new IrisObject(0, 0, 0); + try { + oo.read(ff); + } catch (Throwable e) { + Iris.error("FAILER TO READ: " + f); + return; + } + + if (oo == null) { + Iris.error("FAILER TO READ: " + f); + return; + } + + try { + oo.write(ff); + } catch (IOException e) { + Iris.error("FAILURE TO WRITE: " + oo.getLoadFile()); + } + }); + + q.queue(() -> { + try { + gg.get(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + }); + } + + jobs.add(q); + } + + jobs.add(new SingleJob("Finishing Up", burst::shutdownNow)); + + new JobCollection("Cleaning", jobs).execute(sender()); + } + + public void files(File clean, KList files) + { + if (clean.isDirectory()) { + for (File i : clean.listFiles()) { + files(i, files); + } + } else if (clean.getName().endsWith(".json")) { + try { + files.add(clean); + } catch (Throwable e) { + Iris.reportError(e); + Iris.error("Failed to beautify " + clean.getAbsolutePath() + " You may have errors in your json!"); + } + } + } + + private void fixBlocks(JSONObject obj) { + for (String i : obj.keySet()) { + Object o = obj.get(i); + + if (i.equals("block") && o instanceof String && !o.toString().trim().isEmpty() && !o.toString().contains(":")) { + obj.put(i, "minecraft:" + o); + } + + if (o instanceof JSONObject) { + fixBlocks((JSONObject) o); + } else if (o instanceof JSONArray) { + fixBlocks((JSONArray) o); + } + } + } + + private void fixBlocks(JSONArray obj) { + for (int i = 0; i < obj.length(); i++) { + Object o = obj.get(i); + + if (o instanceof JSONObject) { + fixBlocks((JSONObject) o); + } else if (o instanceof JSONArray) { + fixBlocks((JSONArray) o); + } + } + } } diff --git a/src/main/java/com/volmit/iris/core/project/IrisProject.java b/src/main/java/com/volmit/iris/core/project/IrisProject.java index 77bfa184d..0601e80e3 100644 --- a/src/main/java/com/volmit/iris/core/project/IrisProject.java +++ b/src/main/java/com/volmit/iris/core/project/IrisProject.java @@ -446,4 +446,62 @@ public class IrisProject { sender.sendMessage("Failed!"); return null; } + + + + public static int clean(VolmitSender s, File clean) { + int c = 0; + if (clean.isDirectory()) { + for (File i : clean.listFiles()) { + c += clean(s, i); + } + } else if (clean.getName().endsWith(".json")) { + try { + clean(clean); + } catch (Throwable e) { + Iris.reportError(e); + Iris.error("Failed to beautify " + clean.getAbsolutePath() + " You may have errors in your json!"); + } + + c++; + } + + return c; + } + + public static void clean(File clean) throws IOException { + JSONObject obj = new JSONObject(IO.readAll(clean)); + fixBlocks(obj, clean); + + IO.writeAll(clean, obj.toString(4)); + } + + public static void fixBlocks(JSONObject obj, File f) { + for (String i : obj.keySet()) { + Object o = obj.get(i); + + if (i.equals("block") && o instanceof String && !o.toString().trim().isEmpty() && !o.toString().contains(":")) { + obj.put(i, "minecraft:" + o); + Iris.debug("Updated Block Key: " + o + " to " + obj.getString(i) + " in " + f.getPath()); + } + + if (o instanceof JSONObject) { + fixBlocks((JSONObject) o, f); + } else if (o instanceof JSONArray) { + fixBlocks((JSONArray) o, f); + } + } + } + + public static void fixBlocks(JSONArray obj, File f) { + for (int i = 0; i < obj.length(); i++) { + Object o = obj.get(i); + + if (o instanceof JSONObject) { + fixBlocks((JSONObject) o, f); + } else if (o instanceof JSONArray) { + fixBlocks((JSONArray) o, f); + } + } + } } diff --git a/src/main/java/com/volmit/iris/util/decree/DecreeParameterHandler.java b/src/main/java/com/volmit/iris/util/decree/DecreeParameterHandler.java index 4b1091867..081c7b2bf 100644 --- a/src/main/java/com/volmit/iris/util/decree/DecreeParameterHandler.java +++ b/src/main/java/com/volmit/iris/util/decree/DecreeParameterHandler.java @@ -65,6 +65,12 @@ public interface DecreeParameterHandler { */ default KList getPossibilities(String input) { + if(input.trim().isEmpty()) + { + KList f = getPossibilities(); + return f == null ? new KList<>() : f; + } + input = input.trim(); KList possible = getPossibilities(); KList matches = new KList<>(); diff --git a/src/main/java/com/volmit/iris/util/decree/DecreeSystem.java b/src/main/java/com/volmit/iris/util/decree/DecreeSystem.java index 341ef6009..0c207a83e 100644 --- a/src/main/java/com/volmit/iris/util/decree/DecreeSystem.java +++ b/src/main/java/com/volmit/iris/util/decree/DecreeSystem.java @@ -47,9 +47,13 @@ public interface DecreeSystem extends CommandExecutor, TabCompleter { @Nullable @Override default List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) { - return new KList<>(); + KList enhanced = new KList<>(args); + KList v = getRoot().tabComplete(enhanced, enhanced.toString(" ")); + v.removeDuplicates(); + return v; } + @Override default boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { J.aBukkit(() -> { @@ -62,6 +66,11 @@ public interface DecreeSystem extends CommandExecutor, TabCompleter { } static KList enhanceArgs(String[] args) + { + return enhanceArgs(args, true); + } + + static KList enhanceArgs(String[] args, boolean trim) { KList a = new KList<>(); @@ -73,15 +82,26 @@ public interface DecreeSystem extends CommandExecutor, TabCompleter { StringBuilder flat = new StringBuilder(); for(String i : args) { - if(i.trim().isEmpty()) + if(trim) { - continue; + if(i.trim().isEmpty()) + { + continue; + } + + flat.append(" ").append(i.trim()); } - flat.append(" ").append(i.trim()); + else + { + if(i.endsWith(" ")) + { + flat.append(" ").append(i.trim()).append(" "); + } + } } - flat = new StringBuilder(flat.substring(1).trim()); + flat = new StringBuilder(flat.length() > 0 ? trim ? flat.toString().trim().length() > 0 ?flat.substring(1).trim() : flat.toString().trim() : flat.substring(1) : flat); StringBuilder arg = new StringBuilder(); boolean quoting = false; @@ -93,7 +113,7 @@ public interface DecreeSystem extends CommandExecutor, TabCompleter { if(i == ' ' && !quoting) { - if(!arg.toString().trim().isEmpty()) + if(!arg.toString().trim().isEmpty() && trim) { a.add(arg.toString().trim()); arg = new StringBuilder(); @@ -113,7 +133,7 @@ public interface DecreeSystem extends CommandExecutor, TabCompleter { if(hasNext && j == ' ') { - if(!arg.toString().trim().isEmpty()) + if(!arg.toString().trim().isEmpty() && trim) { a.add(arg.toString().trim()); arg = new StringBuilder(); @@ -122,7 +142,7 @@ public interface DecreeSystem extends CommandExecutor, TabCompleter { else if(!hasNext) { - if(!arg.toString().trim().isEmpty()) + if(!arg.toString().trim().isEmpty() && trim) { a.add(arg.toString().trim()); arg = new StringBuilder(); @@ -137,7 +157,7 @@ public interface DecreeSystem extends CommandExecutor, TabCompleter { } } - if(!arg.toString().trim().isEmpty()) + if(!arg.toString().trim().isEmpty() && trim) { a.add(arg.toString().trim()); } diff --git a/src/main/java/com/volmit/iris/util/decree/handlers/BooleanHandler.java b/src/main/java/com/volmit/iris/util/decree/handlers/BooleanHandler.java new file mode 100644 index 000000000..6a7f1ba98 --- /dev/null +++ b/src/main/java/com/volmit/iris/util/decree/handlers/BooleanHandler.java @@ -0,0 +1,61 @@ +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2021 Arcane Arts (Volmit Software) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.volmit.iris.util.decree.handlers; + +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.decree.DecreeParameterHandler; +import com.volmit.iris.util.decree.exceptions.DecreeParsingException; +import com.volmit.iris.util.math.M; +import com.volmit.iris.util.math.RNG; + +public class BooleanHandler implements DecreeParameterHandler { + @Override + public KList getPossibilities() { + return null; + } + + @Override + public String toString(Boolean aByte) { + return aByte.toString(); + } + + @Override + public Boolean parse(String in) throws DecreeParsingException { + try + { + return Boolean.parseBoolean(in); + } + + catch(Throwable e) + { + throw new DecreeParsingException("Unable to parse boolean \"" + in + "\""); + } + } + + @Override + public boolean supports(Class type) { + return type.equals(Boolean.class) || type.equals(boolean.class); + } + + @Override + public String getRandomDefault() + { + return M.r(0.5) + ""; + } +} diff --git a/src/main/java/com/volmit/iris/util/decree/virtual/VirtualDecreeCommand.java b/src/main/java/com/volmit/iris/util/decree/virtual/VirtualDecreeCommand.java index 37b93c194..627f8fb09 100644 --- a/src/main/java/com/volmit/iris/util/decree/virtual/VirtualDecreeCommand.java +++ b/src/main/java/com/volmit/iris/util/decree/virtual/VirtualDecreeCommand.java @@ -171,6 +171,141 @@ public class VirtualDecreeCommand { return node != null; } + public KList tabComplete(KList args, String raw) + { + KList skip = new KList<>(); + KList tabs = new KList<>(); + invokeTabComplete(args, skip, tabs, raw); + return tabs; + } + + private boolean invokeTabComplete(KList args, KList skip, KList tabs, String raw) + { + if(isStudio() && !IrisSettings.get().isStudio()) + { + return false; + } + + if(isNode()) + { + tab(args, tabs); + skip.add(hashCode()); + return false; + } + + if(args.isEmpty()) + { + tab(args, tabs); + return true; + } + + String head = args.get(0); + + if (args.size() > 1 || head.endsWith(" ")) + { + VirtualDecreeCommand match = matchNode(head, skip); + + if(match != null) + { + args.pop(); + return match.invokeTabComplete(args, skip, tabs, raw); + } + + skip.add(hashCode()); + } + + else + { + tab(args, tabs); + } + + return false; + } + + private void tab(KList args, KList tabs) { + String last = null; + KList ignore = new KList<>(); + Runnable la = () -> { + + }; + for(String a : args) + { + la.run(); + last = a; + la = () -> { + if(isNode()) + { + String sea = a.contains("=") ? a.split("\\Q=\\E")[0] : a; + sea = sea.trim(); + + searching: for(DecreeParameter i : getNode().getParameters()) + { + for(String m : i.getNames()) + { + if(m.equalsIgnoreCase(sea) || m.toLowerCase().contains(sea.toLowerCase()) || sea.toLowerCase().contains(m.toLowerCase())) + { + ignore.add(i); + continue searching; + } + } + } + } + }; + } + + if(last != null) + { + if (isNode()) { + for(DecreeParameter i : getNode().getParameters()) + { + if(ignore.contains(i)) + { + continue; + } + + int g = 0; + + if(last.contains("=")) + { + String[] vv = last.trim().split("\\Q=\\E"); + String vx = vv.length == 2 ? vv[1] : ""; + for(String f : i.getHandler().getPossibilities(vx).convert((v) -> i.getHandler().toStringForce(v))) + { + g++; + tabs.add(i.getName() +"="+ f); + } + } + + else + { + for(String f : i.getHandler().getPossibilities("").convert((v) -> i.getHandler().toStringForce(v))) + { + g++; + tabs.add(i.getName() +"="+ f); + } + } + + if(g == 0) + { + tabs.add(i.getName() + "="); + } + } + } + + else + { + for(VirtualDecreeCommand i : getNodes()) + { + String m = i.getName(); + if(m.equalsIgnoreCase(last) || m.toLowerCase().contains(last.toLowerCase()) || last.toLowerCase().contains(m.toLowerCase())) + { + tabs.addAll(i.getNames()); + } + } + } + } + } + private KMap map(VolmitSender sender, KList in) { KMap data = new KMap<>(); @@ -396,8 +531,43 @@ public class VirtualDecreeCommand { return true; } + public KList matchAllNodes(String in) + { + KList g = new KList<>(); + + if(in.trim().isEmpty()) + { + g.addAll(nodes); + return g; + } + + for(VirtualDecreeCommand i : nodes) + { + if(i.matches(in)) + { + g.add(i); + } + } + + for(VirtualDecreeCommand i : nodes) + { + if(i.deepMatches(in)) + { + g.add(i); + } + } + + g.removeDuplicates(); + return g; + } + public VirtualDecreeCommand matchNode(String in, KList skip) { + if(in.trim().isEmpty()) + { + return null; + } + for(VirtualDecreeCommand i : nodes) { if(skip.contains(i.hashCode())) diff --git a/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java b/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java index 237063351..9fb389ac9 100644 --- a/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java +++ b/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java @@ -367,14 +367,14 @@ public class VolmitSender implements CommandSender { { m.add((i.isNode() ? (i.getNode().getParameters().isNotEmpty()) - ? "Or: " + ? "<#aebef2>✦ <#5ef288>" + i.getParentPath() - + " " + + " <#42ecf5>" + i.getName() + " " + i.getNode().getParameters().shuffleCopy(RNG.r).convert((f) -> (f.isRequired() || RNG.r.b(0.5) - ? "" + f.getNames().getRandom() + "=" - + "" + f.example() + ? "<#f2e15e>" + f.getNames().getRandom() + "=" + + "<#d665f0>" + f.example() : "")) .toString(" ") : "" @@ -384,49 +384,82 @@ public class VolmitSender implements CommandSender { return m.removeDuplicates().convert((iff) -> iff.replaceAll("\\Q \\E", " ")).toString("\n"); } + + public void sendHeader(String name, int overrideLength) + { + int len = overrideLength; + int h = name.length() + 2; + String s = Form.repeat(" ", len - h - 4); + String si = Form.repeat("(", 3); + String so = Form.repeat(")", 3); + String sf = "["; + String se = "]"; + + if(name.trim().isEmpty()) + { + sendMessageRaw("" + sf + s + "" + s + se); + } + + else + { + sendMessageRaw("" + sf + s + si + " " + name + " " + so + s + se); + } + } + + public void sendHeader(String name) + { + sendHeader(name,46); + } + public void sendDecreeHelp(VirtualDecreeCommand v) { int m = v.getNodes().size(); if(v.getNodes().isNotEmpty()) { + sendHeader(Form.capitalize(v.getName()) + " Help"); + if(isPlayer() && v.getParent() != null) + { + sendMessageRaw("Click to go back to <#3299bf>" + Form.capitalize(v.getParent().getName()) + " Help" +"'><#f58571>〈 Back"); + } + for(VirtualDecreeCommand i : v.getNodes()) { if(isPlayer()) { //@builder - sendMessageRaw( + String s = ( " "" + f).toString(", ") + "\n" - + "" + i.getDescription() + "\n" - + "" + (i.isNode() + i.getNames().copy().reverse().convert((f) -> "<#42ecf5>" + f).toString(", ") + "\n" + + "<#3fe05a>✎ <#6ad97d>" + i.getDescription() + "\n" + + "<#bbe03f>✒ <#a8e0a2>" + (i.isNode() ? ((i.getNode().getParameters().isEmpty() - ? "There are no parameters." - : "Hover over all of the parameters to learn more.") + "\n") - : "This is a command category. Run " + i.getPath()) + ? "There are no parameters." + : "Hover over all of the parameters to learn more.") + "\n") + : "This is a command category. Run <#98eda5>" + i.getPath()) + (i.isNode() ? (i.getNode().getParameters().isNotEmpty()) - ? "Usage: " + ? "<#aebef2>✦ <#5ef288>" + i.getParentPath() - + " " + + " <#42ecf5>" + i.getName() + " " + i.getNode().getParameters().convert((f) - -> "" + f.example()) + -> "<#d665f0>" + f.example()) .toString(" ") + "\n" : "" : "") - + (i.isNode() ? pickRandoms(Math.min(i.getNode().getParameters().size() + 1, 5), i) : "") - + "'>" - + "" +i.getName() + "" + + (i.isNode() ? "" + pickRandoms(Math.min(i.getNode().getParameters().size() + 1, 5), i) + "" : "") + + "'>" + + "<#46826a>⇀ " +i.getName() + "" + (i.isNode() ? " " + i.getNode().getParameters().convert((f) -> " "" + ff).toString(", ") + "\n" - + "" + f.getDescription() + "\n" + + f.getNames().convert((ff) -> "<#d665f0>" + ff).toString(", ") + "\n" + + "<#3fe05a>✎ <#6ad97d>" + f.getDescription() + "\n" + (f.isRequired() - ? "This parameter is required." + ? "<#db4321>⚠ <#faa796>This parameter is required." : (f.hasDefault() - ? "Defaults to \""+f.getParam().defaultValue()+"\" if undefined." - : "This parameter is optional.")) + ? "<#2181db>✔ <#78dcf0>Defaults to \""+f.getParam().defaultValue()+"\" if undefined." + : "<#a73abd>✔ <#78dcf0>This parameter is optional.")) + "'>" + (f.isRequired() ? "[" : "") + "" + f.getName() @@ -436,6 +469,8 @@ public class VolmitSender implements CommandSender { ) ); //@done + sendMessageRaw(s); + System.out.println(s); } else diff --git a/src/main/java/com/volmit/iris/util/scheduling/jobs/Job.java b/src/main/java/com/volmit/iris/util/scheduling/jobs/Job.java new file mode 100644 index 000000000..309841b88 --- /dev/null +++ b/src/main/java/com/volmit/iris/util/scheduling/jobs/Job.java @@ -0,0 +1,76 @@ +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2021 Arcane Arts (Volmit Software) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.volmit.iris.util.scheduling.jobs; + +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.format.Form; +import com.volmit.iris.util.plugin.VolmitSender; +import com.volmit.iris.util.scheduling.J; +import com.volmit.iris.util.scheduling.PrecisionStopwatch; + +import java.util.concurrent.CompletableFuture; + +public interface Job +{ + String getName(); + + void execute(); + + void completeWork(); + + int getTotalWork(); + + default int getWorkRemaining() + { + return getTotalWork() - getWorkCompleted(); + } + + int getWorkCompleted(); + + default String getProgressString() + { + return Form.pc(getProgress(), 0); + } + + default double getProgress() + { + return (double)getWorkCompleted() / (double)getTotalWork(); + } + + default void execute(VolmitSender sender) + { + PrecisionStopwatch p = PrecisionStopwatch.start(); + CompletableFuture f = J.afut(this::execute); + int c = J.ar(() -> { + if(sender.isPlayer()) + { + sender.sendProgress(getProgress(), getName()); + } + + else + { + sender.sendMessage(getName() + ": " + getProgressString()); + } + }, sender.isPlayer() ? 0 : 20); + f.whenComplete((fs, ff) -> { + J.car(c); + sender.sendMessage("Completed " + getName() + " in " + Form.duration(p.getMilliseconds(), 1)); + }); + } +} diff --git a/src/main/java/com/volmit/iris/util/scheduling/jobs/JobCollection.java b/src/main/java/com/volmit/iris/util/scheduling/jobs/JobCollection.java new file mode 100644 index 000000000..0accefafb --- /dev/null +++ b/src/main/java/com/volmit/iris/util/scheduling/jobs/JobCollection.java @@ -0,0 +1,70 @@ +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2021 Arcane Arts (Volmit Software) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.volmit.iris.util.scheduling.jobs; + +import com.volmit.iris.util.collection.KList; + +public class JobCollection implements Job { + private final String name; + private String status; + private final KList jobs; + + public JobCollection(String name, Job... jobs) + { + this(name, new KList<>(jobs)); + } + + public JobCollection(String name, KList jobs) + { + this.name = name; + status = null; + this.jobs = new KList<>(jobs); + } + + @Override + public String getName() { + return status == null ? name : (name + " 》" + status); + } + + @Override + public void execute() { + for(Job i : jobs) + { + status = i.getName(); + i.execute(); + } + + status = null; + } + + @Override + public void completeWork() { + + } + + @Override + public int getTotalWork() { + return jobs.stream().mapToInt(Job::getTotalWork).sum(); + } + + @Override + public int getWorkCompleted() { + return jobs.stream().mapToInt(Job::getWorkCompleted).sum(); + } +} diff --git a/src/main/java/com/volmit/iris/util/scheduling/jobs/QueueJob.java b/src/main/java/com/volmit/iris/util/scheduling/jobs/QueueJob.java new file mode 100644 index 000000000..5fb92c5f3 --- /dev/null +++ b/src/main/java/com/volmit/iris/util/scheduling/jobs/QueueJob.java @@ -0,0 +1,73 @@ +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2021 Arcane Arts (Volmit Software) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.volmit.iris.util.scheduling.jobs; + +import com.volmit.iris.util.collection.KList; + +public abstract class QueueJob implements Job { + private final KList queue; + private int totalWork; + private int completed; + + public QueueJob() + { + totalWork = 0; + completed = 0; + queue = new KList<>(); + } + + public void queue(T t) + { + queue.add(t); + totalWork++; + } + + public void queue(KList f) + { + queue.addAll(f); + totalWork += f.size(); + } + + public abstract void execute(T t); + + @Override + public void execute() { + totalWork = queue.size(); + while(queue.isNotEmpty()) + { + execute(queue.pop()); + completeWork(); + } + } + + @Override + public void completeWork() { + completed++; + } + + @Override + public int getTotalWork() { + return totalWork; + } + + @Override + public int getWorkCompleted() { + return completed; + } +} diff --git a/src/main/java/com/volmit/iris/util/scheduling/jobs/SingleJob.java b/src/main/java/com/volmit/iris/util/scheduling/jobs/SingleJob.java new file mode 100644 index 000000000..c422b0ecd --- /dev/null +++ b/src/main/java/com/volmit/iris/util/scheduling/jobs/SingleJob.java @@ -0,0 +1,58 @@ +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2021 Arcane Arts (Volmit Software) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.volmit.iris.util.scheduling.jobs; + +public class SingleJob implements Job{ + private boolean done; + private final String name; + private final Runnable runnable; + + public SingleJob(String name, Runnable runnable) + { + this.name = name; + done = false; + this.runnable = runnable; + } + + @Override + public String getName() { + return name; + } + + @Override + public void execute() { + runnable.run(); + completeWork(); + } + + @Override + public void completeWork() { + done = true; + } + + @Override + public int getTotalWork() { + return 1; + } + + @Override + public int getWorkCompleted() { + return done ? 1 : 0; + } +}