From 2e3a2ff69acbe4feaf7f135dabaebf7d46883df8 Mon Sep 17 00:00:00 2001 From: Dan Date: Sat, 28 Aug 2021 08:26:39 -0800 Subject: [PATCH] Revert "Revert "Merge pull request #561 from CocoTheOwner/DecreeCommands"" This reverts commit a451189d83d792acfa60db7d5553dd2896e535a0. --- .../object/CommandIrisObjectPaste.java | 3 +- .../command/object/CommandIrisObjectUndo.java | 54 +--- .../command/what/CommandIrisWhatBlock.java | 39 --- .../command/what/CommandIrisWhatObjects.java | 9 +- .../core/command/world/CommandIrisVerify.java | 4 +- .../com/volmit/iris/core/decrees/DecIris.java | 22 +- .../volmit/iris/core/decrees/DecObject.java | 218 ++++++++++++-- .../volmit/iris/core/decrees/DecStudio.java | 279 +++++++++++++++++- .../volmit/iris/core/project/IrisProject.java | 40 +-- .../volmit/iris/core/service/CommandSVC.java | 3 +- .../volmit/iris/core/service/ObjectSVC.java | 67 +++++ .../volmit/iris/core/service/StudioSVC.java | 7 +- .../volmit/iris/util/decree/DecreeNode.java | 14 +- .../util/decree/handlers/BiomeHandler.java | 3 + .../util/decree/handlers/BooleanHandler.java | 3 + .../util/decree/handlers/RegionHandler.java | 3 + .../util/decree/handlers/VectorHandler.java | 9 +- .../util/decree/handlers/WorldHandler.java | 8 +- .../volmit/iris/util/plugin/VolmitSender.java | 142 ++++++--- src/main/resources/plugin.yml | 2 + 20 files changed, 705 insertions(+), 224 deletions(-) create mode 100644 src/main/java/com/volmit/iris/core/service/ObjectSVC.java diff --git a/src/main/java/com/volmit/iris/core/command/object/CommandIrisObjectPaste.java b/src/main/java/com/volmit/iris/core/command/object/CommandIrisObjectPaste.java index 247dda859..d263c26c8 100644 --- a/src/main/java/com/volmit/iris/core/command/object/CommandIrisObjectPaste.java +++ b/src/main/java/com/volmit/iris/core/command/object/CommandIrisObjectPaste.java @@ -21,6 +21,7 @@ package com.volmit.iris.core.command.object; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.loader.IrisData; +import com.volmit.iris.core.service.ObjectSVC; import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.service.WandSVC; import com.volmit.iris.core.tools.IrisToolbelt; @@ -185,7 +186,7 @@ public class CommandIrisObjectPaste extends MortarCommand { Map futureChanges = new HashMap<>(); obj.place(block.getBlockX(), block.getBlockY() + (int) obj.getCenter().getY(), block.getBlockZ(), createPlacer(sender.player(), block.getWorld(), futureChanges), placement, new RNG(), null); - CommandIrisObjectUndo.addChanges(sender.player(), futureChanges); + Iris.service(ObjectSVC.class).addChanges(futureChanges); if (intoWand) { ItemStack newWand = WandSVC.createWand(block.clone().subtract(obj.getCenter()).add(obj.getW() - 1, diff --git a/src/main/java/com/volmit/iris/core/command/object/CommandIrisObjectUndo.java b/src/main/java/com/volmit/iris/core/command/object/CommandIrisObjectUndo.java index dea27478a..343df19e0 100644 --- a/src/main/java/com/volmit/iris/core/command/object/CommandIrisObjectUndo.java +++ b/src/main/java/com/volmit/iris/core/command/object/CommandIrisObjectUndo.java @@ -20,6 +20,7 @@ package com.volmit.iris.core.command.object; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.core.service.ObjectSVC; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.plugin.MortarCommand; import com.volmit.iris.util.plugin.VolmitSender; @@ -34,7 +35,6 @@ import java.util.*; public class CommandIrisObjectUndo extends MortarCommand { - private static final Map>> undos = new HashMap<>(); public CommandIrisObjectUndo() { super("undo", "u", "revert"); @@ -101,14 +101,14 @@ public class CommandIrisObjectUndo extends MortarCommand { sender.sendMessage("Please specify an amount greater than 0!"); return true; } - - if (!undos.containsKey(player) || undos.get(player).size() == 0) { + ObjectSVC service = Iris.service(ObjectSVC.class); + if (service.getUndos().size() == 0) { sender.sendMessage("No pastes to undo"); return true; } - int actualReverts = Math.min(undos.get(player).size(), amount); - revertChanges(player, amount); + int actualReverts = Math.min(service.getUndos().size(), amount); + service.revertChanges(actualReverts); sender.sendMessage("Reverted " + actualReverts + " pastes!"); return true; @@ -118,48 +118,4 @@ public class CommandIrisObjectUndo extends MortarCommand { protected String getArgsUsage() { return "[-number [num]] [-user [username]]"; } - - public static void addChanges(Player player, Map oldBlocks) { - if (!undos.containsKey(player.getUniqueId())) { - undos.put(player.getUniqueId(), new ArrayDeque<>()); - } - - undos.get(player.getUniqueId()).add(oldBlocks); - } - - public static void revertChanges(UUID player, int amount) { - loopChange(player, amount); - } - - private static void loopChange(UUID uuid, int amount) { - Deque> queue = undos.get(uuid); - if (queue != null && queue.size() > 0) { - revert(queue.pollLast()); - if (amount > 1) { - J.s(() -> loopChange(uuid, amount - 1), 2); - } - } - } - - /** - * Reverts all the block changes provided, 200 blocks per tick - * - * @param blocks The blocks to remove - */ - private static void revert(Map blocks) { - int amount = 0; - Iterator> it = blocks.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry entry = it.next(); - BlockData data = entry.getValue(); - entry.getKey().setBlockData(data, false); - it.remove(); - - amount++; - - if (amount > 200) { - J.s(() -> revert(blocks), 1); - } - } - } } diff --git a/src/main/java/com/volmit/iris/core/command/what/CommandIrisWhatBlock.java b/src/main/java/com/volmit/iris/core/command/what/CommandIrisWhatBlock.java index 818d1ecb3..6018562f8 100644 --- a/src/main/java/com/volmit/iris/core/command/what/CommandIrisWhatBlock.java +++ b/src/main/java/com/volmit/iris/core/command/what/CommandIrisWhatBlock.java @@ -46,46 +46,7 @@ public class CommandIrisWhatBlock extends MortarCommand { if (sender.isPlayer()) { BlockData bd; Player p = sender.player(); - try { - bd = p.getTargetBlockExact(128, FluidCollisionMode.NEVER).getBlockData(); - } catch (NullPointerException e) { - Iris.reportError(e); - sender.sendMessage("Please look at any block, not at the sky"); - bd = null; - } - if (bd != null) { - sender.sendMessage("Material: " + C.GREEN + bd.getMaterial().name()); - sender.sendMessage("Full: " + C.WHITE + bd.getAsString(true)); - - if (B.isStorage(bd)) { - sender.sendMessage(C.YELLOW + "* Storage Block (Loot Capable)"); - } - - if (B.isLit(bd)) { - sender.sendMessage(C.YELLOW + "* Lit Block (Light Capable)"); - } - - if (B.isFoliage(bd)) { - sender.sendMessage(C.YELLOW + "* Foliage Block"); - } - - if (B.isDecorant(bd)) { - sender.sendMessage(C.YELLOW + "* Decorant Block"); - } - - if (B.isFluid(bd)) { - sender.sendMessage(C.YELLOW + "* Fluid Block"); - } - - if (B.isFoliagePlantable(bd)) { - sender.sendMessage(C.YELLOW + "* Plantable Foliage Block"); - } - - if (B.isSolid(bd)) { - sender.sendMessage(C.YELLOW + "* Solid Block"); - } - } } else { sender.sendMessage("Players only."); } diff --git a/src/main/java/com/volmit/iris/core/command/what/CommandIrisWhatObjects.java b/src/main/java/com/volmit/iris/core/command/what/CommandIrisWhatObjects.java index 83659a91b..fa9d5ca6b 100644 --- a/src/main/java/com/volmit/iris/core/command/what/CommandIrisWhatObjects.java +++ b/src/main/java/com/volmit/iris/core/command/what/CommandIrisWhatObjects.java @@ -61,7 +61,6 @@ public class CommandIrisWhatObjects extends MortarCommand { } - @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") @Override public boolean handle(VolmitSender sender, String[] args) { if (sender.isPlayer()) { @@ -81,11 +80,9 @@ public class CommandIrisWhatObjects extends MortarCommand { try { Location l = p.getTargetBlockExact(48, FluidCollisionMode.NEVER).getLocation(); - if (l != null) { - int cx = l.getChunk().getX(); - int cz = l.getChunk().getZ(); - new Spiraler(3, 3, (x, z) -> chunks.addIfMissing(world.getChunkAt(x + cx, z + cz))).drain(); - } + int cx = l.getChunk().getX(); + int cz = l.getChunk().getZ(); + new Spiraler(3, 3, (x, z) -> chunks.addIfMissing(world.getChunkAt(x + cx, z + cz))).drain(); } catch (Throwable e) { Iris.reportError(e); } diff --git a/src/main/java/com/volmit/iris/core/command/world/CommandIrisVerify.java b/src/main/java/com/volmit/iris/core/command/world/CommandIrisVerify.java index 42bb4aef4..890f79fdd 100644 --- a/src/main/java/com/volmit/iris/core/command/world/CommandIrisVerify.java +++ b/src/main/java/com/volmit/iris/core/command/world/CommandIrisVerify.java @@ -60,8 +60,8 @@ public class CommandIrisVerify extends MortarCommand { MCAFile file = null; try { file = MCAUtil.read(i); - int rx = Integer.valueOf(i.getName().split("\\Q.\\E")[1]); - int rz = Integer.valueOf(i.getName().split("\\Q.\\E")[2]); + int rx = Integer.parseInt(i.getName().split("\\Q.\\E")[1]); + int rz = Integer.parseInt(i.getName().split("\\Q.\\E")[2]); for (int j = 0; j < 32; j++) { for (int k = 0; k < 32; k++) { f.incrementAndGet(); diff --git a/src/main/java/com/volmit/iris/core/decrees/DecIris.java b/src/main/java/com/volmit/iris/core/decrees/DecIris.java index e5ad09ddb..fc696e274 100644 --- a/src/main/java/com/volmit/iris/core/decrees/DecIris.java +++ b/src/main/java/com/volmit/iris/core/decrees/DecIris.java @@ -25,11 +25,15 @@ import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.engine.object.dimensional.IrisDimension; import com.volmit.iris.util.decree.DecreeExecutor; import com.volmit.iris.util.decree.DecreeOrigin; +import com.volmit.iris.util.decree.DecreeSystem; import com.volmit.iris.util.decree.annotations.Decree; import com.volmit.iris.util.decree.annotations.Param; +import com.volmit.iris.util.decree.exceptions.DecreeParsingException; +import com.volmit.iris.util.decree.exceptions.DecreeWhichException; import com.volmit.iris.util.format.C; import java.io.File; +import java.util.Objects; @Decree(name = "irisd", aliases = {"ird"}, description = "Basic Command") public class DecIris implements DecreeExecutor { @@ -43,7 +47,7 @@ public class DecIris implements DecreeExecutor { @Decree(description = "Create a new world", aliases = "+") public void create( - @Param(aliases = "world-name", description = "The name of the world to create", defaultValue = "IrisWorld") + @Param(aliases = "world-name", description = "The name of the world to create") String name, @Param(aliases = "dimension", description = "The dimension type to create the world with", defaultValue = "overworld") IrisDimension type, @@ -81,7 +85,7 @@ public class DecIris implements DecreeExecutor { @Decree(description = "Print version information") public void version() { - sender().sendMessage("Iris v" + Iris.instance.getDescription().getVersion() + " by Volmit Software"); + sender().sendMessage(C.GREEN + "Iris v" + Iris.instance.getDescription().getVersion() + " by Volmit Software"); } @Decree(description = "Set aura spins") @@ -104,7 +108,7 @@ public class DecIris implements DecreeExecutor { public void bitwise( @Param(description = "The first value to run calculations on") int value1, - @Param(description = "The operator: | & ^ >> << %") + @Param(description = "The operator: | & ^ ≺≺ ≻≻ %") String operator, @Param(description = "The second value to run calculations on") int value2 @@ -122,18 +126,20 @@ public class DecIris implements DecreeExecutor { sender().sendMessage(C.RED + "The operator you entered: (" + operator + ") is invalid!"); return; } - sender().sendMessage(C.GREEN + "" + value1 + " " + C.GREEN + operator.replaceAll("<", "≺").replaceAll(">", "≻") + " " + C.GREEN + value2 + C.GREEN + " returns " + C.GREEN + v); + sender().sendMessage(C.GREEN + "" + value1 + " " + C.GREEN + operator.replaceAll("<", "≺").replaceAll(">", "≻").replaceAll("%", "%") + " " + C.GREEN + value2 + C.GREEN + " returns " + C.GREEN + v); } @Decree(description = "Toggle debug") public void debug( - @Param(name = "on", description = "Whether or not debug should be on", defaultValue = "true") - boolean on + @Param(name = "on", description = "Whether or not debug should be on", defaultValue = "other") + Boolean on ) { - IrisSettings.get().getGeneral().setDebug(on); + boolean to = on == null ? !IrisSettings.get().getGeneral().isDebug() : on; + IrisSettings.get().getGeneral().setDebug(to); + sender().sendMessage(C.GREEN + "Set debug to: " + to); } - @Decree(description = "Download a project.") + @Decree(description = "Download a project.", aliases = "dl") public void download( @Param(name = "pack", description = "The pack to download", defaultValue = "overworld", aliases = "project") String pack, diff --git a/src/main/java/com/volmit/iris/core/decrees/DecObject.java b/src/main/java/com/volmit/iris/core/decrees/DecObject.java index 976703571..3da95e599 100644 --- a/src/main/java/com/volmit/iris/core/decrees/DecObject.java +++ b/src/main/java/com/volmit/iris/core/decrees/DecObject.java @@ -1,9 +1,12 @@ package com.volmit.iris.core.decrees; -import com.volmit.iris.core.command.object.CommandIrisObjectUndo; +import com.volmit.iris.Iris; import com.volmit.iris.core.loader.IrisData; +import com.volmit.iris.core.service.ObjectSVC; +import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.service.WandSVC; import com.volmit.iris.engine.object.common.IObjectPlacer; +import com.volmit.iris.engine.object.dimensional.IrisDimension; import com.volmit.iris.engine.object.objects.IrisObject; import com.volmit.iris.engine.object.objects.IrisObjectPlacement; import com.volmit.iris.engine.object.objects.IrisObjectPlacementScaleInterpolator; @@ -14,6 +17,7 @@ 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.decree.specialhandlers.ObjectHandler; import com.volmit.iris.util.format.C; import com.volmit.iris.util.math.Direction; import com.volmit.iris.util.math.RNG; @@ -24,23 +28,27 @@ import org.bukkit.block.BlockState; import org.bukkit.block.TileState; import org.bukkit.block.data.BlockData; import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; +import java.io.File; +import java.io.IOException; import java.text.NumberFormat; import java.util.*; import java.util.stream.Collectors; -@Decree(name = "object", origin = DecreeOrigin.PLAYER, studio = true, description = "Iris object manipulation") +@Decree(name = "object", aliases = "o", origin = DecreeOrigin.PLAYER, studio = true, description = "Iris object manipulation") public class DecObject implements DecreeExecutor { @Decree(description = "Check the composition of an object") public void analyze( - @Param(description = "The object to analyze") - IrisObject object + @Param(description = "The object to analyze", customHandler = ObjectHandler.class) + String object ) { - sender().sendMessage("Object Size: " + object.getW() + " * " + object.getH() + " * " + object.getD() + ""); - sender().sendMessage("Blocks Used: " + NumberFormat.getIntegerInstance().format(object.getBlocks().size())); + IrisObject o = IrisData.loadAnyObject(object); + sender().sendMessage("Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD() + ""); + sender().sendMessage("Blocks Used: " + NumberFormat.getIntegerInstance().format(o.getBlocks().size())); - Queue queue = object.getBlocks().enqueueValues(); + Queue queue = o.getBlocks().enqueueValues(); Map> unsorted = new HashMap<>(); Map amounts = new HashMap<>(); Map materials = new HashMap<>(); @@ -183,21 +191,23 @@ public class DecObject implements DecreeExecutor { private static final Set skipBlocks = Set.of(Material.GRASS, Material.SNOW, Material.VINE, Material.TORCH, Material.DEAD_BUSH, Material.POPPY, Material.DANDELION); - @Decree(description = "Paste an object") + @Decree(description = "Paste an object", sync = true) public void paste( - @Param(description = "The object to paste") - IrisObject object, + @Param(description = "The object to paste", customHandler = ObjectHandler.class) + String object, @Param(description = "Whether or not to edit the object (need to hold wand)", defaultValue = "false") boolean edit, @Param(description = "The amount of degrees to rotate by", defaultValue = "0") int rotate, @Param(description = "The factor by which to scale the object placement", defaultValue = "1") - double scale, - @Param(description = "The scale interpolator to use", defaultValue = "none") - IrisObjectPlacementScaleInterpolator interpolator - ) { - double maxScale = Double.max(10 - object.getBlocks().size() / 10000d, 1); - if (scale < maxScale) { + double scale +// , +// @Param(description = "The scale interpolator to use", defaultValue = "none") +// IrisObjectPlacementScaleInterpolator interpolator + ){ + IrisObject o = IrisData.loadAnyObject(object); + double maxScale = Double.max(10 - o.getBlocks().size() / 10000d, 1); + if (scale > maxScale){ sender().sendMessage(C.YELLOW + "Indicated scale exceeds maximum. Downscaled to maximum: " + maxScale); scale = maxScale; } @@ -212,30 +222,30 @@ public class DecObject implements DecreeExecutor { Map futureChanges = new HashMap<>(); - object = object.scaled(scale, interpolator); - object.place(block.getBlockX(), block.getBlockY() + (int) object.getCenter().getY(), block.getBlockZ(), createPlacer(block.getWorld(), futureChanges), placement, new RNG(), null); + o = o.scaled(scale, IrisObjectPlacementScaleInterpolator.TRICUBIC); + o.place(block.getBlockX(), block.getBlockY() + (int) o.getCenter().getY(), block.getBlockZ(), createPlacer(block.getWorld(), futureChanges), placement, new RNG(), null); - CommandIrisObjectUndo.addChanges(player(), futureChanges); + Iris.service(ObjectSVC.class).addChanges(futureChanges); if (edit) { - ItemStack newWand = WandSVC.createWand(block.clone().subtract(object.getCenter()).add(object.getW() - 1, - object.getH() + object.getCenter().clone().getY() - 1, object.getD() - 1), block.clone().subtract(object.getCenter().clone().setY(0))); + ItemStack newWand = WandSVC.createWand(block.clone().subtract(o.getCenter()).add(o.getW() - 1, + o.getH() + o.getCenter().clone().getY() - 1, o.getD() - 1), block.clone().subtract(o.getCenter().clone().setY(0))); if (WandSVC.isWand(wand)) { wand = newWand; player().getInventory().setItemInMainHand(wand); - sender().sendMessage("Updated wand for " + "objects/" + object.getLoadKey() + ".iob"); + sender().sendMessage("Updated wand for " + "objects/" + o.getLoadKey() + ".iob "); } else { int slot = WandSVC.findWand(player().getInventory()); if (slot == -1) { player().getInventory().addItem(newWand); - sender().sendMessage("Given new wand for " + "objects/" + object.getLoadKey() + ".iob"); + sender().sendMessage("Given new wand for " + "objects/" + o.getLoadKey() + ".iob "); } else { player().getInventory().setItem(slot, newWand); - sender().sendMessage("Updated wand for " + "objects/" + object.getLoadKey() + ".iob"); + sender().sendMessage("Updated wand for " + "objects/" + o.getLoadKey() + ".iob "); } } } else { - sender().sendMessage("Placed " + "objects/" + object.getLoadKey() + ".iob"); + sender().sendMessage("Placed " + "objects/" + o.getLoadKey() + ".iob "); } } @@ -308,4 +318,162 @@ public class DecObject implements DecreeExecutor { }; } + @Decree(description = "Save an object") + public void save( + @Param(description = "The dimension to store the object in", contextual = true) + IrisDimension dimension, + @Param(description = "The file to store it in, can use / for subfolders") + String name, + @Param(description = "Overwrite existing object files", defaultValue = "false", aliases = "force") + boolean overwrite + ){ + IrisObject o = WandSVC.createSchematic(player().getInventory().getItemInMainHand()); + + if (o == null) { + sender().sendMessage(C.YELLOW + "You need to hold your wand!"); + return; + } + + File file = Iris.service(StudioSVC.class).getWorkspaceFile(dimension.getLoadKey(), "objects", name + ".iob"); + + if (file.exists() && !overwrite) { + sender().sendMessage(C.RED + "File already exists. Set overwrite=true to overwrite it."); + return; + } + try { + o.write(file); + } catch (IOException e){ + sender().sendMessage(C.RED + "Failed to save object because of an IOException: " + e.getMessage()); + Iris.reportError(e); + } + + sender().playSound(Sound.BLOCK_ENCHANTMENT_TABLE_USE, 1f, 1.5f); + sender().sendMessage(C.GREEN + "Successfully object to saved: " + dimension.getLoadKey() + "/objects/" + name); + } + + @Decree(description = "Shift a selection in your looking direction", aliases = "-") + public void shift( + @Param(description = "The amount to shift by", defaultValue = "1") + int amount + ){ + if (!WandSVC.isHoldingWand(player())) { + sender().sendMessage("Hold your wand."); + return; + } + + Location[] b = WandSVC.getCuboid(player().getInventory().getItemInMainHand()); + Location a1 = b[0].clone(); + Location a2 = b[1].clone(); + Direction d = Direction.closest(player().getLocation().getDirection()).reverse(); + a1.add(d.toVector().multiply(amount)); + a2.add(d.toVector().multiply(amount)); + Cuboid cursor = new Cuboid(a1, a2); + b[0] = cursor.getLowerNE(); + b[1] = cursor.getUpperSW(); + player().getInventory().setItemInMainHand(WandSVC.createWand(b[0], b[1])); + player().updateInventory(); + sender().playSound(Sound.ENTITY_ITEM_FRAME_ROTATE_ITEM, 1f, 0.55f); + } + + @Decree(description = "Undo a number of pastes", aliases = "-") + public void undo( + @Param(description = "The amount of pastes to undo", defaultValue = "1") + int amount + ){ + ObjectSVC service = Iris.service(ObjectSVC.class); + int actualReverts = Math.min(service.getUndos().size(), amount); + service.revertChanges(actualReverts); + sender().sendMessage("Reverted " + actualReverts + " pastes!"); + } + + @Decree(description = "Get an object wand", sync = true) + public void wand() { + player().getInventory().addItem(WandSVC.createWand()); + sender().playSound(Sound.ITEM_ARMOR_EQUIP_NETHERITE, 1f, 1.5f); + sender().sendMessage(C.GREEN + "Poof! Good luck building!"); + } + + @Decree(name = "x&y", description = "Autoselect up, down & out", sync = true) + public void xay(){ + if (!WandSVC.isHoldingWand(player())){ + sender().sendMessage(C.YELLOW + "Hold your wand!"); + return; + } + + Location[] b = WandSVC.getCuboid(player().getInventory().getItemInMainHand()); + Location a1 = b[0].clone(); + Location a2 = b[1].clone(); + Location a1x = b[0].clone(); + Location a2x = b[1].clone(); + Cuboid cursor = new Cuboid(a1, a2); + Cuboid cursorx = new Cuboid(a1, a2); + + while (!cursor.containsOnly(Material.AIR)) { + a1.add(new org.bukkit.util.Vector(0, 1, 0)); + a2.add(new org.bukkit.util.Vector(0, 1, 0)); + cursor = new Cuboid(a1, a2); + } + + a1.add(new org.bukkit.util.Vector(0, -1, 0)); + a2.add(new org.bukkit.util.Vector(0, -1, 0)); + + while (!cursorx.containsOnly(Material.AIR)) { + a1x.add(new org.bukkit.util.Vector(0, -1, 0)); + a2x.add(new org.bukkit.util.Vector(0, -1, 0)); + cursorx = new Cuboid(a1x, a2x); + } + + a1x.add(new org.bukkit.util.Vector(0, 1, 0)); + a2x.add(new Vector(0, 1, 0)); + b[0] = a1; + b[1] = a2x; + cursor = new Cuboid(b[0], b[1]); + cursor = cursor.contract(Cuboid.CuboidDirection.North); + cursor = cursor.contract(Cuboid.CuboidDirection.South); + cursor = cursor.contract(Cuboid.CuboidDirection.East); + cursor = cursor.contract(Cuboid.CuboidDirection.West); + b[0] = cursor.getLowerNE(); + b[1] = cursor.getUpperSW(); + player().getInventory().setItemInMainHand(WandSVC.createWand(b[0], b[1])); + player().updateInventory(); + sender().playSound(Sound.ENTITY_ITEM_FRAME_ROTATE_ITEM, 1f, 0.55f); + sender().sendMessage(C.GREEN + "Auto-select complete!"); + } + + @Decree(name = "x+y", description = "Autoselect up & out", sync = true) + public void xpy() { + if (!WandSVC.isHoldingWand(player())) { + sender().sendMessage(C.YELLOW + "Hold your wand!"); + return; + } + + Location[] b = WandSVC.getCuboid(player().getInventory().getItemInMainHand()); + b[0].add(new Vector(0, 1, 0)); + b[1].add(new Vector(0, 1, 0)); + Location a1 = b[0].clone(); + Location a2 = b[1].clone(); + Cuboid cursor = new Cuboid(a1, a2); + + while (!cursor.containsOnly(Material.AIR)) { + a1.add(new Vector(0, 1, 0)); + a2.add(new Vector(0, 1, 0)); + cursor = new Cuboid(a1, a2); + } + + a1.add(new Vector(0, -1, 0)); + a2.add(new Vector(0, -1, 0)); + b[0] = a1; + a2 = b[1]; + cursor = new Cuboid(a1, a2); + cursor = cursor.contract(Cuboid.CuboidDirection.North); + cursor = cursor.contract(Cuboid.CuboidDirection.South); + cursor = cursor.contract(Cuboid.CuboidDirection.East); + cursor = cursor.contract(Cuboid.CuboidDirection.West); + b[0] = cursor.getLowerNE(); + b[1] = cursor.getUpperSW(); + player().getInventory().setItemInMainHand(WandSVC.createWand(b[0], b[1])); + player().updateInventory(); + sender().playSound(Sound.ENTITY_ITEM_FRAME_ROTATE_ITEM, 1f, 0.55f); + sender().sendMessage(C.GREEN + "Auto-select complete!"); + } } diff --git a/src/main/java/com/volmit/iris/core/decrees/DecStudio.java b/src/main/java/com/volmit/iris/core/decrees/DecStudio.java index 7d6d5b452..37af6c9a7 100644 --- a/src/main/java/com/volmit/iris/core/decrees/DecStudio.java +++ b/src/main/java/com/volmit/iris/core/decrees/DecStudio.java @@ -18,6 +18,7 @@ package com.volmit.iris.core.decrees; +import com.google.gson.Gson; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.gui.NoiseExplorerGUI; @@ -27,12 +28,14 @@ import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.service.ConversionSVC; import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.tools.IrisToolbelt; +import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.basic.IrisPosition; import com.volmit.iris.engine.object.biome.IrisBiome; import com.volmit.iris.engine.object.biome.IrisBiomePaletteLayer; import com.volmit.iris.engine.object.common.IrisScript; import com.volmit.iris.engine.object.dimensional.IrisDimension; import com.volmit.iris.engine.object.entity.IrisEntity; +import com.volmit.iris.engine.object.feature.IrisFeaturePositional; import com.volmit.iris.engine.object.loot.IrisLootTable; import com.volmit.iris.engine.object.meta.InventorySlotType; import com.volmit.iris.engine.object.noise.IrisGenerator; @@ -40,9 +43,11 @@ import com.volmit.iris.engine.object.noise.IrisInterpolator; import com.volmit.iris.engine.object.noise.IrisNoiseGenerator; import com.volmit.iris.engine.object.noise.NoiseStyle; import com.volmit.iris.engine.object.objects.IrisObject; +import com.volmit.iris.engine.object.objects.IrisObjectPlacement; import com.volmit.iris.engine.object.regional.IrisRegion; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.data.B; import com.volmit.iris.util.decree.DecreeExecutor; import com.volmit.iris.util.decree.DecreeOrigin; @@ -56,7 +61,9 @@ import com.volmit.iris.util.interpolation.InterpolationMethod; 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.math.M; import com.volmit.iris.util.math.RNG; +import com.volmit.iris.util.math.Spiraler; import com.volmit.iris.util.noise.CNG; import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.scheduling.J; @@ -66,16 +73,26 @@ 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; +import io.papermc.lib.PaperLib; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; +import org.bukkit.util.BlockVector; import org.bukkit.util.Vector; import java.awt.*; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.attribute.FileTime; +import java.time.Duration; +import java.time.temporal.ChronoUnit; +import java.util.Date; +import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.function.Supplier; @@ -92,7 +109,16 @@ public class DecStudio implements DecreeExecutor { Iris.service(StudioSVC.class).open(sender(), seed, dimension.getLoadKey()); } - @Decree(description = "Close an open studio project", aliases = "x", sync = true) + @Decree(description = "Open VSCode for a dimension", aliases = {"vsc", "edit"}) + public void vscode( + @Param(defaultValue = "overworld", description = "The dimension to open VSCode for", aliases = "dim") + IrisDimension dimension + ) { + sender().sendMessage(C.GREEN + "Opening VSCode for the \"" + dimension.getName() + "\" pack"); + Iris.service(StudioSVC.class).openVSCode(sender(), dimension.getLoadKey()); + } + + @Decree(description = "Close an open studio project", aliases = {"x", "c"}, sync = true) public void close() { if (!Iris.service(StudioSVC.class).isProjectOpen()) { sender().sendMessage(C.RED + "No open studio projects."); @@ -286,6 +312,11 @@ public class DecStudio implements DecreeExecutor { @Decree(description = "Charges all spawners in the area", aliases = "zzt", origin = DecreeOrigin.PLAYER) public void charge() { + if (!IrisToolbelt.isIrisWorld(world())){ + sender().sendMessage(C.RED + "You must be in an Iris world to charge spawners!"); + return; + } + sender().sendMessage(C.GREEN + "Charging spawners!"); engine().getWorldManager().chargeEnergy(); } @@ -312,9 +343,9 @@ public class DecStudio implements DecreeExecutor { @Decree(description = "Find any biome or region", aliases = {"goto", "g"}, origin = DecreeOrigin.PLAYER) public void find( - @Param(description = "The biome to find", contextual = true) + @Param(description = "The biome or region to find", defaultValue = "null") IrisBiome biome, - @Param(description = "The region to find", contextual = true) + @Param(description = "The region to find", defaultValue = "null") IrisRegion region ) { if (!IrisToolbelt.isIrisWorld(world())) { @@ -323,35 +354,45 @@ public class DecStudio implements DecreeExecutor { } if (biome == null && region == null) { - sender().sendMessage(C.RED + "You must specify a biome or region!"); + sender().sendMessage(C.RED + "You must specify a biome= or region=!"); return; } - IrisPosition l = null; + IrisPosition regionPosition = null; if (region != null) { - l = engine().lookForRegion(region, 10000, (v) -> sender().sendMessage("Looking for the " + C.BOLD + C.WHITE + region.getName() + C.RESET + C.GRAY + " region: Checked " + Form.f(v) + " Places")); - if (l == null) { + regionPosition = engine().lookForRegion(region, 10000, (v) -> sender().sendMessage("Looking for the " + C.BOLD + C.WHITE + region.getName() + C.RESET + C.GRAY + " region: Checked " + Form.f(v) + " Places")); + if (regionPosition == null) { sender().sendMessage(C.YELLOW + "Couldn't find the " + region.getName() + " region."); } else { sender().sendMessage(C.GREEN + "Found the " + region.getName() + " region!."); } } - if (l == null && biome != null) { - l = engine().lookForBiome(biome, 10000, (v) -> sender().sendMessage("Looking for the " + C.BOLD + C.WHITE + biome.getName() + C.RESET + C.GRAY + " biome: Checked " + Form.f(v) + " Places")); - if (l == null) { + IrisPosition biomePosition = null; + if (biome != null) { + biomePosition = engine().lookForBiome(biome, 10000, (v) -> sender().sendMessage("Looking for the " + C.BOLD + C.WHITE + biome.getName() + C.RESET + C.GRAY + " biome: Checked " + Form.f(v) + " Places")); + if (biomePosition == null) { sender().sendMessage(C.YELLOW + "Couldn't find the " + biome.getName() + " biome."); } else { sender().sendMessage(C.GREEN + "Found the " + biome.getName() + " biome!."); } } - if (l == null) { - sender().sendMessage(C.RED + "Could not find the region and / or biome you specified."); - return; + if (regionPosition == null && region != null) { + sender().sendMessage(C.RED + "Could not find the region you specified."); + } else if (regionPosition != null){ + sender().sendMessage(C.GREEN + "Found the region at: " + regionPosition.toString()); + } + if (biomePosition == null && biome != null) { + sender().sendMessage(C.RED + "Could not find the biome you specified."); + } else if (biomePosition != null){ + sender().sendMessage(C.GREEN + "Found the biome at: " + biomePosition.toString()); } - final IrisPosition finalL = l; + final IrisPosition finalL = regionPosition == null ? biomePosition : regionPosition; + if (finalL == null) { + return; + } J.s(() -> player().teleport(finalL.toLocation(world()))); } @@ -360,6 +401,7 @@ public class DecStudio implements DecreeExecutor { if (noStudio()) return; access().hotload(); + sender().sendMessage(C.GREEN + "Hotloaded"); } @Decree(description = "Show loot if a chest were right here", origin = DecreeOrigin.PLAYER, sync = true) @@ -676,8 +718,17 @@ public class DecStudio implements DecreeExecutor { @Param(description = "Whether or not to show information about the block you are holding", defaultValue = "true") boolean hand ) { + if (engine() == null) { + sender().sendMessage(C.RED + "You must be in an Iris world!"); + return; + } // Data - BlockData handHeld = player().getInventory().getItemInMainHand().getType().createBlockData(); + BlockData handHeld = null; + try { + handHeld = player().getInventory().getItemInMainHand().getType().createBlockData(); + } catch (Throwable e) { + sender().sendMessage("Could not get data for hand-held item"); + } Block targetBlock = player().getTargetBlockExact(128, FluidCollisionMode.NEVER); BlockData targetBlockData; if (targetBlock == null) { @@ -739,6 +790,9 @@ public class DecStudio implements DecreeExecutor { } // Hand-held + if (handHeld == null){ + return; + } if (!handHeld.getMaterial().equals(Material.AIR)) { sender().sendMessage(C.YELLOW + "No block held"); } else if (hand) { @@ -749,6 +803,201 @@ public class DecStudio implements DecreeExecutor { } } + @Decree(aliases = {"find-features", "nf"}, description = "Get the noise feature data in your chunk") + public void features() { + + if (!IrisToolbelt.isIrisWorld(player().getWorld())){ + sender().sendMessage(C.RED + "Iris worlds only"); + return; + } + + int n = 0; + + for (IrisFeaturePositional irisFeaturePositional : engine().getMantle().getFeaturesInChunk(player().getLocation().getChunk())) { + sender().sendMessage("#" + n++ + " " + new JSONObject(new Gson().toJson(irisFeaturePositional)).toString(4)); + } + } + + @Decree(aliases = "find-objects", description = "Get information about nearby structures") + public void objects() { + if (!IrisToolbelt.isIrisWorld(player().getWorld())){ + sender().sendMessage(C.RED + "You must be in an Iris world"); + return; + } + + World world = player().getWorld(); + + if (!IrisToolbelt.isIrisWorld(world)) { + sender().sendMessage("You must be in an iris world."); + return; + } + KList chunks = new KList<>(); + int bx = player().getLocation().getChunk().getX(); + int bz = player().getLocation().getChunk().getZ(); + + try { + Location l = player().getTargetBlockExact(48, FluidCollisionMode.NEVER).getLocation(); + + int cx = l.getChunk().getX(); + int cz = l.getChunk().getZ(); + new Spiraler(3, 3, (x, z) -> chunks.addIfMissing(world.getChunkAt(x + cx, z + cz))).drain(); + } catch (Throwable e) { + Iris.reportError(e); + } + + new Spiraler(3, 3, (x, z) -> chunks.addIfMissing(world.getChunkAt(x + bx, z + bz))).drain(); + sender().sendMessage("Capturing IGenData from " + chunks.size() + " nearby chunks."); + try { + File ff = Iris.instance.getDataFile("reports/" + M.ms() + ".txt"); + PrintWriter pw = new PrintWriter(ff); + pw.println("=== Iris Chunk Report ==="); + pw.println("== General Info =="); + pw.println("Iris Version: " + Iris.instance.getDescription().getVersion()); + pw.println("Bukkit Version: " + Bukkit.getBukkitVersion()); + pw.println("MC Version: " + Bukkit.getVersion()); + pw.println("PaperSpigot: " + (PaperLib.isPaper() ? "Yup!" : "Nope!")); + pw.println("Report Captured At: " + new Date()); + pw.println("Chunks: (" + chunks.size() + "): "); + + for (Chunk i : chunks) { + pw.println("- [" + i.getX() + ", " + i.getZ() + "]"); + } + + int regions = 0; + long size = 0; + String age = "No idea..."; + + try { + for (File i : Objects.requireNonNull(new File(world.getWorldFolder(), "region").listFiles())) { + if (i.isFile()) { + size += i.length(); + } + } + } catch (Throwable e) { + Iris.reportError(e); + } + + try { + FileTime creationTime = (FileTime) Files.getAttribute(world.getWorldFolder().toPath(), "creationTime"); + age = hrf(Duration.of(M.ms() - creationTime.toMillis(), ChronoUnit.MILLIS)); + } catch (IOException e) { + Iris.reportError(e); + } + + KList biomes = new KList<>(); + KList caveBiomes = new KList<>(); + KMap>> objects = new KMap<>(); + + for (Chunk i : chunks) { + for (int j = 0; j < 16; j += 3) { + + for (int k = 0; k < 16; k += 3) { + + assert engine() != null; + IrisBiome bb = engine().getSurfaceBiome((i.getX() * 16) + j, (i.getZ() * 16) + k); + IrisBiome bxf = engine().getCaveBiome((i.getX() * 16) + j, (i.getZ() * 16) + k); + biomes.addIfMissing(bb.getName() + " [" + Form.capitalize(bb.getInferredType().name().toLowerCase()) + "] " + " (" + bb.getLoadFile().getName() + ")"); + caveBiomes.addIfMissing(bxf.getName() + " (" + bxf.getLoadFile().getName() + ")"); + exportObjects(bb, pw, engine(), objects); + exportObjects(bxf, pw, engine(), objects); + } + } + } + + regions = Objects.requireNonNull(new File(world.getWorldFolder().getPath() + "/region").list()).length; + + pw.println(); + pw.println("== World Info =="); + pw.println("World Name: " + world.getName()); + pw.println("Age: " + age); + pw.println("Folder: " + world.getWorldFolder().getPath()); + pw.println("Regions: " + Form.f(regions)); + pw.println("Chunks: max. " + Form.f(regions * 32 * 32)); + pw.println("World Size: min. " + Form.fileSize(size)); + pw.println(); + pw.println("== Biome Info =="); + pw.println("Found " + biomes.size() + " Biome(s): "); + + for (String i : biomes) { + pw.println("- " + i); + } + pw.println(); + + pw.println("== Object Info =="); + + for (String i : objects.k()) { + pw.println("- " + i); + + for (String j : objects.get(i).k()) { + pw.println(" @ " + j); + + for (String k : objects.get(i).get(j)) { + pw.println(" * " + k); + } + } + } + + pw.println(); + pw.close(); + + sender().sendMessage("Reported to: " + ff.getPath()); + } catch (FileNotFoundException e) { + e.printStackTrace(); + Iris.reportError(e); + } + } + + private void exportObjects(IrisBiome bb, PrintWriter pw, Engine g, KMap>> objects) { + String n1 = bb.getName() + " [" + Form.capitalize(bb.getInferredType().name().toLowerCase()) + "] " + " (" + bb.getLoadFile().getName() + ")"; + int m = 0; + KSet stop = new KSet<>(); + for (IrisObjectPlacement f : bb.getObjects()) { + m++; + String n2 = "Placement #" + m + " (" + f.getPlace().size() + " possible objects)"; + + for (String i : f.getPlace()) { + String nn3 = i + ": [ERROR] Failed to find object!"; + + try { + if (stop.contains(i)) { + continue; + } + + File ff = g.getData().getObjectLoader().findFile(i); + BlockVector sz = IrisObject.sampleSize(ff); + nn3 = i + ": size=[" + sz.getBlockX() + "," + sz.getBlockY() + "," + sz.getBlockZ() + "] location=[" + ff.getPath() + "]"; + stop.add(i); + } catch (Throwable e) { + Iris.reportError(e); + } + + String n3 = nn3; + + objects.compute(n1, (k1, v1) -> + { + //noinspection ReplaceNullCheck + if (v1 == null) { + return new KMap<>(); + } + + return v1; + }).compute(n2, (k, v) -> + { + if (v == null) { + return new KList().qaddIfMissing(n3); + } + + v.addIfMissing(n3); + return v; + }); + } + } + } + + public static String hrf(Duration duration) { + return duration.toString().substring(2).replaceAll("(\\d[HMS])(?!$)", "$1 ").toLowerCase(); + } + /** * @return true if server GUIs are not enabled */ 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 654cbd0bc..1ee3f5b0a 100644 --- a/src/main/java/com/volmit/iris/core/project/IrisProject.java +++ b/src/main/java/com/volmit/iris/core/project/IrisProject.java @@ -106,25 +106,9 @@ public class IrisProject { }); } - public void open(VolmitSender sender, long seed, Consumer onDone) throws IrisException { - if (isOpen()) { - close(); - } - - boolean hasError = false; - - if (hasError) { - return; - } + public void openVSCode(VolmitSender sender) { IrisDimension d = IrisData.loadAnyDimension(getName()); - if (d == null) { - sender.sendMessage("Can't find dimension: " + getName()); - return; - } else if (sender.isPlayer()) { - sender.player().setGameMode(GameMode.SPECTATOR); - } - J.attemptAsync(() -> { try { @@ -171,6 +155,28 @@ public class IrisProject { e.printStackTrace(); } }); + } + + public void open(VolmitSender sender, long seed, Consumer onDone) throws IrisException { + if (isOpen()) { + close(); + } + + boolean hasError = false; + + if (hasError) { + return; + } + + IrisDimension d = IrisData.loadAnyDimension(getName()); + if (d == null) { + sender.sendMessage("Can't find dimension: " + getName()); + return; + } else if (sender.isPlayer()) { + sender.player().setGameMode(GameMode.SPECTATOR); + } + + openVSCode(sender); J.a(() -> { diff --git a/src/main/java/com/volmit/iris/core/service/CommandSVC.java b/src/main/java/com/volmit/iris/core/service/CommandSVC.java index 793100629..2bc017fb1 100644 --- a/src/main/java/com/volmit/iris/core/service/CommandSVC.java +++ b/src/main/java/com/volmit/iris/core/service/CommandSVC.java @@ -18,6 +18,7 @@ package com.volmit.iris.core.service; +import com.volmit.iris.Iris; import com.volmit.iris.core.decrees.DecIris; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.util.collection.KList; @@ -28,7 +29,7 @@ import com.volmit.iris.util.plugin.IrisService; public class CommandSVC implements IrisService, DecreeSystem { @Override public void onEnable() { - // TODO Iris.instance.getCommand("irisd").setExecutor(this); + Iris.instance.getCommand("irisd").setExecutor(this); } @Override diff --git a/src/main/java/com/volmit/iris/core/service/ObjectSVC.java b/src/main/java/com/volmit/iris/core/service/ObjectSVC.java new file mode 100644 index 000000000..4450a67b8 --- /dev/null +++ b/src/main/java/com/volmit/iris/core/service/ObjectSVC.java @@ -0,0 +1,67 @@ +package com.volmit.iris.core.service; + +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.plugin.IrisService; +import com.volmit.iris.util.scheduling.J; +import lombok.Getter; +import org.bukkit.block.Block; +import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Player; + +import java.util.*; + +public class ObjectSVC implements IrisService { + + @Getter + private final Deque> undos = new ArrayDeque<>(); + + + @Override + public void onEnable() { + + } + + @Override + public void onDisable() { + + } + + public void addChanges(Map oldBlocks) { + undos.add(oldBlocks); + } + + public void revertChanges(int amount) { + loopChange(amount); + } + + private void loopChange(int amount) { + if (undos.size() > 0) { + revert(undos.pollLast()); + if (amount > 1) { + J.s(() -> loopChange(amount - 1), 2); + } + } + } + + /** + * Reverts all the block changes provided, 200 blocks per tick + * + * @param blocks The blocks to remove + */ + private void revert(Map blocks) { + int amount = 0; + Iterator> it = blocks.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = it.next(); + BlockData data = entry.getValue(); + entry.getKey().setBlockData(data, false); + it.remove(); + + amount++; + + if (amount > 200) { + J.s(() -> revert(blocks), 1); + } + } + } +} diff --git a/src/main/java/com/volmit/iris/core/service/StudioSVC.java b/src/main/java/com/volmit/iris/core/service/StudioSVC.java index aad2a367e..0e67227c2 100644 --- a/src/main/java/com/volmit/iris/core/service/StudioSVC.java +++ b/src/main/java/com/volmit/iris/core/service/StudioSVC.java @@ -323,8 +323,7 @@ public class StudioSVC implements IrisService { public void open(VolmitSender sender, long seed, String dimm) { try { - open(sender, seed, dimm, (w) -> { - }); + open(sender, seed, dimm, (w) -> {}); } catch (Exception e) { Iris.reportError(e); sender.sendMessage("Error when creating studio world:"); @@ -342,6 +341,10 @@ public class StudioSVC implements IrisService { project.open(sender, seed, onDone); } + public void openVSCode(VolmitSender sender, String dim) { + new IrisProject(new File(getWorkspaceFolder(), dim)).openVSCode(sender); + } + public File getWorkspaceFolder(String... sub) { return Iris.instance.getDataFolderList(WORKSPACE_NAME, sub); } diff --git a/src/main/java/com/volmit/iris/util/decree/DecreeNode.java b/src/main/java/com/volmit/iris/util/decree/DecreeNode.java index 884ec3aff..ab512b3c0 100644 --- a/src/main/java/com/volmit/iris/util/decree/DecreeNode.java +++ b/src/main/java/com/volmit/iris/util/decree/DecreeNode.java @@ -47,13 +47,21 @@ public class DecreeNode { * @return The list of parameters if ALL are annotated by @{@link Param}, else null */ public KList getParameters() { - KList p = new KList<>(); + KList required = new KList<>(); + KList optional = new KList<>(); for (Parameter i : method.getParameters()) { - p.add(new DecreeParameter(i)); + DecreeParameter p = new DecreeParameter(i); + if (p.isRequired()){ + required.add(p); + } else { + optional.add(p); + } } + + required.addAll(optional); - return p; + return required; } public String getName() { diff --git a/src/main/java/com/volmit/iris/util/decree/handlers/BiomeHandler.java b/src/main/java/com/volmit/iris/util/decree/handlers/BiomeHandler.java index d142cea4d..1f03ae93f 100644 --- a/src/main/java/com/volmit/iris/util/decree/handlers/BiomeHandler.java +++ b/src/main/java/com/volmit/iris/util/decree/handlers/BiomeHandler.java @@ -56,6 +56,9 @@ public class BiomeHandler implements DecreeParameterHandler { @Override public IrisBiome parse(String in) throws DecreeParsingException, DecreeWhichException { + if (in.equals("null")) { + return null; + } try { KList options = getPossibilities(in); 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 index e61de78ad..d53bb1555 100644 --- a/src/main/java/com/volmit/iris/util/decree/handlers/BooleanHandler.java +++ b/src/main/java/com/volmit/iris/util/decree/handlers/BooleanHandler.java @@ -37,6 +37,9 @@ public class BooleanHandler implements DecreeParameterHandler { @Override public Boolean parse(String in) throws DecreeParsingException { try { + if (in.equals("null") || in.equals("other") || in.equals("flip")) { + return null; + } return Boolean.parseBoolean(in); } catch (Throwable e) { throw new DecreeParsingException("Unable to parse boolean \"" + in + "\""); diff --git a/src/main/java/com/volmit/iris/util/decree/handlers/RegionHandler.java b/src/main/java/com/volmit/iris/util/decree/handlers/RegionHandler.java index 8f205af9a..36e80a83b 100644 --- a/src/main/java/com/volmit/iris/util/decree/handlers/RegionHandler.java +++ b/src/main/java/com/volmit/iris/util/decree/handlers/RegionHandler.java @@ -56,6 +56,9 @@ public class RegionHandler implements DecreeParameterHandler { @Override public IrisRegion parse(String in) throws DecreeParsingException, DecreeWhichException { + if (in.equals("null")) { + return null; + } try { KList options = getPossibilities(in); diff --git a/src/main/java/com/volmit/iris/util/decree/handlers/VectorHandler.java b/src/main/java/com/volmit/iris/util/decree/handlers/VectorHandler.java index fb31842e5..53944a4fd 100644 --- a/src/main/java/com/volmit/iris/util/decree/handlers/VectorHandler.java +++ b/src/main/java/com/volmit/iris/util/decree/handlers/VectorHandler.java @@ -43,14 +43,7 @@ public class VectorHandler implements DecreeParameterHandler { @Override public KList getPossibilities() { - KList vx = new KList<>(); - VolmitSender s = DecreeContext.get(); - - if (s.isPlayer()) { - vx.add(s.player().getLocation().toVector()); - } - - return vx; + return null; } @Override diff --git a/src/main/java/com/volmit/iris/util/decree/handlers/WorldHandler.java b/src/main/java/com/volmit/iris/util/decree/handlers/WorldHandler.java index de7438c5e..1f79f4248 100644 --- a/src/main/java/com/volmit/iris/util/decree/handlers/WorldHandler.java +++ b/src/main/java/com/volmit/iris/util/decree/handlers/WorldHandler.java @@ -28,7 +28,13 @@ import org.bukkit.World; public class WorldHandler implements DecreeParameterHandler { @Override public KList getPossibilities() { - return new KList<>(Bukkit.getWorlds()); + KList options = new KList<>(); + for (World world : Bukkit.getWorlds()) { + if (!world.getName().toLowerCase().startsWith("iris/")){ + options.add(world); + } + } + return options; } @Override 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 c4b174a28..844f48430 100644 --- a/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java +++ b/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java @@ -21,6 +21,7 @@ package com.volmit.iris.util.plugin; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.decree.DecreeParameter; import com.volmit.iris.util.decree.virtual.VirtualDecreeCommand; import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.Form; @@ -42,6 +43,7 @@ import org.bukkit.permissions.PermissionAttachmentInfo; import org.bukkit.plugin.Plugin; import java.time.Duration; +import java.util.Comparator; import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -426,55 +428,101 @@ public class VolmitSender implements CommandSender { public void sendDecreeHelpNode(VirtualDecreeCommand i) { if (isPlayer()) { - //@builder - String s = ( + + String newline = "\n"; + + /// Command + // Contains main command & aliases + String realText = i.getPath() + " >" + "<#46826a>⇀ " + i.getName(); + String hoverTitle = i.getNames().copy().reverse().convert((f) -> "<#42ecf5>" + f).toString(", "); + String description = "<#3fe05a>✎ <#6ad97d>" + i.getDescription(); + String usage = "<#bbe03f>✒ <#a8e0a2>"; + String onClick; + if (i.isNode()) { + if (i.getNode().getParameters().isEmpty()){ + usage += "There are no parameters. Click to run."; + onClick = "run_command"; + } else { + usage += "Hover over all of the parameters to learn more."; + onClick = "suggest_command"; + } + } else { + usage += "This is a command category. Click to run."; + onClick = "run_command"; + } + + String suggestion = ""; + String suggestions = ""; + if (i.isNode() && i.getNode().getParameters().isNotEmpty()) { + suggestion += newline + "<#aebef2>✦ <#5ef288>" + i.getParentPath() + " <#42ecf5>" + i.getName() + " " + + i.getNode().getParameters().convert((f) -> "<#d665f0>" + f.example()).toString(" "); + suggestions += newline + "" + pickRandoms(Math.min(i.getNode().getParameters().size() + 1, 5), i); + } + + /// Params + StringBuilder nodes = new StringBuilder(); + if (i.isNode()){ + for (DecreeParameter p : i.getNode().getParameters()) { + + String nTitle = "" + p.getName(); + String nHoverTitle = p.getNames().convert((ff) -> "<#d665f0>" + ff).toString(", "); + String nDescription = "<#3fe05a>✎ <#6ad97d>" + p.getDescription(); + String nUsage; + String context = ""; + if (p.isRequired()){ + nUsage = "<#db4321>⚠ <#faa796>This parameter is required."; + } else if (p.hasDefault()) { + nUsage = "<#2181db>✔ <#78dcf0>Defaults to \""+ p.getParam().defaultValue()+"\" if undefined."; + } else { + nUsage = "<#a73abd>✔ <#78dcf0>This parameter is optional."; + } + if (p.isContextual()){ + context = "<#ff9900>➱ <#ffcc00>The value may be derived from environment context" + newline; + } + String type = "<#cc00ff>✢ <#ff33cc>This parameter is of type " + p.getType().getSimpleName(); + String fullTitle; + if (p.isRequired()){ + fullTitle = "[" + nTitle + "] "; + } else { + fullTitle = "<#4f4f4f>⊰" + nTitle + "<#4f4f4f>⊱"; + } + + nodes + .append("") + .append(fullTitle) + .append(""); + } + } else { + nodes = new StringBuilder(" - Category of Commands"); + } + + /// Wrapper + String wrapper = " "<#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 <#98eda5>" + i.getPath()) - + (i.isNode() - ? (i.getNode().getParameters().isNotEmpty()) - ? "<#aebef2>✦ <#5ef288>" - + i.getParentPath() - + " <#42ecf5>" - + i.getName() + " " - + i.getNode().getParameters().convert((f) - -> "<#d665f0>" + f.example()) - .toString(" ") + "\n" - : "" - : "") - + (i.isNode() ? "" + pickRandoms(Math.min(i.getNode().getParameters().size() + 1, 5), i) + "" : "") - + "'>" - + "<#46826a>⇀ " + i.getName() + "" - + (i.isNode() ? - " " + i.getNode().getParameters().convert((f) - -> " "<#d665f0>" + ff).toString(", ") + "\n" - + "<#3fe05a>✎ <#6ad97d>" + f.getDescription() + "\n" - + (f.isRequired() - ? "<#db4321>⚠ <#faa796>This parameter is required." - : (f.hasDefault() - ? "<#2181db>✔ <#78dcf0>Defaults to \"" + f.getParam().defaultValue() + "\" if undefined." - : "<#a73abd>✔ <#78dcf0>This parameter is optional.")) + "\n" - + (f.isContextual() ? "<#ff9900>➱ <#ffcc00>The value may be derived from environment context \n" : "") - + "<#cc00ff>✢ <#ff33cc>This parameter is of type " + f.getType().getSimpleName() - + "'>" - + (f.isRequired() ? "[" : "") - + "" + f.getName() - + (f.isRequired() ? "]" : "") - + "").toString(" ") - : " - Category of Commands" - ) - ); - //@done - sendMessageRaw(s); - System.out.println(s); + hoverTitle + newline + + description + newline + + usage + + suggestion + //Newlines for suggestions are added when they're built, to prevent blanklines. + suggestions + // ^ + "'>" + + "" + + "" + + " " + + nodes; + + sendMessageRaw(wrapper); } else { - sendMessage(i.getPath() + "()"); + sendMessage(i.getPath()); } } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 43ab6a751..e59e41bf3 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -20,5 +20,7 @@ libraries: commands: iris: aliases: [ ir, irs ] + irisd: + aliases: [ ird, id ] api-version: ${apiversion} hotload-dependencies: false \ No newline at end of file