From 9a45b364f66e833603d678c5adecf0dd50f7f2e9 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Fri, 22 Sep 2017 12:44:49 +1000 Subject: [PATCH] Various minor Fixes #742 Fixes #734 --- .../bukkit/regions/FactionsOneFeature.java | 11 +- .../bukkit/regions/FactionsUUIDFeature.java | 11 +- core/src/main/java/com/boydti/fawe/Fawe.java | 14 +- .../boydti/fawe/command/AnvilCommands.java | 4 +- .../com/boydti/fawe/command/CFICommands.java | 13 +- .../main/java/com/boydti/fawe/config/BBC.java | 6 +- .../com/boydti/fawe/object/RegionWrapper.java | 31 +- .../com/boydti/fawe/regions/FaweMask.java | 7 +- .../java/com/sk89q/worldedit/EditSession.java | 92 +++--- .../extent/inventory/BlockBagExtent.java | 28 +- .../worldedit/regions/EllipsoidRegion.java | 2 + .../ConvexPolyhedralRegionSelector.java | 278 +++++++++++++++++ .../selector/CuboidRegionSelector.java | 8 +- .../selector/CylinderRegionSelector.java | 285 +++++++++++++++++ .../selector/EllipsoidRegionSelector.java | 255 +++++++++++++++ .../ExtendingCuboidRegionSelector.java | 148 +++++++++ .../selector/Polygonal2DRegionSelector.java | 295 ++++++++++++++++++ .../selector/SphereRegionSelector.java | 102 ++++++ 18 files changed, 1482 insertions(+), 108 deletions(-) create mode 100644 core/src/main/java/com/sk89q/worldedit/regions/selector/ConvexPolyhedralRegionSelector.java create mode 100644 core/src/main/java/com/sk89q/worldedit/regions/selector/CylinderRegionSelector.java create mode 100644 core/src/main/java/com/sk89q/worldedit/regions/selector/EllipsoidRegionSelector.java create mode 100644 core/src/main/java/com/sk89q/worldedit/regions/selector/ExtendingCuboidRegionSelector.java create mode 100644 core/src/main/java/com/sk89q/worldedit/regions/selector/Polygonal2DRegionSelector.java create mode 100644 core/src/main/java/com/sk89q/worldedit/regions/selector/SphereRegionSelector.java diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/regions/FactionsOneFeature.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/regions/FactionsOneFeature.java index 82d84c38..4eab9279 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/regions/FactionsOneFeature.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/regions/FactionsOneFeature.java @@ -31,9 +31,10 @@ public class FactionsOneFeature extends BukkitMaskManager implements Listener { final Player player = fp.parent; final Chunk chunk = player.getLocation().getChunk(); final boolean perm = Perm.hasPermission(FawePlayer.wrap(player), "fawe.factions.wilderness"); - final RegionWrapper locs = new RegionWrapper(chunk.getX(), chunk.getX(), chunk.getZ(), chunk.getZ()); final World world = player.getWorld(); + RegionWrapper locs = new RegionWrapper(chunk.getX(), chunk.getX(), chunk.getZ(), chunk.getZ()); + int count = 32; if (this.isAdded(locs, world, player, perm, type)) { @@ -48,28 +49,28 @@ public class FactionsOneFeature extends BukkitMaskManager implements Listener { chunkSelection = new RegionWrapper(locs.maxX + 1, locs.maxX + 1, locs.minZ, locs.maxZ); if (this.isAdded(chunkSelection, world, player, perm, type)) { - locs.maxX += 1; + locs = new RegionWrapper(locs.minX, locs.maxX + 1, locs.minZ, locs.maxZ); hasPerm = true; } chunkSelection = new RegionWrapper(locs.minX - 1, locs.minX - 1, locs.minZ, locs.maxZ); if (this.isAdded(chunkSelection, world, player, perm, type)) { - locs.minX -= 1; + locs = new RegionWrapper(locs.minX - 1, locs.maxX, locs.minZ, locs.maxZ); hasPerm = true; } chunkSelection = new RegionWrapper(locs.minX, locs.maxX, locs.maxZ + 1, locs.maxZ + 1); if (this.isAdded(chunkSelection, world, player, perm, type)) { - locs.maxZ += 1; + locs = new RegionWrapper(locs.minX, locs.maxX, locs.minZ, locs.maxZ + 1); hasPerm = true; } chunkSelection = new RegionWrapper(locs.minX, locs.maxX, locs.minZ - 1, locs.minZ - 1); if (this.isAdded(chunkSelection, world, player, perm, type)) { - locs.minZ -= 1; + locs = new RegionWrapper(locs.minX, locs.maxX, locs.minZ - 1, locs.maxZ); hasPerm = true; } } diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/regions/FactionsUUIDFeature.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/regions/FactionsUUIDFeature.java index d278a291..29451faa 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/regions/FactionsUUIDFeature.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/regions/FactionsUUIDFeature.java @@ -27,9 +27,10 @@ public class FactionsUUIDFeature extends BukkitMaskManager implements Listener { final Player player = fp.parent; final Chunk chunk = player.getLocation().getChunk(); final boolean perm = Perm.hasPermission(FawePlayer.wrap(player), "fawe.factions.wilderness"); - final RegionWrapper locs = new RegionWrapper(chunk.getX(), chunk.getX(), chunk.getZ(), chunk.getZ()); final World world = player.getWorld(); + RegionWrapper locs = new RegionWrapper(chunk.getX(), chunk.getX(), chunk.getZ(), chunk.getZ()); + int count = 32; if (this.isAdded(locs, world, player, perm, type)) { @@ -44,28 +45,28 @@ public class FactionsUUIDFeature extends BukkitMaskManager implements Listener { chunkSelection = new RegionWrapper(locs.maxX + 1, locs.maxX + 1, locs.minZ, locs.maxZ); if (this.isAdded(chunkSelection, world, player, perm, type)) { - locs.maxX += 1; + locs = new RegionWrapper(locs.minX, locs.maxX + 1, locs.minZ, locs.maxZ); hasPerm = true; } chunkSelection = new RegionWrapper(locs.minX - 1, locs.minX - 1, locs.minZ, locs.maxZ); if (this.isAdded(chunkSelection, world, player, perm, type)) { - locs.minX -= 1; + locs = new RegionWrapper(locs.minX - 1, locs.maxX, locs.minZ, locs.maxZ); hasPerm = true; } chunkSelection = new RegionWrapper(locs.minX, locs.maxX, locs.maxZ + 1, locs.maxZ + 1); if (this.isAdded(chunkSelection, world, player, perm, type)) { - locs.maxZ += 1; + locs = new RegionWrapper(locs.minX, locs.maxX, locs.minZ, locs.maxZ + 1); hasPerm = true; } chunkSelection = new RegionWrapper(locs.minX, locs.maxX, locs.minZ - 1, locs.minZ - 1); if (this.isAdded(chunkSelection, world, player, perm, type)) { - locs.minZ -= 1; + locs = new RegionWrapper(locs.minX, locs.maxX, locs.minZ - 1, locs.maxZ); hasPerm = true; } } diff --git a/core/src/main/java/com/boydti/fawe/Fawe.java b/core/src/main/java/com/boydti/fawe/Fawe.java index 05a78e5b..d34315d7 100644 --- a/core/src/main/java/com/boydti/fawe/Fawe.java +++ b/core/src/main/java/com/boydti/fawe/Fawe.java @@ -121,8 +121,13 @@ import com.sk89q.worldedit.math.convolution.HeightMap; import com.sk89q.worldedit.math.interpolation.KochanekBartelsInterpolation; import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.regions.EllipsoidRegion; +import com.sk89q.worldedit.regions.selector.ConvexPolyhedralRegionSelector; import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; +import com.sk89q.worldedit.regions.selector.CylinderRegionSelector; +import com.sk89q.worldedit.regions.selector.EllipsoidRegionSelector; +import com.sk89q.worldedit.regions.selector.ExtendingCuboidRegionSelector; +import com.sk89q.worldedit.regions.selector.Polygonal2DRegionSelector; +import com.sk89q.worldedit.regions.selector.SphereRegionSelector; import com.sk89q.worldedit.regions.shape.ArbitraryShape; import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; import com.sk89q.worldedit.session.ClipboardHolder; @@ -560,7 +565,12 @@ public class Fawe { BrushTool.inject(); // Add transform + support for double action brushes + visualizations // Selectors CuboidRegionSelector.inject(); // Translations - EllipsoidRegion.inject(); // Optimizations + ExtendingCuboidRegionSelector.inject(); + EllipsoidRegionSelector.inject(); + SphereRegionSelector.inject(); + ConvexPolyhedralRegionSelector.inject(); + CylinderRegionSelector.inject(); + Polygonal2DRegionSelector.inject(); // Visitors BreadthFirstSearch.inject(); // Translations + Optimizations DownwardVisitor.inject(); // Optimizations diff --git a/core/src/main/java/com/boydti/fawe/command/AnvilCommands.java b/core/src/main/java/com/boydti/fawe/command/AnvilCommands.java index 2ddb7f22..036256cf 100644 --- a/core/src/main/java/com/boydti/fawe/command/AnvilCommands.java +++ b/core/src/main/java/com/boydti/fawe/command/AnvilCommands.java @@ -626,7 +626,7 @@ public class AnvilCommands { FawePlayer fp = FawePlayer.wrap(player); MCAClipboard clipboard = fp.getMeta(FawePlayer.METADATA_KEYS.ANVIL_CLIPBOARD); if (clipboard == null) { - fp.sendMessage(BBC.getPrefix() + "You must first copy to your clipboard"); + fp.sendMessage(BBC.getPrefix() + "You must first use `//anvil copy`"); return; } CuboidRegion cuboid = clipboard.getRegion(); @@ -649,6 +649,6 @@ public class AnvilCommands { pasteQueue.pasteRegion(copyQueue, copyRegion, offset, iAnvilHistory); } catch (IOException e) { throw new RuntimeException(e); } }); - BBC.COMMAND_PASTE.send(player, player.getPosition()); + BBC.COMMAND_PASTE.send(player, player.getPosition().toBlockVector()); } } \ No newline at end of file diff --git a/core/src/main/java/com/boydti/fawe/command/CFICommands.java b/core/src/main/java/com/boydti/fawe/command/CFICommands.java index c2c788a5..0de2f8e1 100644 --- a/core/src/main/java/com/boydti/fawe/command/CFICommands.java +++ b/core/src/main/java/com/boydti/fawe/command/CFICommands.java @@ -840,6 +840,9 @@ public class CFICommands extends MethodCommands { if (settings.mask != null) maskArgs.append(" " + settings.maskArg); if (!settings.whiteOnly) maskArgs.append(" -w"); + String height = Commands.getAlias(CFICommands.class, "height"); + String waterHeight = Commands.getAlias(CFICommands.class, "waterheight"); + String snow = Commands.getAlias(CFICommands.class, "snow"); Message msg = msg("&8>>&7 Current Settings &8<<&7").newline() .text("&7Mask ").text("&7[&a" + mask + "&7]").cmdTip(alias() + " mask") @@ -849,11 +852,11 @@ public class CFICommands extends MethodCommands { .newline() .text("&8>>&7 Components &8<<&7") .newline() - .text("&7[&aHeight&7]").suggestTip(alias() + " height 120").text(" - Terrain height for whole map") + .text("&7[&aHeight&7]").suggestTip(alias() + " " + alias("height") + " 120").text(" - Terrain height for whole map") .newline() - .text("&7[&aWaterHeight&7]").suggestTip(alias() + " waterHeight 60").text(" - Sea level for whole map") + .text("&7[&aWaterHeight&7]").suggestTip(alias() + " " + alias("waterheight") + " 60").text(" - Sea level for whole map") .newline() - .text("&7[&aSnow&7]").suggestTip(alias() + " snow" + maskArgs).text(" - Set snow in the masked areas") + .text("&7[&aSnow&7]").suggestTip(alias() + " " + alias("snow") + maskArgs).text(" - Set snow in the masked areas") .newline(); if (pattern != null) { @@ -1006,6 +1009,10 @@ public class CFICommands extends MethodCommands { return Commands.getAlias(CFICommand.class, "/cfi"); } + protected String alias(String command) { + return Commands.getAlias(CFICommands.class, command); + } + protected Message msg(String text) { return new Message().newline() .text(BBC.getPrefix()) diff --git a/core/src/main/java/com/boydti/fawe/config/BBC.java b/core/src/main/java/com/boydti/fawe/config/BBC.java index b5af12c8..93f21260 100644 --- a/core/src/main/java/com/boydti/fawe/config/BBC.java +++ b/core/src/main/java/com/boydti/fawe/config/BBC.java @@ -203,8 +203,10 @@ public enum BBC { SELECTOR_FUZZY_POS1("Region set and expanded from %s0 %s1.", "WorldEdit.Selector"), SELECTOR_FUZZY_POS2("Added expansion of %s0 %s1.", "WorldEdit.Selector"), - SELECTOR_CUBOID_POS1("pos1 set to %s0 %s1.", "WorldEdit.Selector"), - SELECTOR_CUBOID_POS2("pos2 set to %s0 %s1.", "WorldEdit.Selector"), + SELECTOR_POS("pos%s0 set to %s1 (%s2).", "WorldEdit.Selector"), + SELECTOR_CENTER("Center set to %s0 (%s1).", "WorldEdit.Selector"), + SELECTOR_RADIUS("Radius set to %s0 (%s1).", "WorldEdit.Selector"), + SELECTOR_EXPANDED("Expanded region to %s0 (%s1)", "WorldEdit.Selector"), SELECTOR_INVALID_COORDINATES("Invalid coordinates %s0", "WorldEdit.Selector"), SELECTOR_ALREADY_SET("Position already set.", "WorldEdit.Selector"), SELECTOR_SET_DEFAULT("Your default region selector is now %s0.", "WorldEdit.Selector"), diff --git a/core/src/main/java/com/boydti/fawe/object/RegionWrapper.java b/core/src/main/java/com/boydti/fawe/object/RegionWrapper.java index e2f4b29c..9f6155ab 100644 --- a/core/src/main/java/com/boydti/fawe/object/RegionWrapper.java +++ b/core/src/main/java/com/boydti/fawe/object/RegionWrapper.java @@ -3,12 +3,12 @@ package com.boydti.fawe.object; import com.sk89q.worldedit.Vector; public class RegionWrapper { - public int minX; - public int maxX; - public int minY; - public int maxY; - public int minZ; - public int maxZ; + public final int minX; + public final int maxX; + public final int minY; + public final int maxY; + public final int minZ; + public final int maxZ; public static RegionWrapper GLOBAL() { return new RegionWrapper(Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE); @@ -40,25 +40,8 @@ public class RegionWrapper { return new RegionWrapper[]{this}; } - private int ly = Integer.MIN_VALUE; - private int lz = Integer.MIN_VALUE; - private boolean lr, lry, lrz; - public boolean isIn(int x, int y, int z) { - if (z != lz) { - lz = z; - lrz = z >= this.minZ && z <= this.maxZ; - if (y != ly) { - ly = y; - lry = y >= this.minY && y <= this.maxY; - } - lr = lrz && lry; - } else if (y != ly) { - ly = y; - lry = y >= this.minY && y <= this.maxY; - lr = lrz && lry; - } - return lr && (x >= this.minX && x <= this.maxX); + return (x >= this.minX) && (x <= this.maxX) && (z >= this.minZ) && (z <= this.maxZ) && (y >= this.minY) && (y <= this.maxY); } public boolean isInChunk(int cx, int cz) { diff --git a/core/src/main/java/com/boydti/fawe/regions/FaweMask.java b/core/src/main/java/com/boydti/fawe/regions/FaweMask.java index 65a2c991..c6214cd4 100644 --- a/core/src/main/java/com/boydti/fawe/regions/FaweMask.java +++ b/core/src/main/java/com/boydti/fawe/regions/FaweMask.java @@ -16,16 +16,15 @@ public class FaweMask { throw new IllegalArgumentException("BlockVectors cannot be null!"); } this.description = id; - this.position1 = new BlockVector(Math.min(pos1.getBlockX(), pos2.getBlockX()), 0, Math.min(pos1.getBlockZ(), pos2.getBlockZ())); - this.position2 = new BlockVector(Math.max(pos1.getBlockX(), pos2.getBlockX()), 256, Math.max(pos1.getBlockZ(), pos2.getBlockZ())); + this.position1 = new BlockVector(Math.min(pos1.getBlockX(), pos2.getBlockX()), pos1.getBlockY(), Math.min(pos1.getBlockZ(), pos2.getBlockZ())); + this.position2 = new BlockVector(Math.max(pos1.getBlockX(), pos2.getBlockX()), pos2.getBlockY(), Math.max(pos1.getBlockZ(), pos2.getBlockZ())); } public FaweMask(final BlockVector pos1, final BlockVector pos2) { + this(pos1, pos2, null); if ((pos1 == null) || (pos2 == null)) { throw new IllegalArgumentException("BlockVectors cannot be null!"); } - this.position1 = new BlockVector(Math.min(pos1.getBlockX(), pos2.getBlockX()), 0, Math.min(pos1.getBlockZ(), pos2.getBlockZ())); - this.position2 = new BlockVector(Math.max(pos1.getBlockX(), pos2.getBlockX()), 256, Math.max(pos1.getBlockZ(), pos2.getBlockZ())); } public HashSet getRegions() { diff --git a/core/src/main/java/com/sk89q/worldedit/EditSession.java b/core/src/main/java/com/sk89q/worldedit/EditSession.java index 985be9a4..4f327950 100644 --- a/core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -268,13 +268,13 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting if (world instanceof MCAWorld) { queue = ((MCAWorld) world).getQueue(); } else { - queue = SetQueue.IMP.getNewQueue(this, fastmode || limit.FAST_PLACEMENT, autoQueue); + queue = SetQueue.IMP.getNewQueue(this, fastmode || this.limit.FAST_PLACEMENT, autoQueue); } } if (combineStages == null) { combineStages = Settings.IMP.HISTORY.COMBINE_STAGES && !(queue instanceof MCAQueue); } - if (!limit.FAST_PLACEMENT || !queue.supportsChangeTask()) { + if (!this.limit.FAST_PLACEMENT || !queue.supportsChangeTask()) { combineStages = false; } if (this.blockBag != null) { @@ -313,24 +313,24 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting changeSet = new MemoryOptimizedHistory(world); } } - if (limit.SPEED_REDUCTION > 0) { - this.bypassHistory = new SlowExtent(this.bypassHistory, limit.SPEED_REDUCTION); + if (this.limit.SPEED_REDUCTION > 0) { + this.bypassHistory = new SlowExtent(this.bypassHistory, this.limit.SPEED_REDUCTION); } if (!(changeSet instanceof NullChangeSet)) { if (player != null && Fawe.imp().getBlocksHubApi() != null) { changeSet = LoggingChangeSet.wrap(player, changeSet); } + if (this.blockBag != null) { + changeSet = new BlockBagChangeSet(changeSet, blockBag, limit.INVENTORY_MODE == 1); + } if (combineStages) { - if (this.blockBag != null) { - changeSet = new BlockBagChangeSet(changeSet, blockBag, limit.INVENTORY_MODE == 1); - } changeTask = changeSet; changeSet.addChangeTask(queue); } else { this.extent = (history = new HistoryExtent(this, bypassHistory, changeSet, queue)); - if (this.blockBag != null) { - this.extent = new BlockBagExtent(this.extent, blockBag, limit.INVENTORY_MODE == 1); - } +// if (this.blockBag != null) { +// this.extent = new BlockBagExtent(this.extent, blockBag, limit.INVENTORY_MODE == 1); +// } } } } @@ -341,13 +341,14 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting } else { this.extent = new ProcessedWEExtent(this.extent, this.limit); if (allowedRegions.length == 1) { - this.extent = new SingleRegionExtent(this.extent, limit, allowedRegions[0]); + RegionWrapper region = allowedRegions[0]; + this.extent = new SingleRegionExtent(this.extent, this.limit, allowedRegions[0]); } else { - this.extent = new MultiRegionExtent(this.extent, limit, allowedRegions); + this.extent = new MultiRegionExtent(this.extent, this.limit, allowedRegions); } } } else { - this.extent = new HeightBoundExtent(this.extent, limit, 0, maxY); + this.extent = new HeightBoundExtent(this.extent, this.limit, 0, maxY); } this.extent = wrapExtent(this.extent, bus, event, Stage.BEFORE_HISTORY); } @@ -889,36 +890,47 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting * @return a map of missing blocks */ public Map popMissingBlocks() { - ChangeSet changeSet = getChangeSet(); - if (changeSet instanceof BlockBagChangeSet) { - BlockBagChangeSet bbcs = (BlockBagChangeSet) changeSet; - BlockBag bag = bbcs.getBlockBag(); - if (bag != null) { - bag.flushChanges(); - Map missingBlocks = ((BlockBagChangeSet) changeSet).popMissing(); - if (!missingBlocks.isEmpty()) { - StringBuilder str = new StringBuilder(); - int size = missingBlocks.size(); - int i = 0; + BlockBag bag = getBlockBag(); + if (bag != null) { + bag.flushChanges(); - for (Map.Entry entry : missingBlocks.entrySet()) { - int combined = entry.getKey(); - int id = FaweCache.getId(combined); - int data = FaweCache.getData(combined); - int amount = entry.getValue(); - BlockType type = BlockType.fromID(id); - str.append((type != null ? type.getName() : "" + id)) - .append((data != 0 ? ":" + data : "")) - .append((amount != 1 ? "x" + amount : "")); - ++i; - if (i != size) { - str.append(", "); - } - } + Map missingBlocks; + ChangeSet changeSet = getChangeSet(); - BBC.WORLDEDIT_SOME_FAILS_BLOCKBAG.send(player, str.toString()); + + if (changeSet instanceof BlockBagChangeSet) { + missingBlocks = ((BlockBagChangeSet) changeSet).popMissing(); + } else { + ExtentTraverser find = new ExtentTraverser(extent).find(BlockBagExtent.class); + if (find != null && find.get() != null) { + missingBlocks = find.get().popMissing(); + } else { + missingBlocks = null; } } + + if (missingBlocks != null && !missingBlocks.isEmpty()) { + StringBuilder str = new StringBuilder(); + int size = missingBlocks.size(); + int i = 0; + + for (Map.Entry entry : missingBlocks.entrySet()) { + int combined = entry.getKey(); + int id = FaweCache.getId(combined); + int data = FaweCache.getData(combined); + int amount = entry.getValue(); + BlockType type = BlockType.fromID(id); + str.append((type != null ? type.getName() : "" + id)) + .append((data != 0 ? ":" + data : "")) + .append((amount != 1 ? "x" + amount : "")); + ++i; + if (i != size) { + str.append(", "); + } + } + + BBC.WORLDEDIT_SOME_FAILS_BLOCKBAG.send(player, str.toString()); + } } return new HashMap<>(); } @@ -1616,7 +1628,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting Vector pos2 = region.getMaximumPoint(); boolean contains = false; for (RegionWrapper current : regionExtent.getRegions()) { - if (current.isIn((int) pos1.getX(), pos1.getBlockZ()) && current.isIn((int) pos2.getX(), pos2.getBlockZ())) { + if (current.isIn((int) pos1.getX(), pos1.getBlockY(), pos1.getBlockZ()) && current.isIn(pos2.getBlockX(), pos2.getBlockY(), pos2.getBlockZ())) { contains = true; break; } diff --git a/core/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java b/core/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java index d7adfeca..a10ed138 100644 --- a/core/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java +++ b/core/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java @@ -1,5 +1,7 @@ package com.sk89q.worldedit.extent.inventory; +import com.boydti.fawe.FaweCache; +import com.boydti.fawe.object.exception.FaweException; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; @@ -87,31 +89,23 @@ public class BlockBagExtent extends AbstractDelegateExtent { @Override public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException { CompoundTag nbt = block.getNbtData(); - final int type = block.getType(); - if (type != 0) { + int combinedTo = block.getCombined(); + if (combinedTo != 0) { try { - blockBag.fetchPlacedBlock(block.getId(), block.getData()); - if (nbt != null) { - // Remove items (to avoid duplication) - if (nbt.containsKey("items")) { - block.setNbtData(null); - } - } + blockBag.fetchPlacedBlock(FaweCache.getId(combinedTo), FaweCache.getData(combinedTo)); } catch (UnplaceableBlockException e) { - return false; + throw new FaweException.FaweBlockBagException(); } catch (BlockBagException e) { - missingBlocks[type]++; - return false; - } catch (Throwable e) { - throw e; + missingBlocks[combinedTo]++; + throw new FaweException.FaweBlockBagException(); } } if (mine) { BaseBlock lazyBlock = getExtent().getLazyBlock(x, y, z); - int existing = lazyBlock.getType(); - if (existing != 0) { + int combinedFrom = lazyBlock.getCombined(); + if (combinedFrom != 0) { try { - blockBag.storeDroppedBlock(existing, lazyBlock.getData()); + blockBag.storeDroppedBlock(FaweCache.getId(combinedFrom), FaweCache.getData(combinedFrom)); } catch (BlockBagException ignored) { } } diff --git a/core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java b/core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java index b3f1fa71..9815571e 100644 --- a/core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java +++ b/core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java @@ -92,6 +92,7 @@ public class EllipsoidRegion extends AbstractRegion { @Override public int getArea() { + if (radius == null) return 0; return (int) Math.floor((4.0 / 3.0) * Math.PI * radius.getX() * radius.getY() * radius.getZ()); } @@ -173,6 +174,7 @@ public class EllipsoidRegion extends AbstractRegion { * @return radii */ public Vector getRadius() { + if (radius == null) return null; return radius.subtract(0.5, 0.5, 0.5); } diff --git a/core/src/main/java/com/sk89q/worldedit/regions/selector/ConvexPolyhedralRegionSelector.java b/core/src/main/java/com/sk89q/worldedit/regions/selector/ConvexPolyhedralRegionSelector.java new file mode 100644 index 00000000..dfb9021b --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/regions/selector/ConvexPolyhedralRegionSelector.java @@ -0,0 +1,278 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.regions.selector; + +import com.boydti.fawe.config.BBC; +import com.google.common.base.Optional; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.BlockVector2D; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.cui.CUIRegion; +import com.sk89q.worldedit.internal.cui.SelectionPointEvent; +import com.sk89q.worldedit.internal.cui.SelectionPolygonEvent; +import com.sk89q.worldedit.regions.ConvexPolyhedralRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.polyhedron.Triangle; +import com.sk89q.worldedit.regions.selector.limit.SelectorLimits; +import com.sk89q.worldedit.world.World; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Nullable; + + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Creates a {@code ConvexPolyhedralRegion} from a user's selections. + */ +public class ConvexPolyhedralRegionSelector extends com.sk89q.worldedit.regions.ConvexPolyhedralRegionSelector implements RegionSelector, CUIRegion { + + private final transient ConvexPolyhedralRegion region; + private transient BlockVector pos1; + + /** + * Create a new selector with a {@code null} world. + */ + public ConvexPolyhedralRegionSelector() { + this((World) null); + } + + /** + * Create a new selector. + * + * @param world the world, which may be {@code null} + */ + public ConvexPolyhedralRegionSelector(@Nullable World world) { + region = new ConvexPolyhedralRegion(world); + } + + /** + * Create a new selector. + * + * @param oldSelector the old selector + */ + public ConvexPolyhedralRegionSelector(RegionSelector oldSelector) { + checkNotNull(oldSelector); + + if (oldSelector instanceof ConvexPolyhedralRegionSelector) { + final ConvexPolyhedralRegionSelector convexPolyhedralRegionSelector = (ConvexPolyhedralRegionSelector) oldSelector; + + pos1 = convexPolyhedralRegionSelector.pos1; + region = new ConvexPolyhedralRegion(convexPolyhedralRegionSelector.region); + } else { + final Region oldRegion; + try { + oldRegion = oldSelector.getRegion(); + } catch (IncompleteRegionException e) { + region = new ConvexPolyhedralRegion(oldSelector.getIncompleteRegion().getWorld()); + return; + } + + final int minY = oldRegion.getMinimumPoint().getBlockY(); + final int maxY = oldRegion.getMaximumPoint().getBlockY(); + + region = new ConvexPolyhedralRegion(oldRegion.getWorld()); + + for (final BlockVector2D pt : new ArrayList(oldRegion.polygonize(Integer.MAX_VALUE))) { + region.addVertex(pt.toVector(minY)); + region.addVertex(pt.toVector(maxY)); + } + + learnChanges(); + } + } + + @Nullable + @Override + public World getWorld() { + return region.getWorld(); + } + + @Override + public void setWorld(@Nullable World world) { + region.setWorld(world); + } + + @Override + public boolean selectPrimary(Vector position, SelectorLimits limits) { + checkNotNull(position); + clear(); + pos1 = position.toBlockVector(); + return region.addVertex(position); + } + + @Override + public boolean selectSecondary(Vector position, SelectorLimits limits) { + checkNotNull(position); + + Optional vertexLimit = limits.getPolyhedronVertexLimit(); + + if (vertexLimit.isPresent() && region.getVertices().size() > vertexLimit.get()) { + return false; + } + + return region.addVertex(position); + } + + @Override + public BlockVector getPrimaryPosition() throws IncompleteRegionException { + return pos1; + } + + @Override + public Region getRegion() throws IncompleteRegionException { + if (!region.isDefined()) { + throw new IncompleteRegionException(); + } + + return region; + } + + @Override + public Region getIncompleteRegion() { + return region; + } + + @Override + public boolean isDefined() { + return region.isDefined(); + } + + @Override + public int getArea() { + return region.getArea(); + } + + @Override + public void learnChanges() { + pos1 = region.getVertices().iterator().next().toBlockVector(); + } + + @Override + public void clear() { + region.clear(); + } + + @Override + public String getTypeName() { + return "Convex Polyhedron"; + } + + @Override + public List getInformationLines() { + List ret = new ArrayList(); + + ret.add("Vertices: "+region.getVertices().size()); + ret.add("Triangles: "+region.getTriangles().size()); + + return ret; + } + + + @Override + public void explainPrimarySelection(Actor player, LocalSession session, Vector pos) { + checkNotNull(player); + checkNotNull(session); + checkNotNull(pos); + + session.describeCUI(player); + + BBC.SELECTOR_POS.send(player, 1, pos, region.getArea()); + } + + @Override + public void explainSecondarySelection(Actor player, LocalSession session, Vector pos) { + checkNotNull(player); + checkNotNull(session); + checkNotNull(pos); + + session.describeCUI(player); + + BBC.SELECTOR_POS.send(player, region.getVertices().size(), pos, region.getArea()); + } + + @Override + public void explainRegionAdjust(Actor player, LocalSession session) { + checkNotNull(player); + checkNotNull(session); + session.describeCUI(player); + } + + @Override + public int getProtocolVersion() { + return 3; + } + + @Override + public String getTypeID() { + return "polyhedron"; + } + + @Override + public void describeCUI(LocalSession session, Actor player) { + checkNotNull(player); + checkNotNull(session); + + Collection vertices = region.getVertices(); + Collection triangles = region.getTriangles(); + + Map vertexIds = new HashMap(vertices.size()); + int lastVertexId = -1; + for (Vector vertex : vertices) { + vertexIds.put(vertex, ++lastVertexId); + session.dispatchCUIEvent(player, new SelectionPointEvent(lastVertexId, vertex, getArea())); + } + + for (Triangle triangle : triangles) { + final int[] v = new int[3]; + for (int i = 0; i < 3; ++i) { + v[i] = vertexIds.get(triangle.getVertex(i)); + } + session.dispatchCUIEvent(player, new SelectionPolygonEvent(v)); + } + } + + @Override + public String getLegacyTypeID() { + return "cuboid"; + } + + @Override + public void describeLegacyCUI(LocalSession session, Actor player) { + checkNotNull(player); + checkNotNull(session); + + if (isDefined()) { + session.dispatchCUIEvent(player, new SelectionPointEvent(0, region.getMinimumPoint(), getArea())); + session.dispatchCUIEvent(player, new SelectionPointEvent(1, region.getMaximumPoint(), getArea())); + } + } + + public static Class inject() { + return ConvexPolyhedralRegionSelector.class; + } +} diff --git a/core/src/main/java/com/sk89q/worldedit/regions/selector/CuboidRegionSelector.java b/core/src/main/java/com/sk89q/worldedit/regions/selector/CuboidRegionSelector.java index eeb3bac7..ddf01129 100644 --- a/core/src/main/java/com/sk89q/worldedit/regions/selector/CuboidRegionSelector.java +++ b/core/src/main/java/com/sk89q/worldedit/regions/selector/CuboidRegionSelector.java @@ -157,9 +157,9 @@ public class CuboidRegionSelector extends com.sk89q.worldedit.regions.CuboidRegi Message msg; if (position1 != null && position2 != null) { - msg = BBC.SELECTOR_CUBOID_POS1.m(position1, "(" + region.getArea() + ")"); + msg = BBC.SELECTOR_POS.m(1, position1, region.getArea()); } else { - msg = BBC.SELECTOR_CUBOID_POS1.m(position1, ""); + msg = BBC.SELECTOR_POS.m(1, position1, ""); } String cmd = Commands.getAlias(SelectionCommands.class, "/pos1") + " " + pos.getBlockX() + "," + pos.getBlockY() + "," + pos.getBlockZ(); msg.suggestTip(cmd).send(player); @@ -175,9 +175,9 @@ public class CuboidRegionSelector extends com.sk89q.worldedit.regions.CuboidRegi Message msg; if (position1 != null && position2 != null) { - msg = BBC.SELECTOR_CUBOID_POS2.m(position2, "(" + region.getArea() + ")"); + msg = BBC.SELECTOR_POS.m(2, position2, region.getArea()); } else { - msg = BBC.SELECTOR_CUBOID_POS2.m(position2, ""); + msg = BBC.SELECTOR_POS.m(2, position2, ""); } String cmd = Commands.getAlias(SelectionCommands.class, "/pos2") + " " + pos.getBlockX() + "," + pos.getBlockY() + "," + pos.getBlockZ(); msg.suggestTip(cmd).send(player); diff --git a/core/src/main/java/com/sk89q/worldedit/regions/selector/CylinderRegionSelector.java b/core/src/main/java/com/sk89q/worldedit/regions/selector/CylinderRegionSelector.java new file mode 100644 index 00000000..906c11a0 --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/regions/selector/CylinderRegionSelector.java @@ -0,0 +1,285 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.regions.selector; + +import com.boydti.fawe.config.BBC; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.cui.CUIRegion; +import com.sk89q.worldedit.internal.cui.SelectionCylinderEvent; +import com.sk89q.worldedit.internal.cui.SelectionMinMaxEvent; +import com.sk89q.worldedit.internal.cui.SelectionPointEvent; +import com.sk89q.worldedit.regions.CylinderRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.limit.SelectorLimits; +import com.sk89q.worldedit.world.World; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nullable; + + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Creates a {@code CylinderRegionSelector} from a user's selections. + */ +public class CylinderRegionSelector extends com.sk89q.worldedit.regions.CylinderRegionSelector implements RegionSelector, CUIRegion { + + protected static transient final NumberFormat NUMBER_FORMAT; + protected transient CylinderRegion region; + + static { + NUMBER_FORMAT = (NumberFormat) NumberFormat.getInstance().clone(); + NUMBER_FORMAT.setMaximumFractionDigits(3); + } + + /** + * Create a new region selector with a {@code null} world. + */ + public CylinderRegionSelector() { + this((World) null); + } + + /** + * Create a new region selector. + * + * @param world the world, which may be {@code null} + */ + public CylinderRegionSelector(@Nullable World world) { + region = new CylinderRegion(world); + } + + /** + * Create a new selector from the given one. + * + * @param oldSelector the old selector + */ + public CylinderRegionSelector(RegionSelector oldSelector) { + this(checkNotNull(oldSelector).getIncompleteRegion().getWorld()); + + if (oldSelector instanceof CylinderRegionSelector) { + final CylinderRegionSelector cylSelector = (CylinderRegionSelector) oldSelector; + + region = new CylinderRegion(cylSelector.region); + } else { + final Region oldRegion; + try { + oldRegion = oldSelector.getRegion(); + } catch (IncompleteRegionException e) { + return; + } + + Vector pos1 = oldRegion.getMinimumPoint(); + Vector pos2 = oldRegion.getMaximumPoint(); + + Vector center = pos1.add(pos2).divide(2).floor(); + region.setCenter(center.toVector2D()); + region.setRadius(pos2.toVector2D().subtract(center.toVector2D())); + + region.setMaximumY(Math.max(pos1.getBlockY(), pos2.getBlockY())); + region.setMinimumY(Math.min(pos1.getBlockY(), pos2.getBlockY())); + } + } + + /** + * Create a new selector. + * + * @param world the world + * @param center the center + * @param radius the radius + * @param minY the minimum Y + * @param maxY the maximum Y + */ + public CylinderRegionSelector(@Nullable World world, Vector2D center, Vector2D radius, int minY, int maxY) { + this(world); + + region.setCenter(center); + region.setRadius(radius); + + region.setMinimumY(Math.min(minY, maxY)); + region.setMaximumY(Math.max(minY, maxY)); + } + + @Nullable + @Override + public World getWorld() { + return region.getWorld(); + } + + @Override + public void setWorld(@Nullable World world) { + region.setWorld(world); + } + + @Override + public boolean selectPrimary(Vector position, SelectorLimits limits) { + if (!region.getCenter().equals(Vector.ZERO) && position.compareTo(region.getCenter()) == 0) { + return false; + } + + region = new CylinderRegion(region.getWorld()); + region.setCenter(position.toVector2D()); + region.setY(position.getBlockY()); + + return true; + } + + @Override + public boolean selectSecondary(Vector position, SelectorLimits limits) { + Vector center = region.getCenter(); + if ((center.compareTo(Vector.ZERO)) == 0) { + return true; + } + + final Vector2D diff = position.subtract(center).toVector2D(); + final Vector2D minRadius = Vector2D.getMaximum(diff, diff.multiply(-1.0)); + region.extendRadius(minRadius); + + region.setY(position.getBlockY()); + + return true; + } + + @Override + public void explainPrimarySelection(Actor player, LocalSession session, Vector pos) { + BBC.SELECTOR_CENTER.send(player, pos, 0); + + session.describeCUI(player); + } + + @Override + public void explainSecondarySelection(Actor player, LocalSession session, Vector pos) { + Vector center = region.getCenter(); + + if (!center.equals(Vector.ZERO)) { + BBC.SELECTOR_RADIUS.send(player, NUMBER_FORMAT.format(region.getRadius().getX()) + "/" + NUMBER_FORMAT.format(region.getRadius().getZ()), region.getArea()); + } else { + BBC.SELECTION_WAND.send(player); + return; + } + + session.describeCUI(player); + } + + @Override + public void explainRegionAdjust(Actor player, LocalSession session) { + session.describeCUI(player); + } + + @Override + public BlockVector getPrimaryPosition() throws IncompleteRegionException { + if (!isDefined()) { + throw new IncompleteRegionException(); + } + + return region.getCenter().toBlockVector(); + } + + @Override + public CylinderRegion getRegion() throws IncompleteRegionException { + if (!isDefined()) { + throw new IncompleteRegionException(); + } + + return region; + } + + @Override + public CylinderRegion getIncompleteRegion() { + return region; + } + + @Override + public boolean isDefined() { + return !region.getRadius().equals(Vector2D.ZERO); + } + + @Override + public void learnChanges() { + } + + @Override + public void clear() { + region = new CylinderRegion(region.getWorld()); + } + + @Override + public String getTypeName() { + return "Cylinder"; + } + + @Override + public List getInformationLines() { + final List lines = new ArrayList(); + + if (!region.getCenter().equals(Vector.ZERO)) { + lines.add("Center: " + region.getCenter()); + } + if (!region.getRadius().equals(Vector2D.ZERO)) { + lines.add("Radius: " + region.getRadius()); + } + + return lines; + } + + @Override + public int getArea() { + return region.getArea(); + } + + @Override + public void describeCUI(LocalSession session, Actor player) { + session.dispatchCUIEvent(player, new SelectionCylinderEvent(region.getCenter(), region.getRadius())); + session.dispatchCUIEvent(player, new SelectionMinMaxEvent(region.getMinimumY(), region.getMaximumY())); + } + + @Override + public void describeLegacyCUI(LocalSession session, Actor player) { + if (isDefined()) { + session.dispatchCUIEvent(player, new SelectionPointEvent(0, region.getMinimumPoint(), getArea())); + session.dispatchCUIEvent(player, new SelectionPointEvent(1, region.getMaximumPoint(), getArea())); + } + } + + @Override + public int getProtocolVersion() { + return 1; + } + + @Override + public String getTypeID() { + return "cylinder"; + } + + @Override + public String getLegacyTypeID() { + return "cuboid"; + } + + public static Class inject() { + return CylinderRegionSelector.class; + } +} diff --git a/core/src/main/java/com/sk89q/worldedit/regions/selector/EllipsoidRegionSelector.java b/core/src/main/java/com/sk89q/worldedit/regions/selector/EllipsoidRegionSelector.java new file mode 100644 index 00000000..48d4779e --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/regions/selector/EllipsoidRegionSelector.java @@ -0,0 +1,255 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.regions.selector; + +import com.boydti.fawe.config.BBC; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.cui.CUIRegion; +import com.sk89q.worldedit.internal.cui.SelectionEllipsoidPointEvent; +import com.sk89q.worldedit.internal.cui.SelectionPointEvent; +import com.sk89q.worldedit.regions.EllipsoidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.limit.SelectorLimits; +import com.sk89q.worldedit.world.World; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nullable; + + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Creates a {@code EllipsoidRegionSelector} from a user's selections. + */ +public class EllipsoidRegionSelector extends com.sk89q.worldedit.regions.EllipsoidRegionSelector implements RegionSelector, CUIRegion { + + protected transient EllipsoidRegion region; + protected transient boolean started = false; + + /** + * Create a new selector with a {@code null} world. + */ + public EllipsoidRegionSelector() { + this((World) null); + } + + /** + * Create a new selector. + * + * @param world the world, which may be {@code null} + */ + public EllipsoidRegionSelector(@Nullable World world) { + region = new EllipsoidRegion(world, new Vector(), new Vector()); + } + + /** + * Create a new selector from the given selector. + * + * @param oldSelector the old selector + */ + public EllipsoidRegionSelector(RegionSelector oldSelector) { + this(checkNotNull(oldSelector).getIncompleteRegion().getWorld()); + if (oldSelector instanceof EllipsoidRegionSelector) { + final EllipsoidRegionSelector ellipsoidRegionSelector = (EllipsoidRegionSelector) oldSelector; + + region = new EllipsoidRegion(ellipsoidRegionSelector.getIncompleteRegion()); + } else { + Region oldRegion; + try { + oldRegion = oldSelector.getRegion(); + } catch (IncompleteRegionException e) { + return; + } + + BlockVector pos1 = oldRegion.getMinimumPoint().toBlockVector(); + BlockVector pos2 = oldRegion.getMaximumPoint().toBlockVector(); + + Vector center = pos1.add(pos2).divide(2).floor(); + region.setCenter(center); + region.setRadius(pos2.subtract(center)); + } + } + + /** + * Create a new selector. + * + * @param world the world + * @param center the center + * @param radius the radius + */ + public EllipsoidRegionSelector(@Nullable World world, Vector center, Vector radius) { + this(world); + + region.setCenter(center); + region.setRadius(radius); + } + + @Nullable + @Override + public World getWorld() { + return region.getWorld(); + } + + @Override + public void setWorld(@Nullable World world) { + region.setWorld(world); + } + + @Override + public boolean selectPrimary(Vector position, SelectorLimits limits) { + if (position.equals(region.getCenter()) && region.getRadius().lengthSq() == 0) { + return false; + } + + region.setCenter(position.toBlockVector()); + region.setRadius(new Vector()); + started = true; + + return true; + } + + @Override + public boolean selectSecondary(Vector position, SelectorLimits limits) { + if (!started) { + return false; + } + + final Vector diff = position.subtract(region.getCenter()); + final Vector minRadius = Vector.getMaximum(diff, diff.multiply(-1.0)); + region.extendRadius(minRadius); + return true; + } + + @Override + public void explainPrimarySelection(Actor player, LocalSession session, Vector pos) { + BBC.SELECTOR_CENTER.send(player, region.getCenter(), region.getArea()); + + session.describeCUI(player); + } + + @Override + public void explainSecondarySelection(Actor player, LocalSession session, Vector pos) { + BBC.SELECTOR_RADIUS.send(player, region.getRadius(), region.getArea()); + + session.describeCUI(player); + } + + @Override + public void explainRegionAdjust(Actor player, LocalSession session) { + session.describeCUI(player); + } + + @Override + public boolean isDefined() { + return started && region.getRadius().lengthSq() > 0; + } + + @Override + public EllipsoidRegion getRegion() throws IncompleteRegionException { + if (!isDefined()) { + throw new IncompleteRegionException(); + } + + return region; + } + + @Override + public EllipsoidRegion getIncompleteRegion() { + return region; + } + + @Override + public void learnChanges() { + } + + @Override + public void clear() { + region.setCenter(new Vector()); + region.setRadius(new Vector()); + } + + @Override + public String getTypeName() { + return "ellipsoid"; + } + + @Override + public List getInformationLines() { + final List lines = new ArrayList(); + + final Vector center = region.getCenter(); + if (center.lengthSq() > 0) { + lines.add("Center: " + center); + } + + final Vector radius = region.getRadius(); + if (radius.lengthSq() > 0) { + lines.add("X/Y/Z radius: " + radius); + } + + return lines; + } + + @Override + public int getArea() { + return region.getArea(); + } + + @Override + public void describeCUI(LocalSession session, Actor player) { + session.dispatchCUIEvent(player, new SelectionEllipsoidPointEvent(0, region.getCenter())); + session.dispatchCUIEvent(player, new SelectionEllipsoidPointEvent(1, region.getRadius())); + } + + @Override + public void describeLegacyCUI(LocalSession session, Actor player) { + session.dispatchCUIEvent(player, new SelectionPointEvent(0, region.getMinimumPoint(), getArea())); + session.dispatchCUIEvent(player, new SelectionPointEvent(1, region.getMaximumPoint(), getArea())); + } + + @Override + public String getLegacyTypeID() { + return "cuboid"; + } + + @Override + public int getProtocolVersion() { + return 1; + } + + @Override + public String getTypeID() { + return "ellipsoid"; + } + + @Override + public BlockVector getPrimaryPosition() throws IncompleteRegionException { + return region.getCenter().toBlockVector(); + } + + public static Class inject() { + return EllipsoidRegionSelector.class; + } +} diff --git a/core/src/main/java/com/sk89q/worldedit/regions/selector/ExtendingCuboidRegionSelector.java b/core/src/main/java/com/sk89q/worldedit/regions/selector/ExtendingCuboidRegionSelector.java new file mode 100644 index 00000000..81ac6ce1 --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/regions/selector/ExtendingCuboidRegionSelector.java @@ -0,0 +1,148 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.regions.selector; + +import com.boydti.fawe.config.BBC; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.limit.SelectorLimits; +import com.sk89q.worldedit.world.World; +import javax.annotation.Nullable; + +/** + * Creates a {@code CuboidRegion} from a user's selections by expanding + * the region on every right click. + */ +public class ExtendingCuboidRegionSelector extends CuboidRegionSelector { + + /** + * Create a new selector with a {@code null} world. + */ + public ExtendingCuboidRegionSelector() { + super((World) null); + } + + /** + * Create a new selector. + * + * @param world the world, which may be {@code null} + */ + public ExtendingCuboidRegionSelector(@Nullable World world) { + super(world); + } + + /** + * Create a new selector from another one. + * + * @param oldSelector the other selector + */ + public ExtendingCuboidRegionSelector(RegionSelector oldSelector) { + super(oldSelector); + + if (position1 == null || position2 == null) { + return; + } + + position1 = region.getMinimumPoint().toBlockVector(); + position2 = region.getMaximumPoint().toBlockVector(); + region.setPos1(position1); + region.setPos2(position2); + } + + /** + * Create a new selector. + * + * @param world the world + * @param position1 the first position + * @param position2 the second position + */ + public ExtendingCuboidRegionSelector(@Nullable World world, Vector position1, Vector position2) { + this(world); + position1 = Vector.getMinimum(position1, position2); + position2 = Vector.getMaximum(position1, position2); + region.setPos1(position1); + region.setPos2(position2); + } + + @Override + public boolean selectPrimary(Vector position, SelectorLimits limits) { + if (position1 != null && position2 != null && position.compareTo(position1) == 0 && position.compareTo(position2) == 0) { + return false; + } + + position1 = position2 = position.toBlockVector(); + region.setPos1(position1); + region.setPos2(position2); + return true; + } + + @Override + public boolean selectSecondary(Vector position, SelectorLimits limits) { + if (position1 == null || position2 == null) { + return selectPrimary(position, limits); + } + + if (region.contains(position)) { + return false; + } + + double x1 = Math.min(position.getX(), position1.getX()); + double y1 = Math.min(position.getY(), position1.getY()); + double z1 = Math.min(position.getZ(), position1.getZ()); + + double x2 = Math.max(position.getX(), position2.getX()); + double y2 = Math.max(position.getY(), position2.getY()); + double z2 = Math.max(position.getZ(), position2.getZ()); + + final BlockVector o1 = position1; + final BlockVector o2 = position2; + position1 = new BlockVector(x1, y1, z1); + position2 = new BlockVector(x2, y2, z2); + region.setPos1(position1); + region.setPos2(position2); + + assert(region.contains(o1)); + assert(region.contains(o2)); + assert(region.contains(position)); + + return true; + } + + @Override + public void explainPrimarySelection(Actor player, LocalSession session, Vector pos) { + BBC.SELECTOR_POS.send(player, 1, pos, region.getArea()); + + explainRegionAdjust(player, session); + } + + @Override + public void explainSecondarySelection(Actor player, LocalSession session, Vector pos) { + BBC.SELECTOR_EXPANDED.send(player, 2, pos, region.getArea()); + + explainRegionAdjust(player, session); + } + + public static Class inject() { + return ExtendingCuboidRegionSelector.class; + } +} diff --git a/core/src/main/java/com/sk89q/worldedit/regions/selector/Polygonal2DRegionSelector.java b/core/src/main/java/com/sk89q/worldedit/regions/selector/Polygonal2DRegionSelector.java new file mode 100644 index 00000000..8c2de10e --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/regions/selector/Polygonal2DRegionSelector.java @@ -0,0 +1,295 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.regions.selector; + +import com.boydti.fawe.config.BBC; +import com.google.common.base.Optional; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.BlockVector2D; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.cui.CUIRegion; +import com.sk89q.worldedit.internal.cui.SelectionMinMaxEvent; +import com.sk89q.worldedit.internal.cui.SelectionPoint2DEvent; +import com.sk89q.worldedit.internal.cui.SelectionShapeEvent; +import com.sk89q.worldedit.regions.Polygonal2DRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.limit.SelectorLimits; +import com.sk89q.worldedit.world.World; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nullable; + + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Creates a {@code Polygonal2DRegion} from a user's selections. + */ +public class Polygonal2DRegionSelector extends com.sk89q.worldedit.regions.Polygonal2DRegionSelector implements RegionSelector, CUIRegion { + + private transient BlockVector pos1; + private transient Polygonal2DRegion region; + + /** + * Create a new selector with a {@code null} world. + */ + public Polygonal2DRegionSelector() { + this((World) null); + } + + /** + * Create a new selector with the given world. + * + * @param world the world + */ + public Polygonal2DRegionSelector(@Nullable World world) { + region = new Polygonal2DRegion(world); + } + + /** + * Create a new selector from another one. + * + * @param oldSelector the old selector + */ + public Polygonal2DRegionSelector(RegionSelector oldSelector) { + this(checkNotNull(oldSelector).getIncompleteRegion().getWorld()); + + if (oldSelector instanceof Polygonal2DRegionSelector) { + final Polygonal2DRegionSelector polygonal2DRegionSelector = (Polygonal2DRegionSelector) oldSelector; + + pos1 = polygonal2DRegionSelector.pos1; + region = new Polygonal2DRegion(polygonal2DRegionSelector.region); + } else { + final Region oldRegion; + try { + oldRegion = oldSelector.getRegion(); + } catch (IncompleteRegionException e) { + return; + } + + final int minY = oldRegion.getMinimumPoint().getBlockY(); + final int maxY = oldRegion.getMaximumPoint().getBlockY(); + + List points = oldRegion.polygonize(Integer.MAX_VALUE); + + pos1 = points.get(0).toVector(minY).toBlockVector(); + region = new Polygonal2DRegion(oldRegion.getWorld(), points, minY, maxY); + } + } + + /** + * @deprecated cast {@code world} to {@link com.sk89q.worldedit.world.World} + */ + @Deprecated + public Polygonal2DRegionSelector(@Nullable LocalWorld world, List points, int minY, int maxY) { + this((World) world, points, minY, maxY); + } + + /** + * Create a new selector. + * + * @param world the world + * @param points a list of points + * @param minY the minimum Y + * @param maxY the maximum Y + */ + public Polygonal2DRegionSelector(@Nullable World world, List points, int minY, int maxY) { + checkNotNull(points); + + final BlockVector2D pos2D = points.get(0); + pos1 = new BlockVector(pos2D.getX(), minY, pos2D.getZ()); + region = new Polygonal2DRegion(world, points, minY, maxY); + } + + @Nullable + @Override + public World getWorld() { + return region.getWorld(); + } + + @Override + public void setWorld(@Nullable World world) { + region.setWorld(world); + } + + @Override + public boolean selectPrimary(Vector position, SelectorLimits limits) { + if (position.equals(pos1)) { + return false; + } + + pos1 = position.toBlockVector(); + region = new Polygonal2DRegion(region.getWorld()); + region.addPoint(position); + region.expandY(position.getBlockY()); + + return true; + } + + @Override + public boolean selectSecondary(Vector position, SelectorLimits limits) { + if (region.size() > 0) { + final List points = region.getPoints(); + + final BlockVector2D lastPoint = points.get(region.size() - 1); + if (lastPoint.getBlockX() == position.getBlockX() && lastPoint.getBlockZ() == position.getBlockZ()) { + return false; + } + + Optional vertexLimit = limits.getPolygonVertexLimit(); + + if (vertexLimit.isPresent() && points.size() > vertexLimit.get()) { + return false; + } + } + + region.addPoint(position); + region.expandY(position.getBlockY()); + + return true; + } + + @Override + public void explainPrimarySelection(Actor player, LocalSession session, Vector pos) { + BBC.SELECTOR_POS.send(player, 1, pos, region.getArea()); + + session.dispatchCUIEvent(player, new SelectionShapeEvent(getTypeID())); + session.dispatchCUIEvent(player, new SelectionPoint2DEvent(0, pos, getArea())); + session.dispatchCUIEvent(player, new SelectionMinMaxEvent(region.getMinimumY(), region.getMaximumY())); + } + + @Override + public void explainSecondarySelection(Actor player, LocalSession session, Vector pos) { + BBC.SELECTOR_POS.send(player, region.size(), pos, region.getArea()); + + session.dispatchCUIEvent(player, new SelectionPoint2DEvent(region.size() - 1, pos, getArea())); + session.dispatchCUIEvent(player, new SelectionMinMaxEvent(region.getMinimumY(), region.getMaximumY())); + } + + @Override + public void explainRegionAdjust(Actor player, LocalSession session) { + session.dispatchCUIEvent(player, new SelectionShapeEvent(getTypeID())); + describeCUI(session, player); + } + + @Override + public BlockVector getPrimaryPosition() throws IncompleteRegionException { + if (pos1 == null) { + throw new IncompleteRegionException(); + } + + return pos1; + } + + @Override + public Polygonal2DRegion getRegion() throws IncompleteRegionException { + if (!isDefined()) { + throw new IncompleteRegionException(); + } + + return region; + } + + @Override + public Polygonal2DRegion getIncompleteRegion() { + return region; + } + + @Override + public boolean isDefined() { + return region.size() > 2; + } + + @Override + public void learnChanges() { + BlockVector2D pt = region.getPoints().get(0); + pos1 = new BlockVector(pt.getBlockX(), region.getMinimumPoint().getBlockY(), pt.getBlockZ()); + } + + @Override + public void clear() { + pos1 = null; + region = new Polygonal2DRegion(region.getWorld()); + } + + @Override + public String getTypeName() { + return "2Dx1D polygon"; + } + + @Override + public List getInformationLines() { + return Collections.singletonList("# points: " + region.size()); + } + + @Override + public int getArea() { + return region.getArea(); + } + + /** + * Get the number of points. + * + * @return the number of points + */ + @Override + public int getPointCount() { + return region.getPoints().size(); + } + + @Override + public void describeCUI(LocalSession session, Actor player) { + final List points = region.getPoints(); + for (int id = 0; id < points.size(); id++) { + session.dispatchCUIEvent(player, new SelectionPoint2DEvent(id, points.get(id), getArea())); + } + + session.dispatchCUIEvent(player, new SelectionMinMaxEvent(region.getMinimumY(), region.getMaximumY())); + } + + @Override + public void describeLegacyCUI(LocalSession session, Actor player) { + describeCUI(session, player); + } + + @Override + public int getProtocolVersion() { + return 0; + } + + @Override + public String getTypeID() { + return "polygon2d"; + } + + @Override + public String getLegacyTypeID() { + return "polygon2d"; + } + + public static Class inject() { + return Polygonal2DRegionSelector.class; + } +} diff --git a/core/src/main/java/com/sk89q/worldedit/regions/selector/SphereRegionSelector.java b/core/src/main/java/com/sk89q/worldedit/regions/selector/SphereRegionSelector.java new file mode 100644 index 00000000..4e45612c --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/regions/selector/SphereRegionSelector.java @@ -0,0 +1,102 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.regions.selector; + +import com.boydti.fawe.config.BBC; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.limit.SelectorLimits; +import com.sk89q.worldedit.world.World; +import javax.annotation.Nullable; + +/** + * Creates a {@code SphereRegion} from a user's selections. + */ +public class SphereRegionSelector extends EllipsoidRegionSelector { + + /** + * Create a new selector with a {@code null world}. + */ + public SphereRegionSelector() { + super(); + } + + /** + * Create a new selector. + * + * @param world the world, which may be {@code null} + */ + public SphereRegionSelector(@Nullable World world) { + super(world); + } + + /** + * Create a new selector from another one + * + * @param oldSelector the old selector + */ + public SphereRegionSelector(RegionSelector oldSelector) { + super(oldSelector); + final Vector radius = region.getRadius(); + final double radiusScalar = Math.max(Math.max(radius.getX(), radius.getY()), radius.getZ()); + region.setRadius(new Vector(radiusScalar, radiusScalar, radiusScalar)); + } + + /** + * Create a new selector. + * + * @param world the world + * @param center the center position + * @param radius the radius + */ + public SphereRegionSelector(@Nullable World world, Vector center, int radius) { + super(world, center, new Vector(radius, radius, radius)); + } + + @Override + public boolean selectSecondary(Vector position, SelectorLimits limits) { + if (!started) { + return false; + } + + final double radiusScalar = Math.ceil(position.distance(region.getCenter())); + region.setRadius(new Vector(radiusScalar, radiusScalar, radiusScalar)); + + return true; + } + + @Override + public void explainSecondarySelection(Actor player, LocalSession session, Vector pos) { + BBC.SELECTOR_RADIUS.send(player, region.getRadius().getX(), region.getArea()); + + session.describeCUI(player); + } + + @Override + public String getTypeName() { + return "sphere"; + } + + public static Class inject() { + return SphereRegionSelector.class; + } +}