diff --git a/src/main/java/com/volmit/iris/Iris.java b/src/main/java/com/volmit/iris/Iris.java index 0d27ae8c4..9a5216ff4 100644 --- a/src/main/java/com/volmit/iris/Iris.java +++ b/src/main/java/com/volmit/iris/Iris.java @@ -26,11 +26,14 @@ import org.bukkit.event.HandlerList; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.util.Vector; import org.zeroturnaround.zip.ZipUtil; import com.google.gson.Gson; +import com.volmit.iris.command.CommandIris; +import com.volmit.iris.command.PermissionIris; +import com.volmit.iris.command.util.MortarPlugin; +import com.volmit.iris.command.util.Permission; import com.volmit.iris.generator.IrisChunkGenerator; import com.volmit.iris.layer.post.PostFloatingNibDeleter; import com.volmit.iris.layer.post.PostNibSmoother; @@ -72,11 +75,12 @@ import com.volmit.iris.util.RollingSequence; import com.volmit.iris.util.ScoreDirection; import com.volmit.iris.wand.WandController; -public class Iris extends JavaPlugin implements BoardProvider +public class Iris extends MortarPlugin implements BoardProvider { public static KList executors = new KList<>(); public static Iris instance; public static IrisDataManager data; + public static ProjectManager proj; public static IrisHotloadManager hotloader; public static WandController wand; private static String last = ""; @@ -87,11 +91,35 @@ public class Iris extends JavaPlugin implements BoardProvider public RollingSequence tp = new RollingSequence(100); public static KList> postProcessors; + @Permission + public static PermissionIris perm; + + @com.volmit.iris.command.util.Command + public CommandIris commandIris; + public Iris() { IO.delete(new File("iris")); } + @Override + public void start() + { + + } + + @Override + 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 void onEnable() { instance = this; @@ -99,6 +127,7 @@ public class Iris extends JavaPlugin implements BoardProvider data = new IrisDataManager(getDataFolder()); wand = new WandController(); postProcessors = loadPostProcessors(); + proj = new ProjectManager(); manager = new BoardManager(this, BoardSettings.builder().boardProvider(this).scoreDirection(ScoreDirection.UP).build()); J.a(() -> @@ -113,6 +142,31 @@ public class Iris extends JavaPlugin implements BoardProvider e.printStackTrace(); } }); + super.onEnable(); + } + + public void onDisable() + { + proj.close(); + + for(GroupedExecutor i : executors) + { + i.close(); + } + + for(World i : Bukkit.getWorlds()) + { + if(i.getGenerator() instanceof IrisChunkGenerator) + { + ((IrisChunkGenerator) i).close(); + } + } + + executors.clear(); + manager.onDisable(); + Bukkit.getScheduler().cancelTasks(this); + HandlerList.unregisterAll((Plugin) this); + super.onDisable(); } @Override @@ -227,31 +281,15 @@ public class Iris extends JavaPlugin implements BoardProvider } } - public void onDisable() - { - for(GroupedExecutor i : executors) - { - i.close(); - } - - for(World i : Bukkit.getWorlds()) - { - if(i.getGenerator() instanceof IrisChunkGenerator) - { - ((IrisChunkGenerator) i).close(); - } - } - - executors.clear(); - manager.onDisable(); - Bukkit.getScheduler().cancelTasks(this); - HandlerList.unregisterAll((Plugin) this); - } - @SuppressWarnings("deprecation") @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if(super.onCommand(sender, command, label, args)) + { + return true; + } + if(command.getName().equals("iris")) { if(args.length == 0) @@ -805,22 +843,33 @@ public class Iris extends JavaPlugin implements BoardProvider String dim = "overworld"; boolean fast = false; - + boolean first = true; + int tc = (int) Math.max(Runtime.getRuntime().availableProcessors(), 4); for(String i : args) { + if(first) + { + first = false; + continue; + } + + if(i.startsWith("-t:")) + { + tc = Integer.valueOf(i.split("\\Q:\\E")[1]); + continue; + } + if(i.equals("--fast") || i.equals("-f")) { fast = true; + continue; } - else - { - dim = args[1]; - } + dim = i; } String dimm = dim; - + int tcc = tc; boolean ff = fast; Bukkit.getScheduler().scheduleSyncDelayedTask(this, () -> { @@ -850,11 +899,11 @@ public class Iris extends JavaPlugin implements BoardProvider imsg(i, "Creating Iris " + dimm + "..."); } - int tc = (int) Math.max(Runtime.getRuntime().availableProcessors() * IrisSettings.get().threadAggression, 4); - IrisChunkGenerator gx = new IrisChunkGenerator(dimm, tc); + IrisChunkGenerator gx = new IrisChunkGenerator(dimm, tcc); + gx.setDev(true); gx.setFastPregen(ff); - info("Generating with " + tc + " threads per chunk"); + info("Generating with " + tcc + " threads per chunk"); O done = new O(); done.set(false); @@ -910,7 +959,7 @@ public class Iris extends JavaPlugin implements BoardProvider return true; } - return false; + return super.onCommand(sender, command, label, args); } public void imsg(CommandSender s, String msg) diff --git a/src/main/java/com/volmit/iris/IrisSettings.java b/src/main/java/com/volmit/iris/IrisSettings.java index a82c26456..58ea1b1f6 100644 --- a/src/main/java/com/volmit/iris/IrisSettings.java +++ b/src/main/java/com/volmit/iris/IrisSettings.java @@ -8,8 +8,8 @@ public class IrisSettings public static transient IrisSettings settings; @DontObfuscate - @Desc("Iris creates (aggression X CPU threads) generator threads.") - public double threadAggression = 2; + @Desc("Iris generator threads (must be 2 or higher).") + public int threads = 8; @DontObfuscate @Desc("Compress parallax data in memory to reduce memory usage in exchange for more cpu usage.") diff --git a/src/main/java/com/volmit/iris/ProjectManager.java b/src/main/java/com/volmit/iris/ProjectManager.java new file mode 100644 index 000000000..50d8cb264 --- /dev/null +++ b/src/main/java/com/volmit/iris/ProjectManager.java @@ -0,0 +1,154 @@ +package com.volmit.iris; + +import java.awt.Desktop; +import java.io.File; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.WorldCreator; +import org.bukkit.WorldType; + +import com.volmit.iris.command.util.MortarSender; +import com.volmit.iris.generator.IrisChunkGenerator; +import com.volmit.iris.object.IrisDimension; +import com.volmit.iris.util.Form; +import com.volmit.iris.util.IO; +import com.volmit.iris.util.J; +import com.volmit.iris.util.O; + +import lombok.Data; + +@Data +public class ProjectManager +{ + private IrisChunkGenerator currentProject; + + public ProjectManager() + { + + } + + public boolean isProjectOpen() + { + return currentProject != null; + } + + public void open(MortarSender sender, String dimm) + { + open(sender, dimm, () -> + { + }); + } + + public void open(MortarSender sender, String dimm, Runnable onDone) + { + IrisDimension d = Iris.data.getDimensionLoader().load(dimm); + + if(d == null) + { + sender.sendMessage("Can't find dimension: " + dimm); + return; + } + + if(isProjectOpen()) + { + sender.sendMessage("Please Wait. Closing Current Project..."); + close(); + } + + sender.sendMessage("Loading " + dimm + "..."); + IrisChunkGenerator gx = new IrisChunkGenerator(dimm, IrisSettings.get().threads); + currentProject = gx; + gx.setDev(true); + sender.sendMessage("Generating with " + IrisSettings.get().threads + " threads per chunk"); + O done = new O(); + done.set(false); + + J.a(() -> + { + double last = 0; + int req = 740; + while(!done.get()) + { + boolean derp = false; + double v = (double) gx.getGenerated() / (double) req; + + if(last > v || v > 1) + { + derp = true; + v = last; + } + + else + { + last = v; + } + + sender.sendMessage("Generating " + Form.pc(v) + (derp ? " (Waiting on Server...)" : "")); + J.sleep(3000); + } + }); + + World world = Bukkit.createWorld(new WorldCreator("iris/" + UUID.randomUUID()).seed(1337).generator(gx).generateStructures(false).type(WorldType.NORMAL).environment(d.getEnvironment())); + done.set(true); + sender.sendMessage("Generating 100%"); + + if(sender.isPlayer()) + { + sender.player().teleport(new Location(world, 150, 150, 275)); + } + + Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> + { + sender.sendMessage("Hotloading Active! Change any files and watch them appear as you load new chunks!"); + + if(sender.isPlayer()) + { + sender.player().setGameMode(GameMode.SPECTATOR); + } + + J.attemptAsync(() -> + { + try + { + File f = d.getLoadFile().getParentFile().getParentFile(); + + for(File i : f.listFiles()) + { + if(i.getName().endsWith(".code-workspace")) + { + Desktop.getDesktop().open(i); + break; + } + } + } + + catch(Throwable e) + { + e.printStackTrace(); + } + }); + onDone.run(); + }, 0); + } + + public void close() + { + if(isProjectOpen()) + { + currentProject.close(); + File folder = currentProject.getWorld().getWorldFolder(); + Bukkit.unloadWorld(currentProject.getWorld(), false); + currentProject = null; + Iris.data.getObjectLoader().clearCache(); + Iris.data.getBiomeLoader().clearCache(); + Iris.data.getRegionLoader().clearCache(); + Iris.data.getGeneratorLoader().clearCache(); + Iris.data.getDimensionLoader().clearCache(); + J.attemptAsync(() -> IO.delete(folder)); + } + } +} diff --git a/src/main/java/com/volmit/iris/command/CommandIris.java b/src/main/java/com/volmit/iris/command/CommandIris.java new file mode 100644 index 000000000..82b4e2757 --- /dev/null +++ b/src/main/java/com/volmit/iris/command/CommandIris.java @@ -0,0 +1,32 @@ +package com.volmit.iris.command; + +import com.volmit.iris.Iris; +import com.volmit.iris.command.util.Command; +import com.volmit.iris.command.util.MortarCommand; +import com.volmit.iris.command.util.MortarSender; + +public class CommandIris extends MortarCommand +{ + @Command + private CommandIrisStudio studio; + + public CommandIris() + { + super("iris", "ir", "irs"); + requiresPermission(Iris.perm); + } + + @Override + public boolean handle(MortarSender sender, String[] args) + { + sender.sendMessage("Iris v" + Iris.instance.getDescription().getVersion() + " by Volmit Software"); + printHelp(sender); + return true; + } + + @Override + protected String getArgsUsage() + { + return ""; + } +} diff --git a/src/main/java/com/volmit/iris/command/CommandIrisStudio.java b/src/main/java/com/volmit/iris/command/CommandIrisStudio.java new file mode 100644 index 000000000..66ec6d3d4 --- /dev/null +++ b/src/main/java/com/volmit/iris/command/CommandIrisStudio.java @@ -0,0 +1,41 @@ +package com.volmit.iris.command; + +import com.volmit.iris.Iris; +import com.volmit.iris.command.util.Command; +import com.volmit.iris.command.util.MortarCommand; +import com.volmit.iris.command.util.MortarSender; + +public class CommandIrisStudio extends MortarCommand +{ + @Command + private CommandIrisStudioCreate create; + + @Command + private CommandIrisStudioOpen open; + + @Command + private CommandIrisStudioClose close; + + @Command + private CommandIrisStudioList list; + + public CommandIrisStudio() + { + super("studio", "std"); + requiresPermission(Iris.perm.studio); + } + + @Override + public boolean handle(MortarSender sender, String[] args) + { + sender.sendMessage("Iris Studio Commands"); + printHelp(sender); + return true; + } + + @Override + protected String getArgsUsage() + { + return "[subcommand]"; + } +} diff --git a/src/main/java/com/volmit/iris/command/CommandIrisStudioClose.java b/src/main/java/com/volmit/iris/command/CommandIrisStudioClose.java new file mode 100644 index 000000000..76a648c56 --- /dev/null +++ b/src/main/java/com/volmit/iris/command/CommandIrisStudioClose.java @@ -0,0 +1,71 @@ +package com.volmit.iris.command; + +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.entity.Player; + +import com.volmit.iris.Iris; +import com.volmit.iris.command.util.MortarCommand; +import com.volmit.iris.command.util.MortarSender; + +public class CommandIrisStudioClose extends MortarCommand +{ + public CommandIrisStudioClose() + { + super("close", "x"); + requiresPermission(Iris.perm.studio); + setDescription("Close the existing dimension"); + } + + @Override + public boolean handle(MortarSender sender, String[] args) + { + if(!Iris.proj.isProjectOpen()) + { + sender.sendMessage("No open projects."); + return true; + } + + if(sender.isPlayer()) + { + World f = null; + + for(World i : Bukkit.getWorlds()) + { + if(i.getWorldFolder().getAbsolutePath().equals(Iris.proj.getCurrentProject().getWorld().getWorldFolder().getAbsolutePath())) + { + continue; + } + + f = i; + break; + } + + if(f == null) + { + for(Player i : Iris.proj.getCurrentProject().getWorld().getPlayers()) + { + i.kickPlayer("Project Closing, No other world to put you in. Rejoin Please!"); + } + } + + else + { + for(Player i : Iris.proj.getCurrentProject().getWorld().getPlayers()) + { + i.teleport(f.getSpawnLocation()); + } + } + } + + Iris.proj.close(); + sender.sendMessage("Projects Closed & Caches Cleared!"); + return true; + } + + @Override + protected String getArgsUsage() + { + return ""; + } +} diff --git a/src/main/java/com/volmit/iris/command/CommandIrisStudioCreate.java b/src/main/java/com/volmit/iris/command/CommandIrisStudioCreate.java new file mode 100644 index 000000000..b68c58d4a --- /dev/null +++ b/src/main/java/com/volmit/iris/command/CommandIrisStudioCreate.java @@ -0,0 +1,134 @@ +package com.volmit.iris.command; + +import java.io.IOException; + +import com.google.gson.Gson; +import com.volmit.iris.Iris; +import com.volmit.iris.command.util.MortarCommand; +import com.volmit.iris.command.util.MortarSender; +import com.volmit.iris.object.InterpolationMethod; +import com.volmit.iris.object.IrisBiome; +import com.volmit.iris.object.IrisBiomeGeneratorLink; +import com.volmit.iris.object.IrisDimension; +import com.volmit.iris.object.IrisGenerator; +import com.volmit.iris.object.IrisNoiseGenerator; +import com.volmit.iris.object.IrisRegion; +import com.volmit.iris.util.Form; +import com.volmit.iris.util.IO; +import com.volmit.iris.util.JSONException; +import com.volmit.iris.util.JSONObject; + +import net.md_5.bungee.api.ChatColor; + +public class CommandIrisStudioCreate extends MortarCommand +{ + public CommandIrisStudioCreate() + { + super("create", "new"); + requiresPermission(Iris.perm.studio); + setDescription("Create a new project & open it."); + } + + @Override + public boolean handle(MortarSender sender, String[] args) + { + if(args.length != 1) + { + sender.sendMessage("Please use a lowercase name with hyphens (-) for spaces."); + sender.sendMessage("I.e. /iris std new " + ChatColor.BOLD + "aether"); + return true; + } + + IrisDimension dimension = new IrisDimension(); + dimension.setLoadKey(args[0]); + dimension.setName(Form.capitalizeWords(args[0].replaceAll("\\Q-\\E", " "))); + sender.sendMessage("Creating New Project \"" + dimension.getName() + "\"..."); + IrisRegion exampleRegion = new IrisRegion(); + exampleRegion.setName("Example Region"); + exampleRegion.setLoadKey("example-region"); + IrisBiome exampleLand1 = new IrisBiome(); + exampleLand1.setName("Example Land 1"); + exampleLand1.setLoadKey("land-1"); + IrisBiome exampleShore1 = new IrisBiome(); + exampleShore1.setName("Example Shore"); + exampleShore1.setLoadKey("shore"); + IrisBiome exampleOcean1 = new IrisBiome(); + exampleOcean1.setName("Example Sea"); + exampleOcean1.setLoadKey("sea"); + IrisBiome exampleLand2 = new IrisBiome(); + exampleLand2.setName("Example Land 2"); + exampleLand2.setLoadKey("land-2"); + exampleLand2.setRarity(4); + dimension.setSeaZoom(1); + dimension.setLandZoom(1.5); + IrisGenerator gen = new IrisGenerator(); + IrisNoiseGenerator gg = new IrisNoiseGenerator(true); + gen.setInterpolationFunction(InterpolationMethod.HERMITE); + gen.setInterpolationScale(185); + gen.getComposite().add(gg); + gen.setLoadKey("example-generator"); + IrisBiomeGeneratorLink b1 = new IrisBiomeGeneratorLink(); + b1.setGenerator(gen.getLoadKey()); + b1.setMin(3); + b1.setMax(7); + IrisBiomeGeneratorLink b2 = new IrisBiomeGeneratorLink(); + b1.setGenerator(gen.getLoadKey()); + b1.setMin(12); + b1.setMax(35); + IrisBiomeGeneratorLink b3 = new IrisBiomeGeneratorLink(); + b1.setGenerator(gen.getLoadKey()); + b1.setMin(-1); + b1.setMax(1); + IrisBiomeGeneratorLink b4 = new IrisBiomeGeneratorLink(); + b1.setGenerator(gen.getLoadKey()); + b1.setMin(-5); + b1.setMax(-38); + exampleLand2.getLayers().get(0).getPalette().clear(); + exampleLand2.getLayers().get(0).getPalette().add("RED_SAND"); + exampleShore1.getLayers().get(0).getPalette().clear(); + exampleShore1.getLayers().get(0).getPalette().add("SAND"); + exampleOcean1.getLayers().get(0).getPalette().clear(); + exampleOcean1.getLayers().get(0).getPalette().add("SAND"); + exampleLand1.getGenerators().clear(); + exampleLand1.getGenerators().add(b1); + exampleLand2.getGenerators().clear(); + exampleLand2.getGenerators().add(b2); + exampleShore1.getGenerators().clear(); + exampleShore1.getGenerators().add(b3); + exampleOcean1.getGenerators().clear(); + exampleOcean1.getGenerators().add(b4); + exampleRegion.getLandBiomes().add(exampleLand1.getLoadKey()); + exampleRegion.getLandBiomes().add(exampleLand2.getLoadKey()); + exampleRegion.getShoreBiomes().add(exampleShore1.getLoadKey()); + exampleRegion.getSeaBiomes().add(exampleOcean1.getLoadKey()); + dimension.getRegions().add(exampleRegion.getLoadKey()); + + try + { + String g = "{\"folders\": [{\"path\": \".\"}],\"settings\": {\"workbench.colorTheme\": \"Monokai\",\"workbench.preferredHighContrastColorTheme\": \"Solarized Dark\",\"workbench.preferredDarkColorTheme\": \"Solarized Dark\",\"workbench.statusBar.visible\": false,\"workbench.tips.enabled\": false,\"workbench.tree.indent\": 24,\"files.autoSave\": \"onFocusChange\"}}"; + IO.writeAll(Iris.instance.getDataFile("packs", dimension.getLoadKey(), "dimensions", dimension.getLoadKey() + ".json"), new JSONObject(new Gson().toJson(dimension)).toString(4)); + IO.writeAll(Iris.instance.getDataFile("packs", dimension.getLoadKey(), "regions", exampleRegion.getLoadKey() + ".json"), new JSONObject(new Gson().toJson(exampleRegion)).toString(4)); + IO.writeAll(Iris.instance.getDataFile("packs", dimension.getLoadKey(), "biomes", exampleLand1.getLoadKey() + ".json"), new JSONObject(new Gson().toJson(exampleLand1)).toString(4)); + IO.writeAll(Iris.instance.getDataFile("packs", dimension.getLoadKey(), "biomes", exampleLand2.getLoadKey() + ".json"), new JSONObject(new Gson().toJson(exampleLand2)).toString(4)); + 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"), new JSONObject(g).toString(4)); + Iris.proj.open(sender, dimension.getName()); + } + + catch(JSONException | IOException e) + { + sender.sendMessage("Failed! Check the console."); + e.printStackTrace(); + } + + return true; + } + + @Override + protected String getArgsUsage() + { + return "[dimension]"; + } +} diff --git a/src/main/java/com/volmit/iris/command/CommandIrisStudioList.java b/src/main/java/com/volmit/iris/command/CommandIrisStudioList.java new file mode 100644 index 000000000..1f1ed9c0a --- /dev/null +++ b/src/main/java/com/volmit/iris/command/CommandIrisStudioList.java @@ -0,0 +1,53 @@ +package com.volmit.iris.command; + +import java.io.File; + +import com.volmit.iris.Iris; +import com.volmit.iris.command.util.MortarCommand; +import com.volmit.iris.command.util.MortarSender; +import com.volmit.iris.object.IrisDimension; + +public class CommandIrisStudioList extends MortarCommand +{ + public CommandIrisStudioList() + { + super("list", "l"); + requiresPermission(Iris.perm.studio); + setDescription("List projects that can be opened."); + } + + @Override + public boolean handle(MortarSender sender, String[] args) + { + int m = 0; + for(File i : Iris.data.getDimensionLoader().getFolders()) + { + for(File j : i.listFiles()) + { + if(j.isFile() && j.getName().endsWith(".json")) + { + try + { + m++; + IrisDimension d = Iris.data.getDimensionLoader().load(j.getName().replaceAll("\\Q.json\\E", "")); + sender.sendMessage("- " + d.getLoadKey() + " (" + d.getName() + ")"); + } + catch(Throwable e) + { + + } + } + } + } + + sender.sendMessage("Found " + m + " project" + (m == 1 ? "" : "s")); + + return true; + } + + @Override + protected String getArgsUsage() + { + return ""; + } +} diff --git a/src/main/java/com/volmit/iris/command/CommandIrisStudioOpen.java b/src/main/java/com/volmit/iris/command/CommandIrisStudioOpen.java new file mode 100644 index 000000000..98fa783ab --- /dev/null +++ b/src/main/java/com/volmit/iris/command/CommandIrisStudioOpen.java @@ -0,0 +1,33 @@ +package com.volmit.iris.command; + +import com.volmit.iris.Iris; +import com.volmit.iris.command.util.MortarCommand; +import com.volmit.iris.command.util.MortarSender; + +public class CommandIrisStudioOpen extends MortarCommand +{ + public CommandIrisStudioOpen() + { + super("open", "o"); + requiresPermission(Iris.perm.studio); + setDescription("Create a new temporary world to design a dimension."); + } + + @Override + public boolean handle(MortarSender sender, String[] args) + { + if(args.length != 1) + { + sender.sendMessage("/iris std open (file name without .json)"); + } + + Iris.proj.open(sender, args[0]); + return true; + } + + @Override + protected String getArgsUsage() + { + return "[dimension]"; + } +} diff --git a/src/main/java/com/volmit/iris/command/PermissionIris.java b/src/main/java/com/volmit/iris/command/PermissionIris.java new file mode 100644 index 000000000..a522aae97 --- /dev/null +++ b/src/main/java/com/volmit/iris/command/PermissionIris.java @@ -0,0 +1,28 @@ +package com.volmit.iris.command; + +import com.volmit.iris.command.util.MortarPermission; +import com.volmit.iris.command.util.Permission; + +public class PermissionIris extends MortarPermission +{ + @Permission + public PermissionIrisStudio studio; + + @Override + protected String getNode() + { + return "iris"; + } + + @Override + public String getDescription() + { + return "Iris Permissions"; + } + + @Override + public boolean isDefault() + { + return false; + } +} diff --git a/src/main/java/com/volmit/iris/command/PermissionIrisStudio.java b/src/main/java/com/volmit/iris/command/PermissionIrisStudio.java new file mode 100644 index 000000000..d76e2872c --- /dev/null +++ b/src/main/java/com/volmit/iris/command/PermissionIrisStudio.java @@ -0,0 +1,24 @@ +package com.volmit.iris.command; + +import com.volmit.iris.command.util.MortarPermission; + +public class PermissionIrisStudio extends MortarPermission +{ + @Override + protected String getNode() + { + return "studio"; + } + + @Override + public String getDescription() + { + return "Iris Studio Permissions"; + } + + @Override + public boolean isDefault() + { + return false; + } +} diff --git a/src/main/java/com/volmit/iris/command/util/Command.java b/src/main/java/com/volmit/iris/command/util/Command.java new file mode 100644 index 000000000..4fa425439 --- /dev/null +++ b/src/main/java/com/volmit/iris/command/util/Command.java @@ -0,0 +1,14 @@ +package com.volmit.iris.command.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(FIELD) +public @interface Command +{ + String value() default ""; +} diff --git a/src/main/java/com/volmit/iris/command/util/Control.java b/src/main/java/com/volmit/iris/command/util/Control.java new file mode 100644 index 000000000..1c7330ed9 --- /dev/null +++ b/src/main/java/com/volmit/iris/command/util/Control.java @@ -0,0 +1,14 @@ +package com.volmit.iris.command.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(FIELD) +public @interface Control +{ + +} diff --git a/src/main/java/com/volmit/iris/command/util/Controller.java b/src/main/java/com/volmit/iris/command/util/Controller.java new file mode 100644 index 000000000..53e03d548 --- /dev/null +++ b/src/main/java/com/volmit/iris/command/util/Controller.java @@ -0,0 +1,70 @@ +package com.volmit.iris.command.util; + +import com.volmit.iris.Iris; + +public abstract class Controller implements IController +{ + private int tickRate; + private String name; + + public Controller() + { + name = getClass().getSimpleName().replaceAll("Controller", "") + " Controller"; + tickRate = -1; + } + + protected void setTickRate(int rate) + { + this.tickRate = rate; + } + + protected void disableTicking() + { + setTickRate(-1); + } + + @Override + public void l(Object l) + { + Iris.info("[" + getName() + "]: " + l); + } + + @Override + public void w(Object l) + { + Iris.warn("[" + getName() + "]: " + l); + } + + @Override + public void f(Object l) + { + Iris.error("[" + getName() + "]: " + l); + } + + @Override + public void v(Object l) + { + Iris.verbose("[" + getName() + "]: " + l); + } + + @Override + public String getName() + { + return name; + } + + @Override + public abstract void start(); + + @Override + public abstract void stop(); + + @Override + public abstract void tick(); + + @Override + public int getTickInterval() + { + return tickRate; + } +} diff --git a/src/main/java/com/volmit/iris/command/util/ICommand.java b/src/main/java/com/volmit/iris/command/util/ICommand.java new file mode 100644 index 000000000..22f1dad09 --- /dev/null +++ b/src/main/java/com/volmit/iris/command/util/ICommand.java @@ -0,0 +1,55 @@ +package com.volmit.iris.command.util; + +import com.volmit.iris.util.KList; + +/** + * Represents a pawn command + * + * @author cyberpwn + * + */ +public interface ICommand +{ + public KList getRequiredPermissions(); + + /** + * Get the name of this command (node) + * + * @return the node + */ + public String getNode(); + + /** + * Get all (realized) nodes of this command + * + * @return the nodes + */ + public KList getNodes(); + + /** + * Get all (every) node in this command + * + * @return all nodes + */ + public KList getAllNodes(); + + /** + * Add a node to this command + * + * @param node + * the node + */ + public void addNode(String node); + + /** + * Handle a command. If this is a subcommand, parameters after the subcommand + * will be adapted in args for you + * + * @param sender + * the volume sender (pre-tagged) + * @param args + * the arguments after this command node + * @return return true to mark it as handled + */ + public boolean handle(MortarSender sender, String[] args); +} diff --git a/src/main/java/com/volmit/iris/command/util/IController.java b/src/main/java/com/volmit/iris/command/util/IController.java new file mode 100644 index 000000000..52acb0f83 --- /dev/null +++ b/src/main/java/com/volmit/iris/command/util/IController.java @@ -0,0 +1,24 @@ +package com.volmit.iris.command.util; + +import org.bukkit.event.Listener; + +public interface IController extends Listener +{ + public String getName(); + + public void start(); + + public void stop(); + + public void tick(); + + public int getTickInterval(); + + public void l(Object l); + + public void w(Object l); + + public void f(Object l); + + public void v(Object l); +} diff --git a/src/main/java/com/volmit/iris/command/util/Instance.java b/src/main/java/com/volmit/iris/command/util/Instance.java new file mode 100644 index 000000000..7c4c2ba6c --- /dev/null +++ b/src/main/java/com/volmit/iris/command/util/Instance.java @@ -0,0 +1,14 @@ +package com.volmit.iris.command.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(FIELD) +public @interface Instance +{ + +} diff --git a/src/main/java/com/volmit/iris/command/util/MortarCommand.java b/src/main/java/com/volmit/iris/command/util/MortarCommand.java new file mode 100644 index 000000000..be0a90d58 --- /dev/null +++ b/src/main/java/com/volmit/iris/command/util/MortarCommand.java @@ -0,0 +1,180 @@ +package com.volmit.iris.command.util; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; + +import org.bukkit.ChatColor; + +import com.volmit.iris.util.KList; + +/** + * Represents a pawn command + * + * @author cyberpwn + * + */ +public abstract class MortarCommand implements ICommand +{ + private KList children; + private KList nodes; + private KList requiredPermissions; + private String node; + private String category; + private String description; + + /** + * Override this with a super constructor as most commands shouldnt change these + * parameters + * + * @param node + * the node (primary node) i.e. volume + * @param nodes + * the aliases. i.e. v, vol, bile + */ + public MortarCommand(String node, String... nodes) + { + category = ""; + this.node = node; + this.nodes = new KList(nodes); + requiredPermissions = new KList<>(); + children = buildChildren(); + description = "No Description"; + } + + public void printHelp(MortarSender sender) + { + boolean b = false; + + for(MortarCommand i : getChildren()) + { + for(String j : i.getRequiredPermissions()) + { + if(!sender.hasPermission(j)) + { + continue; + } + } + b = true; + sender.sendMessage("/" + ChatColor.GREEN + i.getAllNodes().toString(",") + " " + ChatColor.WHITE + getArgsUsage() + ChatColor.GRAY + " - " + getDescription()); + } + + if(!b) + { + sender.sendMessage("There are either no sub-commands or you do not have permission to use them."); + } + } + + protected abstract String getArgsUsage(); + + public String getDescription() + { + return description; + } + + protected void setDescription(String description) + { + this.description = description; + } + + protected void requiresPermission(MortarPermission node) + { + if(node == null) + { + return; + } + + requiresPermission(node.toString()); + } + + protected void requiresPermission(String node) + { + if(node == null) + { + return; + } + + requiredPermissions.add(node); + } + + @Override + public String getNode() + { + return node; + } + + @Override + public KList getNodes() + { + return nodes; + } + + @Override + public KList getAllNodes() + { + return getNodes().copy().qadd(getNode()); + } + + @Override + public void addNode(String node) + { + getNodes().add(node); + } + + public KList getChildren() + { + return children; + } + + private KList buildChildren() + { + KList p = new KList<>(); + + for(Field i : getClass().getDeclaredFields()) + { + if(i.isAnnotationPresent(Command.class)) + { + try + { + i.setAccessible(true); + MortarCommand pc = (MortarCommand) i.getType().getConstructor().newInstance(); + Command c = i.getAnnotation(Command.class); + + if(!c.value().trim().isEmpty()) + { + pc.setCategory(c.value().trim()); + } + + else + { + pc.setCategory(getCategory()); + } + + p.add(pc); + } + + catch(IllegalArgumentException | IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException | SecurityException e) + { + e.printStackTrace(); + } + } + } + + return p; + } + + @Override + public KList getRequiredPermissions() + { + return requiredPermissions; + } + + public String getCategory() + { + return category; + } + + public void setCategory(String category) + { + this.category = category; + } +} diff --git a/src/main/java/com/volmit/iris/command/util/MortarPermission.java b/src/main/java/com/volmit/iris/command/util/MortarPermission.java new file mode 100644 index 000000000..1557493bd --- /dev/null +++ b/src/main/java/com/volmit/iris/command/util/MortarPermission.java @@ -0,0 +1,100 @@ +package com.volmit.iris.command.util; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; + +import org.bukkit.command.CommandSender; + +import com.volmit.iris.util.KList; + +public abstract class MortarPermission +{ + private MortarPermission parent; + + public MortarPermission() + { + for(Field i : getClass().getDeclaredFields()) + { + if(i.isAnnotationPresent(Permission.class)) + { + try + { + MortarPermission px = (MortarPermission) i.getType().getConstructor().newInstance(); + px.setParent(this); + i.set(Modifier.isStatic(i.getModifiers()) ? null : this, px); + } + + catch(IllegalArgumentException | IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException | SecurityException e) + { + e.printStackTrace(); + } + } + } + } + + public KList getChildren() + { + KList p = new KList<>(); + + for(Field i : getClass().getDeclaredFields()) + { + if(i.isAnnotationPresent(Permission.class)) + { + try + { + p.add((MortarPermission) i.get(Modifier.isStatic(i.getModifiers()) ? null : this)); + } + + catch(IllegalArgumentException | IllegalAccessException | SecurityException e) + { + e.printStackTrace(); + } + } + } + + return p; + } + + public String getFullNode() + { + if(hasParent()) + { + return getParent().getFullNode() + "." + getNode(); + } + + return getNode(); + } + + protected abstract String getNode(); + + public abstract String getDescription(); + + public abstract boolean isDefault(); + + @Override + public String toString() + { + return getFullNode(); + } + + public boolean hasParent() + { + return getParent() != null; + } + + public MortarPermission getParent() + { + return parent; + } + + public void setParent(MortarPermission parent) + { + this.parent = parent; + } + + public boolean has(CommandSender sender) + { + return sender.hasPermission(getFullNode()); + } +} diff --git a/src/main/java/com/volmit/iris/command/util/MortarPlugin.java b/src/main/java/com/volmit/iris/command/util/MortarPlugin.java new file mode 100644 index 000000000..8f614dab5 --- /dev/null +++ b/src/main/java/com/volmit/iris/command/util/MortarPlugin.java @@ -0,0 +1,620 @@ +package com.volmit.iris.command.util; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.util.Iterator; +import java.util.Map; + +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandMap; +import org.bukkit.command.CommandSender; +import org.bukkit.command.PluginCommand; +import org.bukkit.command.SimpleCommandMap; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.permissions.PermissionDefault; +import org.bukkit.plugin.java.JavaPlugin; + +import com.volmit.iris.Iris; +import com.volmit.iris.util.IO; +import com.volmit.iris.util.J; +import com.volmit.iris.util.KList; +import com.volmit.iris.util.KMap; +import com.volmit.iris.util.M; + +public abstract class MortarPlugin extends JavaPlugin implements Listener +{ + private KMap, VirtualCommand> commands; + private KList commandCache; + private KList permissionCache; + private KMap controllers; + private KList cachedControllers; + private KMap, IController> cachedClassControllers; + + public void l(Object l) + { + Iris.info("[" + getName() + "]: " + l); + } + + public void w(Object l) + { + Iris.warn("[" + getName() + "]: " + l); + } + + public void f(Object l) + { + Iris.error("[" + getName() + "]: " + l); + } + + public void v(Object l) + { + Iris.verbose("[" + getName() + "]: " + l); + } + + public void onEnable() + { + registerInstance(); + registerPermissions(); + registerCommands(); + registerControllers(); + Bukkit.getScheduler().scheduleSyncRepeatingTask(this, this::tickControllers, 0, 0); + J.a(() -> outputInfo()); + registerListener(this); + start(); + } + + public void unregisterAll() + { + stopControllers(); + unregisterListeners(); + unregisterCommands(); + unregisterPermissions(); + unregisterInstance(); + } + + private void outputInfo() + { + try + { + IO.delete(getDataFolder("info")); + getDataFolder("info").mkdirs(); + outputPluginInfo(); + outputCommandInfo(); + outputPermissionInfo(); + } + + catch(Throwable e) + { + + } + } + + private void outputPermissionInfo() throws IOException + { + FileConfiguration fc = new YamlConfiguration(); + + for(MortarPermission i : permissionCache) + { + chain(i, fc); + } + + fc.save(getDataFile("info", "permissions.yml")); + } + + private void chain(MortarPermission i, FileConfiguration fc) + { + KList ff = new KList(); + + for(MortarPermission j : i.getChildren()) + { + ff.add(j.getFullNode()); + } + + fc.set(i.getFullNode().replaceAll("\\Q.\\E", ",") + "." + "description", i.getDescription()); + fc.set(i.getFullNode().replaceAll("\\Q.\\E", ",") + "." + "default", i.isDefault()); + fc.set(i.getFullNode().replaceAll("\\Q.\\E", ",") + "." + "children", ff); + + for(MortarPermission j : i.getChildren()) + { + chain(j, fc); + } + } + + private void outputCommandInfo() throws IOException + { + FileConfiguration fc = new YamlConfiguration(); + + for(MortarCommand i : commandCache) + { + chain(i, "/", fc); + } + + fc.save(getDataFile("info", "commands.yml")); + } + + private void chain(MortarCommand i, String c, FileConfiguration fc) + { + String n = c + (c.length() == 1 ? "" : " ") + i.getNode(); + fc.set(n + "." + "description", i.getDescription()); + fc.set(n + "." + "required-permissions", i.getRequiredPermissions()); + fc.set(n + "." + "aliases", i.getAllNodes()); + + for(MortarCommand j : i.getChildren()) + { + chain(j, n, fc); + } + } + + private void outputPluginInfo() throws IOException + { + FileConfiguration fc = new YamlConfiguration(); + fc.set("version", getDescription().getVersion()); + fc.set("name", getDescription().getName()); + fc.save(getDataFile("info", "plugin.yml")); + } + + private void registerPermissions() + { + permissionCache = new KList<>(); + + for(Field i : getClass().getDeclaredFields()) + { + if(i.isAnnotationPresent(Permission.class)) + { + try + { + i.setAccessible(true); + MortarPermission pc = (MortarPermission) i.getType().getConstructor().newInstance(); + i.set(Modifier.isStatic(i.getModifiers()) ? null : this, pc); + registerPermission(pc); + permissionCache.add(pc); + v("Registered Permissions " + pc.getFullNode() + " (" + i.getName() + ")"); + } + + catch(IllegalArgumentException | IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException | SecurityException e) + { + w("Failed to register permission (field " + i.getName() + ")"); + e.printStackTrace(); + } + } + } + + for(org.bukkit.permissions.Permission i : computePermissions()) + { + try + { + Bukkit.getPluginManager().addPermission(i); + } + + catch(Throwable e) + { + + } + } + } + + private KList computePermissions() + { + KList g = new KList<>(); + for(Field i : getClass().getDeclaredFields()) + { + if(i.isAnnotationPresent(Permission.class)) + { + try + { + MortarPermission x = (MortarPermission) i.get(Modifier.isStatic(i.getModifiers()) ? null : this); + g.add(toPermission(x)); + g.addAll(computePermissions(x)); + } + + catch(IllegalArgumentException | IllegalAccessException | SecurityException e) + { + e.printStackTrace(); + } + } + } + + return g.removeDuplicates(); + } + + private KList computePermissions(MortarPermission p) + { + KList g = new KList<>(); + + if(p == null) + { + return g; + } + + for(MortarPermission i : p.getChildren()) + { + if(i == null) + { + continue; + } + + g.add(toPermission(i)); + g.addAll(computePermissions(i)); + } + + return g; + } + + private org.bukkit.permissions.Permission toPermission(MortarPermission p) + { + if(p == null) + { + return null; + } + + org.bukkit.permissions.Permission perm = new org.bukkit.permissions.Permission(p.getFullNode() + (p.hasParent() ? "" : ".*")); + perm.setDescription(p.getDescription() == null ? "" : p.getDescription()); + perm.setDefault(p.isDefault() ? PermissionDefault.TRUE : PermissionDefault.OP); + + for(MortarPermission i : p.getChildren()) + { + perm.getChildren().put(i.getFullNode(), true); + } + + return perm; + } + + private void registerPermission(MortarPermission pc) + { + + } + + @Override + public void onDisable() + { + stop(); + Bukkit.getScheduler().cancelTasks(this); + unregisterListener(this); + unregisterAll(); + } + + private void tickControllers() + { + for(IController i : getControllers()) + { + tickController(i); + } + } + + private void tickController(IController i) + { + if(i.getTickInterval() < 0) + { + return; + } + + M.tick++; + if(M.interval(i.getTickInterval())) + { + try + { + i.tick(); + } + + catch(Throwable e) + { + w("Failed to tick controller " + i.getName()); + e.printStackTrace(); + } + } + } + + public KList getControllers() + { + return cachedControllers; + } + + private void registerControllers() + { + controllers = new KMap<>(); + cachedClassControllers = new KMap<>(); + + for(Field i : getClass().getDeclaredFields()) + { + if(i.isAnnotationPresent(Control.class)) + { + try + { + i.setAccessible(true); + IController pc = (IController) i.getType().getConstructor().newInstance(); + registerController(pc); + i.set(this, pc); + v("Registered " + pc.getName() + " (" + i.getName() + ")"); + } + + catch(IllegalArgumentException | IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException | SecurityException e) + { + w("Failed to register controller (field " + i.getName() + ")"); + e.printStackTrace(); + } + } + } + + cachedControllers = controllers.v(); + } + + public IController getController(Class c) + { + return cachedClassControllers.get(c); + } + + private void registerController(IController pc) + { + controllers.put(pc.getName(), pc); + cachedClassControllers.put(pc.getClass(), pc); + registerListener(pc); + + try + { + pc.start(); + v("Started " + pc.getName()); + } + + catch(Throwable e) + { + w("Failed to start controller " + pc.getName()); + e.printStackTrace(); + } + } + + private void registerInstance() + { + for(Field i : getClass().getDeclaredFields()) + { + if(i.isAnnotationPresent(Instance.class)) + { + try + { + i.setAccessible(true); + i.set(Modifier.isStatic(i.getModifiers()) ? null : this, this); + v("Registered Instance " + i.getName()); + } + + catch(IllegalArgumentException | IllegalAccessException | SecurityException e) + { + w("Failed to register instance (field " + i.getName() + ")"); + e.printStackTrace(); + } + } + } + } + + private void unregisterInstance() + { + for(Field i : getClass().getDeclaredFields()) + { + if(i.isAnnotationPresent(Instance.class)) + { + try + { + i.setAccessible(true); + i.set(Modifier.isStatic(i.getModifiers()) ? null : this, null); + v("Unregistered Instance " + i.getName()); + } + + catch(IllegalArgumentException | IllegalAccessException | SecurityException e) + { + w("Failed to unregister instance (field " + i.getName() + ")"); + e.printStackTrace(); + } + } + } + } + + private void registerCommands() + { + commands = new KMap<>(); + commandCache = new KList<>(); + + for(Field i : getClass().getDeclaredFields()) + { + if(i.isAnnotationPresent(com.volmit.iris.command.util.Command.class)) + { + try + { + i.setAccessible(true); + MortarCommand pc = (MortarCommand) i.getType().getConstructor().newInstance(); + com.volmit.iris.command.util.Command c = i.getAnnotation(com.volmit.iris.command.util.Command.class); + registerCommand(pc, c.value()); + commandCache.add(pc); + v("Registered Commands /" + pc.getNode() + " (" + i.getName() + ")"); + } + + catch(IllegalArgumentException | IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException | SecurityException e) + { + w("Failed to register command (field " + i.getName() + ")"); + e.printStackTrace(); + } + } + } + } + + @Override + public boolean onCommand(CommandSender sender, org.bukkit.command.Command command, String label, String[] args) + { + KList chain = new KList(); + chain.add(args); + + for(KList i : commands.k()) + { + for(String j : i) + { + if(j.equalsIgnoreCase(label)) + { + VirtualCommand cmd = commands.get(i); + + if(cmd.hit(sender, chain.copy(), label)) + { + return true; + } + } + } + } + + return false; + } + + public void registerCommand(ICommand cmd) + { + registerCommand(cmd, ""); + } + + public void registerCommand(ICommand cmd, String subTag) + { + commands.put(cmd.getAllNodes(), new VirtualCommand(cmd, subTag.trim().isEmpty() ? getTag() : getTag(subTag.trim()))); + PluginCommand cc = getCommand(cmd.getNode().toLowerCase()); + + if(cc != null) + { + cc.setExecutor(this); + cc.setUsage(getName() + ":" + getClass().toString() + ":" + cmd.getNode()); + } + + else + { + RouterCommand r = new RouterCommand(cmd, this); + r.setUsage(getName() + ":" + getClass().toString()); + ((CommandMap) new com.volmit.iris.util.V(Bukkit.getServer()).get("commandMap")).register("", r); + } + } + + public void unregisterCommand(ICommand cmd) + { + try + { + SimpleCommandMap m = new com.volmit.iris.util.V(Bukkit.getServer()).get("commandMap"); + + Map k = new com.volmit.iris.util.V(m).get("knownCommands"); + + for(Iterator> it = k.entrySet().iterator(); it.hasNext();) + { + Map.Entry entry = it.next(); + if(entry.getValue() instanceof Command) + { + org.bukkit.command.Command c = (org.bukkit.command.Command) entry.getValue(); + String u = c.getUsage(); + + if(u != null && u.equals(getName() + ":" + getClass().toString() + ":" + cmd.getNode())) + { + if(c.unregister(m)) + { + it.remove(); + v("Unregistered Command /" + cmd.getNode()); + } + + else + { + Bukkit.getConsoleSender().sendMessage(getTag() + "Failed to unregister command " + c.getName()); + } + } + } + } + } + + catch(Throwable e) + { + e.printStackTrace(); + } + } + + public String getTag() + { + return getTag(""); + } + + public void registerListener(Listener l) + { + Bukkit.getPluginManager().registerEvents(l, this); + } + + public void unregisterListener(Listener l) + { + HandlerList.unregisterAll(l); + } + + public void unregisterListeners() + { + HandlerList.unregisterAll((Listener) this); + } + + public void unregisterCommands() + { + for(VirtualCommand i : commands.v()) + { + try + { + unregisterCommand(i.getCommand()); + } + + catch(Throwable e) + { + + } + } + } + + private void unregisterPermissions() + { + for(org.bukkit.permissions.Permission i : computePermissions()) + { + Bukkit.getPluginManager().removePermission(i); + v("Unregistered Permission " + i.getName()); + } + } + + private void stopControllers() + { + for(IController i : controllers.v()) + { + try + { + unregisterListener(i); + i.stop(); + v("Stopped " + i.getName()); + } + + catch(Throwable e) + { + w("Failed to stop controller " + i.getName()); + e.printStackTrace(); + } + } + } + + public File getDataFile(String... strings) + { + File f = new File(getDataFolder(), new KList(strings).toString(File.separator)); + f.getParentFile().mkdirs(); + return f; + } + + public File getDataFolder(String... strings) + { + if(strings.length == 0) + { + return super.getDataFolder(); + } + + File f = new File(getDataFolder(), new KList(strings).toString(File.separator)); + f.mkdirs(); + + return f; + } + + public abstract void start(); + + public abstract void stop(); + + public abstract String getTag(String subTag); +} diff --git a/src/main/java/com/volmit/iris/command/util/MortarSender.java b/src/main/java/com/volmit/iris/command/util/MortarSender.java new file mode 100644 index 000000000..14a3212a5 --- /dev/null +++ b/src/main/java/com/volmit/iris/command/util/MortarSender.java @@ -0,0 +1,209 @@ +package com.volmit.iris.command.util; + +import java.util.Set; + +import org.bukkit.ChatColor; +import org.bukkit.Server; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionAttachment; +import org.bukkit.permissions.PermissionAttachmentInfo; +import org.bukkit.plugin.Plugin; + +import lombok.Getter; +import lombok.Setter; + +/** + * Represents a volume sender. A command sender with extra crap in it + * + * @author cyberpwn + * + */ +public class MortarSender implements CommandSender +{ + private CommandSender s; + private String tag; + + @Getter + @Setter + private String command; + + /** + * Wrap a command sender + * + * @param s + * the command sender + */ + public MortarSender(CommandSender s) + { + tag = ""; + this.s = s; + } + + public MortarSender(CommandSender s, String tag) + { + this.tag = tag; + this.s = s; + } + + /** + * Set a command tag (prefix for sendMessage) + * + * @param tag + * the tag + */ + public void setTag(String tag) + { + this.tag = tag; + } + + /** + * Get the command tag + * + * @return the command tag + */ + public String getTag() + { + return tag; + } + + /** + * Is this sender a player? + * + * @return true if it is + */ + public boolean isPlayer() + { + return getS() instanceof Player; + } + + /** + * Force cast to player (be sure to check first) + * + * @return a casted player + */ + public Player player() + { + return (Player) getS(); + } + + /** + * Get the origin sender this object is wrapping + * + * @return the command sender + */ + public CommandSender getS() + { + return s; + } + + @Override + public boolean isPermissionSet(String name) + { + return s.isPermissionSet(name); + } + + @Override + public boolean isPermissionSet(Permission perm) + { + return s.isPermissionSet(perm); + } + + @Override + public boolean hasPermission(String name) + { + return s.hasPermission(name); + } + + @Override + public boolean hasPermission(Permission perm) + { + return s.hasPermission(perm); + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) + { + return s.addAttachment(plugin, name, value); + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin) + { + return s.addAttachment(plugin); + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) + { + return s.addAttachment(plugin, name, value, ticks); + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin, int ticks) + { + return s.addAttachment(plugin, ticks); + } + + @Override + public void removeAttachment(PermissionAttachment attachment) + { + s.removeAttachment(attachment); + } + + @Override + public void recalculatePermissions() + { + s.recalculatePermissions(); + } + + @Override + public Set getEffectivePermissions() + { + return s.getEffectivePermissions(); + } + + @Override + public boolean isOp() + { + return s.isOp(); + } + + @Override + public void setOp(boolean value) + { + s.setOp(value); + } + + @Override + public void sendMessage(String message) + { + s.sendMessage(ChatColor.translateAlternateColorCodes('&', getTag()) + message); + } + + @Override + public void sendMessage(String[] messages) + { + for(String str : messages) + s.sendMessage(ChatColor.translateAlternateColorCodes('&', getTag() + str)); + } + + @Override + public Server getServer() + { + return s.getServer(); + } + + @Override + public String getName() + { + return s.getName(); + } + + @Override + public Spigot spigot() + { + return s.spigot(); + } +} diff --git a/src/main/java/com/volmit/iris/command/util/Permission.java b/src/main/java/com/volmit/iris/command/util/Permission.java new file mode 100644 index 000000000..8ad0803f1 --- /dev/null +++ b/src/main/java/com/volmit/iris/command/util/Permission.java @@ -0,0 +1,14 @@ +package com.volmit.iris.command.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(FIELD) +public @interface Permission +{ + +} diff --git a/src/main/java/com/volmit/iris/command/util/RouterCommand.java b/src/main/java/com/volmit/iris/command/util/RouterCommand.java new file mode 100644 index 000000000..78f49aa32 --- /dev/null +++ b/src/main/java/com/volmit/iris/command/util/RouterCommand.java @@ -0,0 +1,52 @@ +package com.volmit.iris.command.util; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; + +/** + * Assistive command router + * + * @author cyberpwn + * + */ +public class RouterCommand extends org.bukkit.command.Command +{ + private CommandExecutor ex; + private String usage; + + /** + * The router command routes commands to bukkit executors + * + * @param realCommand + * the real command + * @param ex + * the executor + */ + public RouterCommand(ICommand realCommand, CommandExecutor ex) + { + super(realCommand.getNode().toLowerCase()); + setAliases(realCommand.getNodes()); + + this.ex = ex; + } + + @Override + public Command setUsage(String u) + { + this.usage = u; + return this; + } + + @Override + public String getUsage() + { + return usage; + } + + @Override + public boolean execute(CommandSender sender, String commandLabel, String[] args) + { + return ex.onCommand(sender, this, commandLabel, args); + } +} diff --git a/src/main/java/com/volmit/iris/command/util/VirtualCommand.java b/src/main/java/com/volmit/iris/command/util/VirtualCommand.java new file mode 100644 index 000000000..2390c17d3 --- /dev/null +++ b/src/main/java/com/volmit/iris/command/util/VirtualCommand.java @@ -0,0 +1,146 @@ +package com.volmit.iris.command.util; + +import java.lang.reflect.Field; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; + +import com.volmit.iris.Iris; +import com.volmit.iris.util.KList; +import com.volmit.iris.util.KMap; +import com.volmit.iris.util.V; + +/** + * Represents a virtual command. A chain of iterative processing through + * subcommands. + * + * @author cyberpwn + * + */ +public class VirtualCommand +{ + private ICommand command; + private String tag; + + private KMap, VirtualCommand> children; + + public VirtualCommand(ICommand command) + { + this(command, ""); + } + + public VirtualCommand(ICommand command, String tag) + { + this.command = command; + children = new KMap, VirtualCommand>(); + this.tag = tag; + + for(Field i : command.getClass().getDeclaredFields()) + { + if(i.isAnnotationPresent(Command.class)) + { + try + { + Command cc = i.getAnnotation(Command.class); + ICommand cmd = (ICommand) i.getType().getConstructor().newInstance(); + new V(command, true, true).set(i.getName(), cmd); + children.put(cmd.getAllNodes(), new VirtualCommand(cmd, cc.value().trim().isEmpty() ? tag : cc.value().trim())); + } + + catch(Exception e) + { + e.printStackTrace(); + } + } + } + } + + public String getTag() + { + return tag; + } + + public ICommand getCommand() + { + return command; + } + + public KMap, VirtualCommand> getChildren() + { + return children; + } + + public boolean hit(CommandSender sender, KList chain) + { + return hit(sender, chain, null); + } + + public boolean hit(CommandSender sender, KList chain, String label) + { + MortarSender vs = new MortarSender(sender); + vs.setTag(tag); + + if(label != null) + vs.setCommand(label); + + if(chain.isEmpty()) + { + if(!checkPermissions(sender, command)) + { + return true; + } + + return command.handle(vs, new String[0]); + } + + String nl = chain.get(0); + + for(KList i : children.k()) + { + for(String j : i) + { + if(j.equalsIgnoreCase(nl)) + { + vs.setCommand(chain.get(0)); + VirtualCommand cmd = children.get(i); + KList c = chain.copy(); + c.remove(0); + if(cmd.hit(sender, c, vs.getCommand())) + { + return true; + } + } + } + } + + if(!checkPermissions(sender, command)) + { + return true; + } + + return command.handle(vs, chain.toArray(new String[chain.size()])); + } + + private boolean checkPermissions(CommandSender sender, ICommand command2) + { + boolean failed = false; + + for(String i : command.getRequiredPermissions()) + { + if(!sender.hasPermission(i)) + { + failed = true; + Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> sender.sendMessage("- " + ChatColor.WHITE + i), 0); + } + } + + if(failed) + { + sender.sendMessage("Insufficient Permissions"); + return false; + } + + return true; + } +} diff --git a/src/main/java/com/volmit/iris/generator/ContextualChunkGenerator.java b/src/main/java/com/volmit/iris/generator/ContextualChunkGenerator.java index 11a389886..13f881c6d 100644 --- a/src/main/java/com/volmit/iris/generator/ContextualChunkGenerator.java +++ b/src/main/java/com/volmit/iris/generator/ContextualChunkGenerator.java @@ -40,6 +40,7 @@ public abstract class ContextualChunkGenerator extends ChunkGenerator implements { protected boolean failing; protected int task; + protected boolean dev; protected boolean initialized; protected RNG masterRandom; protected ChronoLatch perSecond; @@ -64,6 +65,7 @@ public abstract class ContextualChunkGenerator extends ChunkGenerator implements initialized = false; failing = false; pregenDone = false; + dev = false; } protected abstract void onGenerate(RNG masterRandom, int x, int z, ChunkData data, BiomeGrid grid); @@ -102,20 +104,29 @@ public abstract class ContextualChunkGenerator extends ChunkGenerator implements private void tick() { - if(perSecond.flip()) + if(dev) { - if(generated > (fastPregen ? 1950 : 770)) + if(perSecond.flip()) { - pregenDone = true; - } + if(generated > (fastPregen ? 1950 : 770)) + { + pregenDone = true; + } - if(pregenDone) - { - metrics.getPerSecond().put(generated); - generated = 0; + if(pregenDone) + { + metrics.getPerSecond().put(generated); + generated = 0; + } } } + else + { + pregenDone = true; + fastPregen = false; + } + onTick(ticks++); } @@ -250,6 +261,12 @@ public abstract class ContextualChunkGenerator extends ChunkGenerator implements @Override public ChunkData generateChunkData(World world, Random no, int x, int z, BiomeGrid biomeGrid) { + if(!dev) + { + pregenDone = true; + fastPregen = false; + } + PrecisionStopwatch sx = PrecisionStopwatch.start(); if(failing) diff --git a/src/main/java/com/volmit/iris/generator/IrisChunkGenerator.java b/src/main/java/com/volmit/iris/generator/IrisChunkGenerator.java index 39e7e6de8..fc8b2bbd2 100644 --- a/src/main/java/com/volmit/iris/generator/IrisChunkGenerator.java +++ b/src/main/java/com/volmit/iris/generator/IrisChunkGenerator.java @@ -168,4 +168,28 @@ public class IrisChunkGenerator extends CeilingChunkGenerator implements IrisCon return bytes; } + + @Override + public boolean shouldGenerateCaves() + { + return false; + } + + @Override + public boolean shouldGenerateDecorations() + { + return false; + } + + @Override + public boolean shouldGenerateMobs() + { + return true; + } + + @Override + public boolean shouldGenerateStructures() + { + return true; + } } diff --git a/src/main/java/com/volmit/iris/generator/ParallelChunkGenerator.java b/src/main/java/com/volmit/iris/generator/ParallelChunkGenerator.java index 3596af25a..1b2bfc0d0 100644 --- a/src/main/java/com/volmit/iris/generator/ParallelChunkGenerator.java +++ b/src/main/java/com/volmit/iris/generator/ParallelChunkGenerator.java @@ -112,6 +112,7 @@ public abstract class ParallelChunkGenerator extends BiomeChunkGenerator protected void onClose() { accelerant.close(); + Iris.executors.remove(accelerant); } public void onInit(World world, RNG rng) diff --git a/src/main/java/com/volmit/iris/generator/TerrainChunkGenerator.java b/src/main/java/com/volmit/iris/generator/TerrainChunkGenerator.java index 86eb1e22c..5f3052ae5 100644 --- a/src/main/java/com/volmit/iris/generator/TerrainChunkGenerator.java +++ b/src/main/java/com/volmit/iris/generator/TerrainChunkGenerator.java @@ -266,7 +266,7 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator } } - if(onto.equals(Material.STONE) || onto.equals(Material.ANDESITE) || onto.equals(Material.GRANITE) || onto.equals(Material.DIORITE) || onto.equals(Material.BLACKSTONE) || onto.equals(Material.BASALT)) + if(onto.equals(Material.STONE) || onto.equals(Material.GRAVEL) || onto.equals(Material.ANDESITE) || onto.equals(Material.GRANITE) || onto.equals(Material.DIORITE) || onto.equals(Material.BLACKSTONE) || onto.equals(Material.BASALT)) { if(mat.equals(Material.POPPY) || mat.equals(Material.DANDELION) || mat.equals(Material.CORNFLOWER) || mat.equals(Material.ORANGE_TULIP) || mat.equals(Material.PINK_TULIP) || mat.equals(Material.RED_TULIP) || mat.equals(Material.WHITE_TULIP) || mat.equals(Material.FERN) || mat.equals(Material.LARGE_FERN) || mat.equals(Material.GRASS) || mat.equals(Material.TALL_GRASS)) { diff --git a/src/main/java/com/volmit/iris/layer/GenLayerCave.java b/src/main/java/com/volmit/iris/layer/GenLayerCave.java index 28f8c69ed..0e173ec12 100644 --- a/src/main/java/com/volmit/iris/layer/GenLayerCave.java +++ b/src/main/java/com/volmit/iris/layer/GenLayerCave.java @@ -42,6 +42,7 @@ public class GenLayerCave extends GenLayer return EMPTY; } + int surface = data.getHighestBlock(); KList result = new KList<>(); shuffle.scale(0.01); double shuffleDistance = 72; @@ -73,6 +74,11 @@ public class GenLayerCave extends GenLayer int pu = (int) (caveHeight + tunnelHeight); int pd = (int) (caveHeight - tunnelHeight); + if(pd > surface + 1) + { + continue; + } + if((pu > 255 && pd > 255) || (pu < 0 && pd < 0)) { continue; @@ -98,6 +104,27 @@ public class GenLayerCave extends GenLayer { ceiling = pu > ceiling ? pu : ceiling; floor = pu < floor ? pu : floor; + + if(pu > surface - 2) + { + if(dig(x, pu + 1, z, data)) + { + ceiling = pu + 1 > ceiling ? pu + 1 : ceiling; + floor = pu + 1 < floor ? pu + 1 : floor; + + if(dig(x, pu + 2, z, data)) + { + ceiling = pu + 2 > ceiling ? pu + 2 : ceiling; + floor = pu + 2 < floor ? pu + 2 : floor; + + if(dig(x, pu + 3, z, data)) + { + ceiling = pu + 3 > ceiling ? pu + 3 : ceiling; + floor = pu + 3 < floor ? pu + 3 : floor; + } + } + } + } } if(dig(x, pd, z, data)) diff --git a/src/main/java/com/volmit/iris/layer/post/PostSlabber.java b/src/main/java/com/volmit/iris/layer/post/PostSlabber.java index 4bdc579b2..b38c12249 100644 --- a/src/main/java/com/volmit/iris/layer/post/PostSlabber.java +++ b/src/main/java/com/volmit/iris/layer/post/PostSlabber.java @@ -45,7 +45,17 @@ public class PostSlabber extends IrisPostBlockFilter return; } - if(isAir(x, h + 2, z) || getPostBlock(x, h + 2, z).getMaterial().equals(WATER)) + if(d.getMaterial().equals(Material.SNOW) && h + 1 <= gen.getFluidHeight()) + { + return; + } + + if(isSnowLayer(x, h, z)) + { + return; + } + + if(isAirOrWater(x, h + 2, z)) { queue(() -> { diff --git a/src/main/java/com/volmit/iris/object/IrisBiomeDecorator.java b/src/main/java/com/volmit/iris/object/IrisBiomeDecorator.java index 5e455fba8..504378428 100644 --- a/src/main/java/com/volmit/iris/object/IrisBiomeDecorator.java +++ b/src/main/java/com/volmit/iris/object/IrisBiomeDecorator.java @@ -120,21 +120,20 @@ public class IrisBiomeDecorator return null; } - RNG nrng = rng.nextParallelRNG((int) (z - (int) ((x + 34856) * (int) (x + z + (int) (28835521 + (getChance() * 1000) + getStackMin() + getStackMax() + (getZoom() * 556)))))); - double xx = dispersion.equals(Dispersion.SCATTER) ? nrng.i(-1000000, 1000000) : x; - double zz = dispersion.equals(Dispersion.SCATTER) ? nrng.i(-1000000, 1000000) : z; + RNG nrng = dispersion.equals(Dispersion.SCATTER) ? rng.nextParallelRNG((int) (z - (int) ((x + 34856) * (int) (x + z + (int) (28835521 + (getChance() * 1000) + getStackMin() + getStackMax() + (getZoom() * 556)))))) : null; + double xx = dispersion.equals(Dispersion.SCATTER) ? nrng.i(-1000000, 1000000) + z : x; + double zz = dispersion.equals(Dispersion.SCATTER) ? nrng.i(-1000000, 1000000) - x : z; + xx /= getZoom(); + zz /= getZoom(); if(getGenerator(rng).fitDoubleD(0D, 1D, xx, zz) <= chance) { - try + if(getBlockData().size() == 1) { - return getBlockData().get(getGenerator(rng.nextParallelRNG(45622222)).fit(0, getBlockData().size() - 1, xx, zz)); + return getBlockData().get(0); } - catch(Throwable e) - { - - } + return getBlockData().get(getGenerator(rng.nextParallelRNG(44)).fit(0, getBlockData().size() - 1, xx, zz)); } return null; diff --git a/src/main/java/com/volmit/iris/object/IrisRegistrant.java b/src/main/java/com/volmit/iris/object/IrisRegistrant.java index 5273823bf..1da3c211d 100644 --- a/src/main/java/com/volmit/iris/object/IrisRegistrant.java +++ b/src/main/java/com/volmit/iris/object/IrisRegistrant.java @@ -1,9 +1,13 @@ package com.volmit.iris.object; +import java.io.File; + import lombok.Data; @Data public class IrisRegistrant { private String loadKey; + + private File loadFile; } diff --git a/src/main/java/com/volmit/iris/util/IrisPostBlockFilter.java b/src/main/java/com/volmit/iris/util/IrisPostBlockFilter.java index 0175e322a..fb9e8f360 100644 --- a/src/main/java/com/volmit/iris/util/IrisPostBlockFilter.java +++ b/src/main/java/com/volmit/iris/util/IrisPostBlockFilter.java @@ -64,6 +64,29 @@ public abstract class IrisPostBlockFilter implements IPostBlockAccess return d.getMaterial().equals(Material.AIR) || d.getMaterial().equals(Material.CAVE_AIR); } + public boolean hasGravity(int x, int y, int z) + { + BlockData d = getPostBlock(x, y, z); + return d.getMaterial().equals(Material.SAND) + || d.getMaterial().equals(Material.RED_SAND) + || d.getMaterial().equals(Material.BLACK_CONCRETE_POWDER) + || d.getMaterial().equals(Material.BLUE_CONCRETE_POWDER) + || d.getMaterial().equals(Material.BROWN_CONCRETE_POWDER) + || d.getMaterial().equals(Material.CYAN_CONCRETE_POWDER) + || d.getMaterial().equals(Material.GRAY_CONCRETE_POWDER) + || d.getMaterial().equals(Material.GREEN_CONCRETE_POWDER) + || d.getMaterial().equals(Material.LIGHT_BLUE_CONCRETE_POWDER) + || d.getMaterial().equals(Material.LIGHT_GRAY_CONCRETE_POWDER) + || d.getMaterial().equals(Material.LIME_CONCRETE_POWDER) + || d.getMaterial().equals(Material.MAGENTA_CONCRETE_POWDER) + || d.getMaterial().equals(Material.ORANGE_CONCRETE_POWDER) + || d.getMaterial().equals(Material.PINK_CONCRETE_POWDER) + || d.getMaterial().equals(Material.PURPLE_CONCRETE_POWDER) + || d.getMaterial().equals(Material.RED_CONCRETE_POWDER) + || d.getMaterial().equals(Material.WHITE_CONCRETE_POWDER) + || d.getMaterial().equals(Material.YELLOW_CONCRETE_POWDER); + } + public boolean isSolid(int x, int y, int z) { BlockData d = getPostBlock(x, y, z); @@ -82,6 +105,12 @@ public abstract class IrisPostBlockFilter implements IPostBlockAccess return d instanceof Slab; } + public boolean isSnowLayer(int x, int y, int z) + { + BlockData d = getPostBlock(x, y, z); + return d.getMaterial().equals(Material.SNOW); + } + public boolean isWater(int x, int y, int z) { BlockData d = getPostBlock(x, y, z); diff --git a/src/main/java/com/volmit/iris/util/KList.java b/src/main/java/com/volmit/iris/util/KList.java index c1029c7ac..01325fa1e 100644 --- a/src/main/java/com/volmit/iris/util/KList.java +++ b/src/main/java/com/volmit/iris/util/KList.java @@ -91,6 +91,7 @@ public class KList extends ArrayList implements List * the function * @return the new map */ + @SuppressWarnings("hiding") public KMap asKeys(Function f) { KMap m = new KMap(); @@ -274,6 +275,7 @@ public class KList extends ArrayList implements List * the converter that converts the forign type into this list type * @return this list (builder) */ + @SuppressWarnings("hiding") public KList addFrom(List v, Function converter) { v.forEach((g) -> add(converter.apply(g))); @@ -288,6 +290,7 @@ public class KList extends ArrayList implements List * @param converter * @return */ + @SuppressWarnings("hiding") public KList convert(Function converter) { KList v = new KList(); @@ -663,4 +666,13 @@ public class KList extends ArrayList implements List add(t); return this; } + + public KList removeDuplicates() + { + KSet v = new KSet<>(); + v.addAll(this); + KList m = new KList<>(); + m.addAll(v); + return m; + } } diff --git a/src/main/java/com/volmit/iris/util/KMap.java b/src/main/java/com/volmit/iris/util/KMap.java index 9a855da2b..f6dab9707 100644 --- a/src/main/java/com/volmit/iris/util/KMap.java +++ b/src/main/java/com/volmit/iris/util/KMap.java @@ -6,6 +6,7 @@ import java.util.Enumeration; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +@SuppressWarnings("hiding") public class KMap extends ConcurrentHashMap { private static final long serialVersionUID = 7288942695300448163L; diff --git a/src/main/java/com/volmit/iris/util/KeyPair.java b/src/main/java/com/volmit/iris/util/KeyPair.java index 3e98b3da8..c972ec733 100644 --- a/src/main/java/com/volmit/iris/util/KeyPair.java +++ b/src/main/java/com/volmit/iris/util/KeyPair.java @@ -7,6 +7,7 @@ package com.volmit.iris.util; * @param the key type * @param the value type */ +@SuppressWarnings("hiding") public class KeyPair { private K k; diff --git a/src/main/java/com/volmit/iris/util/M.java b/src/main/java/com/volmit/iris/util/M.java index 1662e7047..27f38ad85 100644 --- a/src/main/java/com/volmit/iris/util/M.java +++ b/src/main/java/com/volmit/iris/util/M.java @@ -16,6 +16,7 @@ public class M private static final int precision = 128; private static final int modulus = 360 * precision; private static final float[] sin = new float[modulus]; + public static int tick = 0; /** * Scales B by an external range change so that
@@ -440,4 +441,9 @@ public class M return a >= 0 ? sin[a % (modulus)] : -sin[-a % (modulus)]; } + public static boolean interval(int tickInterval) + { + return tick % (tickInterval <= 0 ? 1 : tickInterval) == 0; + } + } diff --git a/src/main/java/com/volmit/iris/util/ResourceLoader.java b/src/main/java/com/volmit/iris/util/ResourceLoader.java index 7dc6f722e..6a1bdc15d 100644 --- a/src/main/java/com/volmit/iris/util/ResourceLoader.java +++ b/src/main/java/com/volmit/iris/util/ResourceLoader.java @@ -45,6 +45,7 @@ public class ResourceLoader Iris.hotloader.track(j); Iris.info("Loading " + resourceTypeName + ": " + j.getPath()); t.setLoadKey(name); + t.setLoadFile(j); lock.unlock(); return t; } diff --git a/src/main/java/com/volmit/iris/util/V.java b/src/main/java/com/volmit/iris/util/V.java new file mode 100644 index 000000000..e99f2e9cc --- /dev/null +++ b/src/main/java/com/volmit/iris/util/V.java @@ -0,0 +1,150 @@ +package com.volmit.iris.util; + +import java.lang.annotation.Annotation; + +public class V +{ + private Object o; + private boolean local; + private boolean suppress = false; + + public V(Class c, Object... parameters) + { + this.o = Violator.construct(c, parameters); + this.local = true; + } + + public V(Object o) + { + this.o = o; + this.local = true; + } + + public V(Object o, boolean local, boolean suppress) + { + this(o); + this.local = local; + this.suppress = suppress; + } + + public V(Object o, boolean local) + { + this(o); + this.local = local; + } + + public T get(Class t) + { + try + { + return (T) (local ? Violator.getDeclaredAnnotation(o.getClass(), t) : Violator.getAnnotation(o.getClass(), t)); + } + + catch(Throwable e) + { + if(!suppress) + { + e.printStackTrace(); + } + } + + return null; + } + + public T get(Class t, String mn, Class... pars) + { + try + { + return (T) (local ? Violator.getDeclaredAnnotation(Violator.getDeclaredMethod(o.getClass(), mn, pars), t) : Violator.getAnnotation(Violator.getMethod(o.getClass(), mn, pars), t)); + } + + catch(Throwable e) + { + if(!suppress) + { + e.printStackTrace(); + } + } + + return null; + } + + public T get(Class t, String mn) + { + try + { + return (T) (local ? Violator.getDeclaredAnnotation(Violator.getDeclaredField(o.getClass(), mn), t) : Violator.getAnnotation(Violator.getField(o.getClass(), mn), t)); + } + + catch(Throwable e) + { + if(!suppress) + { + e.printStackTrace(); + } + } + + return null; + } + + @SuppressWarnings("unchecked") + public T get(String field) + { + try + { + return (T) (local ? Violator.getDeclaredField(o.getClass(), field) : Violator.getField(o.getClass(), field)).get(o); + } + + catch(Throwable e) + { + if(!suppress) + { + e.printStackTrace(); + } + } + + return null; + } + + public Object invoke(String method, Object... parameters) + { + KList> par = new KList>(); + + for(Object i : parameters) + { + par.add(i.getClass()); + } + + try + { + return (local ? Violator.getDeclaredMethod(o.getClass(), method, par.toArray(new Class[par.size()])) : Violator.getMethod(o.getClass(), method, par.toArray(new Class[par.size()]))).invoke(o, parameters); + } + + catch(Throwable e) + { + if(!suppress) + { + e.printStackTrace(); + } + } + + return null; + } + + public void set(String field, Object value) + { + try + { + // https://github.com/VolmitSoftware/Mortar/issues/5 + (local ? Violator.getDeclaredField(o.getClass(), field) : Violator.getField(o.getClass(), field)).set(o, value); + } + + catch(Throwable e) + { + if(!suppress) + { + e.printStackTrace(); + } + } + } +} diff --git a/src/main/java/com/volmit/iris/util/Violator.java b/src/main/java/com/volmit/iris/util/Violator.java new file mode 100644 index 000000000..cf1de4b8c --- /dev/null +++ b/src/main/java/com/volmit/iris/util/Violator.java @@ -0,0 +1,302 @@ +package com.volmit.iris.util; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.concurrent.ConcurrentSkipListMap; + +public class Violator +{ + protected static ConcurrentSkipListMap nodes = new ConcurrentSkipListMap(); + + private static String id(Object o, Object h) + { + if(o instanceof Field) + { + return id(((Field) o).getDeclaringClass(), null) + "." + ((Field) o).getName(); + } + + if(o instanceof String) + { + return (String) o; + } + + if(o instanceof Class) + { + return ((Class) o).getCanonicalName(); + } + + if(o instanceof Constructor) + { + Constructor co = (Constructor) o; + + String mx = ""; + + for(Class i : co.getParameterTypes()) + { + mx += "," + i.getCanonicalName(); + } + + mx = mx.length() >= 1 ? mx.substring(1) : mx; + + return id(co.getDeclaringClass(), null) + "(" + mx + ")"; + } + + if(o instanceof Method) + { + String mx = ""; + + for(Class i : ((Method) o).getParameterTypes()) + { + mx += "," + i.getCanonicalName(); + } + + mx = mx.length() >= 1 ? mx.substring(1) : mx; + + return id(((Method) o).getDeclaringClass(), null) + "." + ((Method) o).getName() + "(" + mx + ")"; + } + + if(o instanceof Annotation) + { + Annotation a = (Annotation) o; + return "@" + a.annotationType().getCanonicalName() + "[" + id(h, null) + "]"; + } + + return o.hashCode() + o.toString(); + } + + private static void p(String n, Object o) + { + nodes.put(n, o); + } + + private static boolean h(String n) + { + return nodes.containsKey(n); + } + + private static Object g(String n) + { + return nodes.get(n); + } + + public static Constructor getConstructor(Class c, Class... params) throws NoSuchMethodException, SecurityException + { + String mx = ""; + + for(Class i : params) + { + mx += "," + i.getCanonicalName(); + } + + mx = mx.length() >= 1 ? mx.substring(1) : mx; + + if(!h(id(c, null) + "(" + mx + ")")) + { + Constructor co = c.getConstructor(params); + co.setAccessible(true); + p(id(co, null), co); + } + + return (Constructor) g(id(c, null) + "(" + mx + ")"); + } + + @SuppressWarnings("rawtypes") + public static Field getField(Class c, String name) throws Throwable + { + if(!h(id(c, null) + "." + name)) + { + try + { + Field f = c.getField(name); + f.setAccessible(true); + p(id(c, null) + "." + name, f); + } + catch(NoSuchFieldException e) + { + Class s = c.getSuperclass(); + if(null == s) + { + throw e; + } + Field f = s.getField(name); + f.setAccessible(true); + p(id(c, null) + "." + name, f); + } + } + + return (Field) g(id(c, null) + "." + name); + } + + @SuppressWarnings("rawtypes") + public static Field getDeclaredField(Class c, String name) throws Throwable + { + if(!h(id(c, null) + "." + name)) + { + try + { + Field f = c.getDeclaredField(name); + f.setAccessible(true); + p(id(c, null) + "." + name, f); + } + catch(NoSuchFieldException e) + { + Class s = c.getSuperclass(); + if(null == s) + { + throw e; + } + Field f = s.getDeclaredField(name); + f.setAccessible(true); + p(id(c, null) + "." + name, f); + } + } + + return (Field) g(id(c, null) + "." + name); + } + + public static Method getMethod(Class c, String name, Class... pars) throws Throwable + { + String iv = ""; + String mx = ""; + + for(Class i : pars) + { + mx += "," + i.getCanonicalName(); + } + + mx = mx.length() >= 1 ? mx.substring(1) : mx; + iv = id(c, null) + "." + name + "(" + mx + ")"; + + if(!h(iv)) + { + Method f = c.getMethod(name, pars); + f.setAccessible(true); + p(iv, f); + } + + return (Method) g(iv); + } + + @SuppressWarnings("unchecked") + public static T construct(Class c, Object... parameters) + { + KList> cv = new KList>(); + + for(Object i : parameters) + { + cv.add(i.getClass()); + } + + try + { + Constructor co = getConstructor(c, cv.toArray(new Class[cv.size()])); + return (T) co.newInstance(parameters); + } + + catch(Exception e) + { + e.printStackTrace(); + } + + return null; + } + + public static Method getDeclaredMethod(Class c, String name, Class... pars) throws Throwable + { + String iv = ""; + String mx = ""; + + for(Class i : pars) + { + mx += "," + i.getCanonicalName(); + } + + mx = mx.length() >= 1 ? mx.substring(1) : mx; + iv = id(c, null) + "." + name + "(" + mx + ")"; + + if(!h(iv)) + { + Method f = c.getDeclaredMethod(name, pars); + f.setAccessible(true); + p(iv, f); + } + + return (Method) g(iv); + } + + @SuppressWarnings("unchecked") + public static T getAnnotation(Class c, Class a) throws Throwable + { + if(!h("@" + a.getCanonicalName() + "[" + c.getCanonicalName() + "]")) + { + T f = c.getAnnotation(a); + p(id(f, c), f); + } + + return (T) g("@" + a.getCanonicalName() + "[" + c.getCanonicalName() + "]"); + } + + @SuppressWarnings("unchecked") + public static T getDeclaredAnnotation(Class c, Class a) throws Throwable + { + if(!h("@" + a.getCanonicalName() + "[" + c.getCanonicalName() + "]")) + { + T f = c.getDeclaredAnnotation(a); + p(id(f, c), f); + } + + return (T) g("@" + a.getCanonicalName() + "[" + c.getCanonicalName() + "]"); + } + + @SuppressWarnings("unchecked") + public static T getAnnotation(Field c, Class a) throws Throwable + { + if(!h("@" + a.getCanonicalName() + "[" + id(c, null) + "]")) + { + T f = c.getAnnotation(a); + p(id(f, c), f); + } + + return (T) g("@" + a.getCanonicalName() + "[" + id(c, null) + "]"); + } + + @SuppressWarnings("unchecked") + public static T getDeclaredAnnotation(Field c, Class a) throws Throwable + { + if(!h("@" + a.getCanonicalName() + "[" + id(c, null) + "]")) + { + T f = c.getDeclaredAnnotation(a); + p(id(f, c), f); + } + + return (T) g("@" + a.getCanonicalName() + "[" + id(c, null) + "]"); + } + + @SuppressWarnings("unchecked") + public static T getAnnotation(Method c, Class a) throws Throwable + { + if(!h("@" + a.getCanonicalName() + "[" + id(c, null) + "]")) + { + T f = c.getAnnotation(a); + p(id(f, c), f); + } + + return (T) g("@" + a.getCanonicalName() + "[" + id(c, null) + "]"); + } + + @SuppressWarnings("unchecked") + public static T getDeclaredAnnotation(Method c, Class a) throws Throwable + { + if(!h("@" + a.getCanonicalName() + "[" + id(c, null) + "]")) + { + T f = c.getDeclaredAnnotation(a); + p(id(f, c), f); + + System.out.println("Set as " + id(f, c) + " as " + ("@" + a.getCanonicalName() + "[" + id(c, null) + "]")); + } + + return (T) g("@" + a.getCanonicalName() + "[" + id(c, null) + "]"); + } +}