From 2cb1485553debf541d865471ff52fec95fc4adf3 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Fri, 23 Sep 2016 17:11:41 +1000 Subject: [PATCH] Various Fixes #305 //sel extend bug Translate a few messages Add option `store-redo: true`, disabling will result in smaller history but cannot use redo Add option `small-edits: false` will reduce history by assuming edits < 4096x256x4096 Change FaweStreamChangeSet to use new settings, but be backwards compatible (uses mode byte) Add auto generated semantic version (may not be accurate) Add recursive brush Optimize undo/redo using mutable change objects Tweak several classes to implement HasFaweQueue Fix wrong cancel message for entity/biome changes Optimized offset mask Fixed masks not being reset after edit Added interface ResettableMask used to reset masks after being used for an EditSession Added MaskTraverser for traversing and resetting inherited masks after use Added angle mask \#,# Added id,data,combined mask #id #data #iddata (Must match starting block id/data) Added x,y,z axis mask #xaxis #yaxis #zaxis Add mode 4 FAWE format (short location prefix + no combined from bytes) Fix `/frb` command not respecting regions Tweak permission for `/frb` -> worldedit.history.rollback Translated ToolUtil commands --- build.gradle | 34 ++- .../fawe/bukkit/wrapper/AsyncWorld.java | 3 +- core/src/main/java/com/boydti/fawe/Fawe.java | 8 + .../java/com/boydti/fawe/FaweVersion.java | 6 +- .../main/java/com/boydti/fawe/config/BBC.java | 8 +- .../java/com/boydti/fawe/config/Settings.java | 11 + .../rollback/RollbackOptimizedHistory.java | 5 +- .../com/boydti/fawe/object/FaweLimit.java | 20 ++ .../com/boydti/fawe/object/FawePlayer.java | 13 +- .../com/boydti/fawe/object/HasFaweQueue.java | 5 + .../fawe/object/brush/RecurseBrush.java | 56 ++++ .../object/change/MutableBlockChange.java | 25 +- .../object/change/MutableChunkChange.java | 31 +- .../object/change/MutableEntityChange.java | 37 ++- .../object/change/MutableFullBlockChange.java | 29 +- .../fawe/object/change/MutableTileChange.java | 37 ++- .../object/changeset/DiskStorageHistory.java | 26 +- .../object/changeset/FaweStreamChangeSet.java | 266 ++++++++++++++---- .../changeset/MemoryOptimizedHistory.java | 6 +- .../object/extent/FastWorldEditExtent.java | 5 +- .../boydti/fawe/object/extent/MCAExtent.java | 3 +- .../fawe/object/extent/ProcessedWEExtent.java | 8 +- .../function/mask/AbstractDelegateMask.java | 8 +- .../boydti/fawe/object/mask/AngleMask.java | 186 ++++++++++++ .../com/boydti/fawe/object/mask/DataMask.java | 39 +++ .../boydti/fawe/object/mask/IdDataMask.java | 40 +++ .../com/boydti/fawe/object/mask/IdMask.java | 39 +++ .../fawe/object/mask/ResettableMask.java | 5 + .../boydti/fawe/object/mask/XAxisMask.java | 33 +++ .../boydti/fawe/object/mask/YAxisMask.java | 33 +++ .../boydti/fawe/object/mask/ZAxisMask.java | 33 +++ .../fawe/object/schematic/FaweFormat.java | 202 ++++++------- .../com/boydti/fawe/util/MaskTraverser.java | 48 ++++ .../java/com/sk89q/worldedit/EditSession.java | 20 +- .../worldedit/command/BrushCommands.java | 24 +- .../worldedit/command/HistoryCommands.java | 18 +- .../sk89q/worldedit/command/ToolCommands.java | 1 - .../worldedit/command/ToolUtilCommands.java | 130 +++++++++ .../extension/factory/DefaultMaskParser.java | 187 ++++++++++++ .../sk89q/worldedit/function/mask/Masks.java | 234 +++++++++++++++ .../worldedit/function/mask/OffsetMask.java | 92 ++++++ .../sk89q/worldedit/regions/CuboidRegion.java | 3 + .../selector/CuboidRegionSelector.java | 1 - 43 files changed, 1746 insertions(+), 272 deletions(-) create mode 100644 core/src/main/java/com/boydti/fawe/object/HasFaweQueue.java create mode 100644 core/src/main/java/com/boydti/fawe/object/brush/RecurseBrush.java create mode 100644 core/src/main/java/com/boydti/fawe/object/mask/AngleMask.java create mode 100644 core/src/main/java/com/boydti/fawe/object/mask/DataMask.java create mode 100644 core/src/main/java/com/boydti/fawe/object/mask/IdDataMask.java create mode 100644 core/src/main/java/com/boydti/fawe/object/mask/IdMask.java create mode 100644 core/src/main/java/com/boydti/fawe/object/mask/ResettableMask.java create mode 100644 core/src/main/java/com/boydti/fawe/object/mask/XAxisMask.java create mode 100644 core/src/main/java/com/boydti/fawe/object/mask/YAxisMask.java create mode 100644 core/src/main/java/com/boydti/fawe/object/mask/ZAxisMask.java create mode 100644 core/src/main/java/com/boydti/fawe/util/MaskTraverser.java create mode 100644 core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java create mode 100644 core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultMaskParser.java create mode 100644 core/src/main/java/com/sk89q/worldedit/function/mask/Masks.java create mode 100644 core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java diff --git a/build.gradle b/build.gradle index a30f2435..603c999f 100644 --- a/build.gradle +++ b/build.gradle @@ -18,20 +18,48 @@ group = 'com.boydti.fawe' def revision = "" def buildNumber = "" -final def date = new Date().format("yy.MM.dd") +def semver = "" +def date = "" ext { git = org.ajoberstar.grgit.Grgit.open(file(".git")) + date = git.head().date.format("yy.MM.dd") revision = "-${git.head().abbreviatedId}" parents = git.head().parentIds; index = -45; // Offset to mach CI + int major, minor, patch; + major = minor = patch = 0; for (;parents != null && !parents.isEmpty();index++) { + int majorCount, minorCount, patchCount; + patchCount = 1; commit = git.getResolve().toCommit(parents.get(0)); - parents = commit.getParentIds(); + for (String line : commit.fullMessage.tokenize("\n")) { + switch (line.replaceAll("- ", "").split(" ")[0].toLowerCase()) { + case "minor": + case "added": + case "add": + case "change": + case "changed": + case "changes": + if (majorCount == 0) {minorCount = 1; patch = patchCount = 0;} + break; + case "refactor": + case "remove": + case "major": + patch = minor = minorCount = patchCount = 0; + majorCount = 1; + break; + } + } + major += majorCount; + minor += minorCount; + patch += patchCount; + parents = commit.getParentIds() } buildNumber = "-${index}" + semver = "-${major}.${minor}.${patch}" } -version = date + revision + buildNumber +version = date + revision + buildNumber + semver if ( project.hasProperty("lzNoVersion") ) { // gradle build -PlzNoVersion version = "unknown"; } diff --git a/bukkit0/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java b/bukkit0/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java index 5c0f8a13..0dcb7987 100644 --- a/bukkit0/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java +++ b/bukkit0/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java @@ -3,6 +3,7 @@ package com.boydti.fawe.bukkit.wrapper; import com.boydti.fawe.FaweAPI; import com.boydti.fawe.bukkit.v0.BukkitQueue_0; import com.boydti.fawe.object.FaweQueue; +import com.boydti.fawe.object.HasFaweQueue; import com.boydti.fawe.object.RunnableVal; import com.boydti.fawe.util.SetQueue; import com.boydti.fawe.util.StringMan; @@ -57,7 +58,7 @@ import org.bukkit.util.Vector; * @see #wrap(org.bukkit.World) * @see #create(org.bukkit.WorldCreator) */ -public class AsyncWorld implements World { +public class AsyncWorld implements World, HasFaweQueue { private World parent; private FaweQueue queue; diff --git a/core/src/main/java/com/boydti/fawe/Fawe.java b/core/src/main/java/com/boydti/fawe/Fawe.java index 397cb4ef..21987150 100644 --- a/core/src/main/java/com/boydti/fawe/Fawe.java +++ b/core/src/main/java/com/boydti/fawe/Fawe.java @@ -33,10 +33,12 @@ import com.sk89q.worldedit.command.RegionCommands; import com.sk89q.worldedit.command.SchematicCommands; import com.sk89q.worldedit.command.ScriptingCommands; import com.sk89q.worldedit.command.ToolCommands; +import com.sk89q.worldedit.command.ToolUtilCommands; import com.sk89q.worldedit.command.composition.SelectionCommand; import com.sk89q.worldedit.command.tool.LongRangeBuildTool; import com.sk89q.worldedit.command.tool.brush.GravityBrush; import com.sk89q.worldedit.event.extent.EditSessionEvent; +import com.sk89q.worldedit.extension.factory.DefaultMaskParser; import com.sk89q.worldedit.extension.platform.CommandManager; import com.sk89q.worldedit.extension.platform.PlatformManager; import com.sk89q.worldedit.extent.AbstractDelegateExtent; @@ -48,6 +50,8 @@ import com.sk89q.worldedit.extent.transform.BlockTransformExtent; import com.sk89q.worldedit.function.entity.ExtentEntityCopy; import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.function.mask.FuzzyBlockMask; +import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.function.mask.OffsetMask; import com.sk89q.worldedit.function.mask.SolidBlockMask; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.ClipboardPattern; @@ -337,6 +341,7 @@ public class Fawe { HistoryCommands.inject(); // Translations NavigationCommands.inject(); // Translations + thru fix ParametricBuilder.inject(); // Translations + ToolUtilCommands.inject(); // Fixes + Translations // Schematic SchematicReader.inject(); SchematicWriter.inject(); @@ -379,6 +384,9 @@ public class Fawe { BlockMask.inject(); // Optimizations SolidBlockMask.inject(); // Optimizations FuzzyBlockMask.inject(); // Optimizations + OffsetMask.inject(); // Optimizations + DefaultMaskParser.inject(); // Add new masks + Masks.inject(); // // Operations Operations.inject(); // Optimizations // BlockData diff --git a/core/src/main/java/com/boydti/fawe/FaweVersion.java b/core/src/main/java/com/boydti/fawe/FaweVersion.java index 56f6e218..3e5b7a07 100644 --- a/core/src/main/java/com/boydti/fawe/FaweVersion.java +++ b/core/src/main/java/com/boydti/fawe/FaweVersion.java @@ -1,7 +1,7 @@ package com.boydti.fawe; public class FaweVersion { - public final int year, month, day, hash, build; + public final int year, month, day, hash, build, major, minor, patch; public FaweVersion(String version) { String[] split = version.substring(version.indexOf('=') + 1).split("-"); @@ -11,6 +11,10 @@ public class FaweVersion { this.day = Integer.parseInt(date[2]); this.hash = Integer.parseInt(split[1], 16); this.build = Integer.parseInt(split[2]); + String[] semver = split[3].split("\\."); + this.major = Integer.parseInt(semver[0]); + this.minor = Integer.parseInt(semver[1]); + this.patch = Integer.parseInt(semver[2]); } @Override 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 2460cb5f..1d6886bb 100644 --- a/core/src/main/java/com/boydti/fawe/config/BBC.java +++ b/core/src/main/java/com/boydti/fawe/config/BBC.java @@ -95,7 +95,11 @@ public enum BBC { BRUSH_BLEND_BALL("Blend ball brush equipped (%s0).", "WorldEdit.Brush"), BRUSH_ERODE("Erode brush equipped (%s0).", "WorldEdit.Brush"), BRUSH_PASTE_NONE("Nothing to paste", "WorldEdit.Brush"), - + BRUSH_SIZE("Brush size set", "WorldEdit.Brush"), + BRUSH_RANGE("Brush size set", "WorldEdit.Brush"), + BRUSH_MASK_DISABLED("Brush mask disabled", "WorldEdit.Brush"), + BRUSH_MASK("Brush mask set", "WorldEdit.Brush"), + BRUSH_MATERIAL("Brush material set", "WorldEdit.Brush"), ROLLBACK_ELEMENT("Undoing %s0", "WorldEdit.Rollback"), @@ -114,6 +118,8 @@ public enum BBC { TOOL_FARWAND("Far wand tool bound to %s0.", "WorldEdit.Tool"), TOOL_LRBUILD_BOUND("Long-range building tool bound to %s0.", "WorldEdit.Tool"), TOOL_LRBUILD_INFO("Left-click set to %s0; right-click set to %s1.", "WorldEdit.Tool"), + SUPERPICKAXE_ENABLED("Super Pickaxe enabled.", "WorldEdit.Tool"), + SUPERPICKAXE_DISABLED("Super Pickaxe disabled.", "WorldEdit.Tool"), SCHEMATIC_DELETE("%s0 has been deleted.", "Worldedit.Schematic"), diff --git a/core/src/main/java/com/boydti/fawe/config/Settings.java b/core/src/main/java/com/boydti/fawe/config/Settings.java index c85b5276..bc3f09a7 100644 --- a/core/src/main/java/com/boydti/fawe/config/Settings.java +++ b/core/src/main/java/com/boydti/fawe/config/Settings.java @@ -154,6 +154,17 @@ public class Settings extends Config { " - Use of the FAWE API will not be effected" }) public static boolean ENABLE_FOR_CONSOLE = true; + @Comment({ + "Should redo information be stored:", + " - History is about 20% larger", + " - Enables use of /redo", + }) + public static boolean STORE_REDO = true; + @Comment({ + "Assumes all edits are smaller than 4096x256x4096:", + " - Reduces history size by ~10%", + }) + public static boolean SMALL_EDITS = false; } public static class QUEUE { diff --git a/core/src/main/java/com/boydti/fawe/logging/rollback/RollbackOptimizedHistory.java b/core/src/main/java/com/boydti/fawe/logging/rollback/RollbackOptimizedHistory.java index ad77c35e..d7f3fbe6 100644 --- a/core/src/main/java/com/boydti/fawe/logging/rollback/RollbackOptimizedHistory.java +++ b/core/src/main/java/com/boydti/fawe/logging/rollback/RollbackOptimizedHistory.java @@ -6,6 +6,7 @@ import com.boydti.fawe.object.changeset.DiskStorageHistory; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.world.World; import java.io.IOException; +import java.io.OutputStream; import java.util.UUID; public class RollbackOptimizedHistory extends DiskStorageHistory { @@ -101,13 +102,13 @@ public class RollbackOptimizedHistory extends DiskStorageHistory { } @Override - public void writeHeader(int x, int y, int z) throws IOException { + public void writeHeader(OutputStream os, int x, int y, int z) throws IOException { minX = x; maxX = x; minY = y; maxY = y; minZ = z; maxZ = z; - super.writeHeader(x, y, z); + super.writeHeader(os, x, y, z); } } diff --git a/core/src/main/java/com/boydti/fawe/object/FaweLimit.java b/core/src/main/java/com/boydti/fawe/object/FaweLimit.java index ad1d59a1..4781cd98 100644 --- a/core/src/main/java/com/boydti/fawe/object/FaweLimit.java +++ b/core/src/main/java/com/boydti/fawe/object/FaweLimit.java @@ -76,6 +76,26 @@ public class FaweLimit { return MAX_ENTITIES-- > 0; } + public boolean isUnlimited() { + return MAX_CHANGES == Integer.MAX_VALUE && + MAX_FAILS == Integer.MAX_VALUE && + MAX_CHECKS == Integer.MAX_VALUE && + MAX_ITERATIONS == Integer.MAX_VALUE && + MAX_BLOCKSTATES == Integer.MAX_VALUE && + MAX_ENTITIES == Integer.MAX_VALUE && + MAX_HISTORY == Integer.MAX_VALUE; + } + + public void set(FaweLimit limit) { + MAX_ACTIONS = limit.MAX_ACTIONS; + MAX_CHANGES = limit.MAX_CHANGES; + MAX_BLOCKSTATES = limit.MAX_BLOCKSTATES; + MAX_CHECKS = limit.MAX_CHECKS; + MAX_ENTITIES = limit.MAX_ENTITIES; + MAX_FAILS = limit.MAX_FAILS; + MAX_ITERATIONS = limit.MAX_ITERATIONS; + MAX_HISTORY = limit.MAX_HISTORY; + } public FaweLimit copy() { FaweLimit limit = new FaweLimit(); diff --git a/core/src/main/java/com/boydti/fawe/object/FawePlayer.java b/core/src/main/java/com/boydti/fawe/object/FawePlayer.java index fa4f6b2e..ed4c2209 100644 --- a/core/src/main/java/com/boydti/fawe/object/FawePlayer.java +++ b/core/src/main/java/com/boydti/fawe/object/FawePlayer.java @@ -145,7 +145,7 @@ public abstract class FawePlayer { ConcurrentLinkedDeque adder = getMeta("fawe_action_v2"); if (adder == null) { adder = new ConcurrentLinkedDeque(); - ConcurrentLinkedDeque previous = (ConcurrentLinkedDeque) setMeta("fawe_action_v2", adder); + ConcurrentLinkedDeque previous = (ConcurrentLinkedDeque) getAndSetMeta("fawe_action_v2", adder); if (previous != null) { setMeta("fawe_action_v2", adder = previous); } @@ -397,11 +397,18 @@ public abstract class FawePlayer { * @param value * @return previous value */ - public Object setMeta(String key, Object value) { + public void setMeta(String key, Object value) { if (this.meta == null) { this.meta = new ConcurrentHashMap<>(8, 0.9f, 1); } - return this.meta.put(key, value); + this.meta.put(key, value); + } + + public T getAndSetMeta(String key, T value) { + if (this.meta == null) { + this.meta = new ConcurrentHashMap<>(8, 0.9f, 1); + } + return (T) this.meta.put(key, value); } /** diff --git a/core/src/main/java/com/boydti/fawe/object/HasFaweQueue.java b/core/src/main/java/com/boydti/fawe/object/HasFaweQueue.java new file mode 100644 index 00000000..8ad5b840 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/HasFaweQueue.java @@ -0,0 +1,5 @@ +package com.boydti.fawe.object; + +public interface HasFaweQueue { + FaweQueue getQueue(); +} diff --git a/core/src/main/java/com/boydti/fawe/object/brush/RecurseBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/RecurseBrush.java new file mode 100644 index 00000000..3df2784d --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/brush/RecurseBrush.java @@ -0,0 +1,56 @@ +package com.boydti.fawe.object.brush; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.command.tool.BrushTool; +import com.sk89q.worldedit.command.tool.brush.Brush; +import com.sk89q.worldedit.function.block.BlockReplace; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.function.visitor.RecursiveVisitor; + +public class RecurseBrush implements Brush { + + private final BrushTool tool; + + public RecurseBrush(BrushTool tool) { + this.tool = tool; + } + + @Override + public void build(final EditSession editSession, final Vector position, Pattern to, double size) throws MaxChangedBlocksException { + Mask mask = tool.getMask(); + if (mask == null) { + mask = Masks.alwaysTrue(); + } + final int radius = (int) size; + BaseBlock block = editSession.getBlock(position); + if (block.getId() == 0) { + return; + } + final BlockReplace replace = new BlockReplace(editSession, to); + editSession.setMask((Mask) null); + RecursiveVisitor visitor = new RecursiveVisitor(mask, replace) { + @Override + public boolean isVisitable(Vector from, Vector to) { + if (super.isVisitable(from, to)) { + int dx = Math.abs((int) (position.x - to.x)); + if (dx > radius) return false; + int dz = Math.abs((int) (position.z - to.z)); + if (dz > radius) return false; + int dy = Math.abs((int) (position.y - to.y)); + if (dy > radius) return false; + return true; + } else { + return false; + } + } + }; + visitor.visit(position); + Operations.completeBlindly(visitor); + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/change/MutableBlockChange.java b/core/src/main/java/com/boydti/fawe/object/change/MutableBlockChange.java index d23cc258..d058d766 100644 --- a/core/src/main/java/com/boydti/fawe/object/change/MutableBlockChange.java +++ b/core/src/main/java/com/boydti/fawe/object/change/MutableBlockChange.java @@ -1,8 +1,8 @@ package com.boydti.fawe.object.change; import com.boydti.fawe.Fawe; -import com.boydti.fawe.object.extent.FastWorldEditExtent; -import com.boydti.fawe.util.ExtentTraverser; +import com.boydti.fawe.object.FaweQueue; +import com.boydti.fawe.object.HasFaweQueue; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.history.UndoContext; @@ -35,14 +35,21 @@ public class MutableBlockChange implements Change { create(context); } + private FaweQueue queue; + private boolean checkedQueue; + public void create(UndoContext context) { - Extent extent = context.getExtent(); - ExtentTraverser find = new ExtentTraverser(extent).find(FastWorldEditExtent.class); - if (find != null) { - FastWorldEditExtent fwee = find.get(); - fwee.getQueue().setBlock(x, y, z, id, data); - } else { - Fawe.debug("FAWE doesn't support: " + extent + " for " + getClass() + " (bug Empire92)"); + if (queue != null) { + queue.setBlock(x, y, z, id, data); + } + if (!checkedQueue) { + checkedQueue = true; + Extent extent = context.getExtent(); + if (extent instanceof HasFaweQueue) { + (queue = ((HasFaweQueue) extent).getQueue()).setBlock(x, y, z, id, data); + } else { + Fawe.debug("FAWE doesn't support: " + extent + " for " + getClass() + " (bug Empire92)"); + } } } } diff --git a/core/src/main/java/com/boydti/fawe/object/change/MutableChunkChange.java b/core/src/main/java/com/boydti/fawe/object/change/MutableChunkChange.java index 77e638dd..65eee4a6 100644 --- a/core/src/main/java/com/boydti/fawe/object/change/MutableChunkChange.java +++ b/core/src/main/java/com/boydti/fawe/object/change/MutableChunkChange.java @@ -2,8 +2,8 @@ package com.boydti.fawe.object.change; import com.boydti.fawe.Fawe; import com.boydti.fawe.object.FaweChunk; -import com.boydti.fawe.object.extent.FastWorldEditExtent; -import com.boydti.fawe.util.ExtentTraverser; +import com.boydti.fawe.object.FaweQueue; +import com.boydti.fawe.object.HasFaweQueue; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.history.UndoContext; @@ -29,18 +29,29 @@ public class MutableChunkChange implements Change { create(context, false); } + private FaweQueue queue; + private boolean checkedQueue; + public void create(UndoContext context, boolean undo) { - Extent extent = context.getExtent(); - ExtentTraverser find = new ExtentTraverser(extent).find(FastWorldEditExtent.class); - if (find != null) { - FastWorldEditExtent fwee = find.get(); - if (undo) { - fwee.getQueue().setChunk(from); + if (queue != null) { + perform(queue, undo); + } + if (!checkedQueue) { + checkedQueue = true; + Extent extent = context.getExtent(); + if (extent instanceof HasFaweQueue) { + perform(queue = ((HasFaweQueue) extent).getQueue(), undo); } else { - fwee.getQueue().setChunk(to); + Fawe.debug("FAWE doesn't support: " + extent + " for " + getClass() + " (bug Empire92)"); } + } + } + + public void perform(FaweQueue queue, boolean undo) { + if (undo) { + queue.setChunk(from); } else { - Fawe.debug("FAWE doesn't support: " + context + " for " + getClass()); + queue.setChunk(to); } } } diff --git a/core/src/main/java/com/boydti/fawe/object/change/MutableEntityChange.java b/core/src/main/java/com/boydti/fawe/object/change/MutableEntityChange.java index bfd4ff95..aa9fb664 100644 --- a/core/src/main/java/com/boydti/fawe/object/change/MutableEntityChange.java +++ b/core/src/main/java/com/boydti/fawe/object/change/MutableEntityChange.java @@ -1,6 +1,8 @@ package com.boydti.fawe.object.change; import com.boydti.fawe.Fawe; +import com.boydti.fawe.object.FaweQueue; +import com.boydti.fawe.object.HasFaweQueue; import com.boydti.fawe.object.extent.FastWorldEditExtent; import com.boydti.fawe.util.ExtentTraverser; import com.sk89q.jnbt.CompoundTag; @@ -72,19 +74,30 @@ public class MutableEntityChange implements Change { } } + private FaweQueue queue; + private boolean checkedQueue; + public void create(UndoContext context) { - Extent extent = context.getExtent(); - ExtentTraverser find = new ExtentTraverser(extent).find(FastWorldEditExtent.class); - if (find != null) { - FastWorldEditExtent fwee = find.get(); - Map map = tag.getValue(); - List pos = (List) map.get("Pos").getValue(); - int x = (int) Math.round(pos.get(0).getValue()); - int y = (int) Math.round(pos.get(1).getValue()); - int z = (int) Math.round(pos.get(2).getValue()); - fwee.getQueue().setEntity(x, y, z, tag); - } else { - Fawe.debug("FAWE doesn't support: " + context + " for " + getClass() + " (bug Empire92)"); + if (queue != null) { + perform(queue); + } + if (!checkedQueue) { + checkedQueue = true; + Extent extent = context.getExtent(); + if (extent instanceof HasFaweQueue) { + perform(queue = ((HasFaweQueue) extent).getQueue()); + } else { + Fawe.debug("FAWE doesn't support: " + extent + " for " + getClass() + " (bug Empire92)"); + } } } + + public void perform(FaweQueue queue) { + Map map = tag.getValue(); + List pos = (List) map.get("Pos").getValue(); + int x = (int) Math.round(pos.get(0).getValue()); + int y = (int) Math.round(pos.get(1).getValue()); + int z = (int) Math.round(pos.get(2).getValue()); + queue.setEntity(x, y, z, tag); + } } diff --git a/core/src/main/java/com/boydti/fawe/object/change/MutableFullBlockChange.java b/core/src/main/java/com/boydti/fawe/object/change/MutableFullBlockChange.java index 2d4c5d87..5335cd6d 100644 --- a/core/src/main/java/com/boydti/fawe/object/change/MutableFullBlockChange.java +++ b/core/src/main/java/com/boydti/fawe/object/change/MutableFullBlockChange.java @@ -2,8 +2,8 @@ package com.boydti.fawe.object.change; import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; -import com.boydti.fawe.object.extent.FastWorldEditExtent; -import com.boydti.fawe.util.ExtentTraverser; +import com.boydti.fawe.object.FaweQueue; +import com.boydti.fawe.object.HasFaweQueue; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.history.UndoContext; @@ -36,14 +36,25 @@ public class MutableFullBlockChange implements Change { create(context); } + private FaweQueue queue; + private boolean checkedQueue; + public void create(UndoContext context) { - Extent extent = context.getExtent(); - ExtentTraverser find = new ExtentTraverser(extent).find(FastWorldEditExtent.class); - if (find != null) { - FastWorldEditExtent fwee = find.get(); - fwee.getQueue().setBlock(x, y, z, FaweCache.getId(from), FaweCache.getData(from)); - } else { - Fawe.debug("FAWE doesn't support: " + extent + " for " + getClass() + " (bug Empire92)"); + if (queue != null) { + perform(queue); + } + if (!checkedQueue) { + checkedQueue = true; + Extent extent = context.getExtent(); + if (extent instanceof HasFaweQueue) { + perform(queue = ((HasFaweQueue) extent).getQueue()); + } else { + Fawe.debug("FAWE doesn't support: " + extent + " for " + getClass() + " (bug Empire92)"); + } } } + + public void perform(FaweQueue queue) { + queue.setBlock(x, y, z, FaweCache.getId(from), FaweCache.getData(from)); + } } diff --git a/core/src/main/java/com/boydti/fawe/object/change/MutableTileChange.java b/core/src/main/java/com/boydti/fawe/object/change/MutableTileChange.java index 33b99dbb..73e9efa3 100644 --- a/core/src/main/java/com/boydti/fawe/object/change/MutableTileChange.java +++ b/core/src/main/java/com/boydti/fawe/object/change/MutableTileChange.java @@ -1,8 +1,8 @@ package com.boydti.fawe.object.change; import com.boydti.fawe.Fawe; -import com.boydti.fawe.object.extent.FastWorldEditExtent; -import com.boydti.fawe.util.ExtentTraverser; +import com.boydti.fawe.object.FaweQueue; +import com.boydti.fawe.object.HasFaweQueue; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.Tag; @@ -36,18 +36,29 @@ public class MutableTileChange implements Change { } } + private FaweQueue queue; + private boolean checkedQueue; + public void create(UndoContext context) { - Extent extent = context.getExtent(); - ExtentTraverser find = new ExtentTraverser(extent).find(FastWorldEditExtent.class); - if (find != null) { - FastWorldEditExtent fwee = find.get(); - Map map = tag.getValue(); - int x = ((IntTag) map.get("x")).getValue(); - int y = ((IntTag) map.get("y")).getValue(); - int z = ((IntTag) map.get("z")).getValue(); - fwee.getQueue().setTile(x, y, z, tag); - } else { - Fawe.debug("FAWE doesn't support: " + context + " for " + getClass()); + if (queue != null) { + perform(queue); + } + if (!checkedQueue) { + checkedQueue = true; + Extent extent = context.getExtent(); + if (extent instanceof HasFaweQueue) { + perform(queue = ((HasFaweQueue) extent).getQueue()); + } else { + Fawe.debug("FAWE doesn't support: " + extent + " for " + getClass() + " (bug Empire92)"); + } } } + + public void perform(FaweQueue queue) { + Map map = tag.getValue(); + int x = ((IntTag) map.get("x")).getValue(); + int y = ((IntTag) map.get("y")).getValue(); + int z = ((IntTag) map.get("z")).getValue(); + queue.setTile(x, y, z, tag); + } } diff --git a/core/src/main/java/com/boydti/fawe/object/changeset/DiskStorageHistory.java b/core/src/main/java/com/boydti/fawe/object/changeset/DiskStorageHistory.java index 84c17ec8..32124eff 100644 --- a/core/src/main/java/com/boydti/fawe/object/changeset/DiskStorageHistory.java +++ b/core/src/main/java/com/boydti/fawe/object/changeset/DiskStorageHistory.java @@ -199,26 +199,11 @@ public class DiskStorageHistory extends FaweStreamChangeSet { if (osBD != null) { return osBD; } - writeHeader(x, y, z); - return osBD; - } - - public void writeHeader(int x, int y, int z) throws IOException { bdFile.getParentFile().mkdirs(); bdFile.createNewFile(); osBD = getCompressedOS(new FileOutputStream(bdFile)); - // Mode - osBD.write((byte) MODE); - // Origin - setOrigin(x, z); - osBD.write((byte) (x >> 24)); - osBD.write((byte) (x >> 16)); - osBD.write((byte) (x >> 8)); - osBD.write((byte) (x)); - osBD.write((byte) (z >> 24)); - osBD.write((byte) (z >> 16)); - osBD.write((byte) (z >> 8)); - osBD.write((byte) (z)); + writeHeader(osBD, x, y, z); + return osBD; } @Override @@ -271,12 +256,7 @@ public class DiskStorageHistory extends FaweStreamChangeSet { return null; } InputStream is = MainUtil.getCompressedIS(new FileInputStream(bdFile)); - // skip mode - is.skip(1); - // origin - int x = ((is.read() << 24) + (is.read() << 16) + (is.read() << 8) + (is.read() << 0)); - int z = ((is.read() << 24) + (is.read() << 16) + (is.read() << 8) + (is.read() << 0)); - setOrigin(x, z); + readHeader(is); return is; } diff --git a/core/src/main/java/com/boydti/fawe/object/changeset/FaweStreamChangeSet.java b/core/src/main/java/com/boydti/fawe/object/changeset/FaweStreamChangeSet.java index c9f6c542..a4e7d475 100644 --- a/core/src/main/java/com/boydti/fawe/object/changeset/FaweStreamChangeSet.java +++ b/core/src/main/java/com/boydti/fawe/object/changeset/FaweStreamChangeSet.java @@ -8,11 +8,13 @@ import com.boydti.fawe.object.change.MutableEntityChange; import com.boydti.fawe.object.change.MutableFullBlockChange; import com.boydti.fawe.object.change.MutableTileChange; import com.boydti.fawe.util.MainUtil; +import com.boydti.fawe.util.MathMan; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.NBTOutputStream; import com.sk89q.worldedit.history.change.Change; import com.sk89q.worldedit.world.World; +import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -21,18 +23,197 @@ import java.util.Iterator; public abstract class FaweStreamChangeSet extends FaweChangeSet { - public static final int MODE = 3; public static final int HEADER_SIZE = 9; - + private int mode; private final int compression; + private FaweStreamIdDelegate idDel; + private FaweStreamPositionDelegate posDel; + public FaweStreamChangeSet(World world) { - this(world, Settings.HISTORY.COMPRESSION_LEVEL); + this(world, Settings.HISTORY.COMPRESSION_LEVEL, Settings.HISTORY.STORE_REDO, Settings.HISTORY.SMALL_EDITS); } - public FaweStreamChangeSet(World world, int compression) { + public FaweStreamChangeSet(World world, int compression, boolean storeRedo, boolean smallLoc) { super(world); this.compression = compression; + if (storeRedo) { + if (smallLoc) { + mode = 4; + } else { + mode = 3; + } + } else if (smallLoc) { + mode = 1; + } else { + mode = 2; + } + } + + public interface FaweStreamPositionDelegate { + void write(OutputStream out, int x, int y, int z) throws IOException; + int readX(InputStream in) throws IOException; + int readY(InputStream in) throws IOException; + int readZ(InputStream in) throws IOException; + } + + public interface FaweStreamIdDelegate { + void writeChange(OutputStream out, int from, int to) throws IOException; + void readCombined(InputStream in, MutableBlockChange change, boolean dir) throws IOException; + void readCombined(InputStream in, MutableFullBlockChange change, boolean dir) throws IOException; + } + + private void setupStreamDelegates(int mode) { + this.mode = mode; + if (mode == 3 || mode == 4) { + idDel = new FaweStreamIdDelegate() { + @Override + public void writeChange(OutputStream stream, int combinedFrom, int combinedTo) throws IOException { + stream.write((combinedFrom) & 0xff); + stream.write(((combinedFrom) >> 8) & 0xff); + stream.write((combinedTo) & 0xff); + stream.write(((combinedTo) >> 8) & 0xff); + } + + @Override + public void readCombined(InputStream is, MutableBlockChange change, boolean dir) throws IOException { + if (dir) { + is.skip(2); + int to1 = is.read(); + int to2 = is.read(); + change.id = (short) ((to2 << 4) + (to1 >> 4)); + change.data = (byte) (to1 & 0xf); + } else { + int from1 = is.read(); + int from2 = is.read(); + is.skip(2); + change.id = (short) ((from2 << 4) + (from1 >> 4)); + change.data = (byte) (from1 & 0xf); + } + } + + @Override + public void readCombined(InputStream is, MutableFullBlockChange change, boolean dir) throws IOException { + change.from = ((byte) is.read() & 0xFF) + ((byte) is.read() << 8); + change.to = ((byte) is.read() & 0xFF) + ((byte) is.read() << 8); + } + }; + } else { + idDel = new FaweStreamIdDelegate() { + @Override + public void writeChange(OutputStream stream, int combinedFrom, int to) throws IOException { + stream.write((combinedFrom) & 0xff); + stream.write(((combinedFrom) >> 8) & 0xff); + } + + @Override + public void readCombined(InputStream in, MutableBlockChange change, boolean dir) throws IOException { + int from1 = in.read(); + int from2 = in.read(); + change.id = (short) ((from2 << 4) + (from1 >> 4)); + change.data = (byte) (from1 & 0xf); + } + + @Override + public void readCombined(InputStream is, MutableFullBlockChange change, boolean dir) throws IOException { + change.from = ((byte) is.read() & 0xFF) + ((byte) is.read() << 8); + change.to = 0; + } + }; + } + if (mode == 1 || mode == 4) { // small + posDel = new FaweStreamPositionDelegate() { + @Override + public void write(OutputStream out, int x, int y, int z) throws IOException { + byte b1 = (byte) y; + byte b2 = (byte) (x); + byte b3 = (byte) (z); + int x16 = (x >> 8) & 0xF; + int z16 = (z >> 8) & 0xF; + byte b4 = MathMan.pair16(x16, z16); + out.write(b1); + out.write(b2); + out.write(b3); + out.write(b4); + } + + byte[] buffer = new byte[4]; + + @Override + public int readX(InputStream in) throws IOException { + if (in.read(buffer) == -1) { + throw new EOFException(); + } + return (((buffer[1] & 0xFF) + ((MathMan.unpair16x(buffer[3])) << 8)) << 20) >> 20; + } + + @Override + public int readY(InputStream in) { + return buffer[0] & 0xFF; + } + + @Override + public int readZ(InputStream in) throws IOException { + return (((buffer[2] & 0xFF) + ((MathMan.unpair16y(buffer[3])) << 8)) << 20) >> 20; + } + }; + } else { + posDel = new FaweStreamPositionDelegate() { + + byte[] buffer = new byte[5]; + + @Override + public void write(OutputStream stream, int x, int y, int z) throws IOException { + stream.write((x) & 0xff); + stream.write(((x) >> 8) & 0xff); + stream.write((z) & 0xff); + stream.write(((z) >> 8) & 0xff); + stream.write((byte) y); + } + + @Override + public int readX(InputStream is) throws IOException { + if (is.read(buffer) == -1) { + throw new EOFException(); + } + return (buffer[0] & 0xFF) + (buffer[1] << 8); + } + + @Override + public int readY(InputStream is) throws IOException { + return buffer[4] & 0xFF; + } + + @Override + public int readZ(InputStream is) throws IOException { + return (buffer[2] & 0xFF) + (buffer[3] << 8); + } + }; + } + } + + public void writeHeader(OutputStream os, int x, int y, int z) throws IOException { + os.write(mode); + setOrigin(x, z); + os.write((byte) (x >> 24)); + os.write((byte) (x >> 16)); + os.write((byte) (x >> 8)); + os.write((byte) (x)); + os.write((byte) (z >> 24)); + os.write((byte) (z >> 16)); + os.write((byte) (z >> 8)); + os.write((byte) (z)); + setupStreamDelegates(mode); + } + + public void readHeader(InputStream is) throws IOException { + // skip mode + int mode = is.read(); + // origin + int x = ((is.read() << 24) + (is.read() << 16) + (is.read() << 8) + (is.read() << 0)); + int z = ((is.read() << 24) + (is.read() << 16) + (is.read() << 8) + (is.read() << 0)); + setOrigin(x, z); + setupStreamDelegates(mode); } public FaweOutputStream getCompressedOS(OutputStream os) throws IOException { @@ -93,21 +274,8 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet { try { OutputStream stream = getBlockOS(x, y, z); //x - x-=originX; - stream.write((x) & 0xff); - stream.write(((x) >> 8) & 0xff); - //z - z-=originZ; - stream.write((z) & 0xff); - stream.write(((z) >> 8) & 0xff); - //y - stream.write((byte) y); - //from - stream.write((combinedFrom) & 0xff); - stream.write(((combinedFrom) >> 8) & 0xff); - //to - stream.write((combinedTo) & 0xff); - stream.write(((combinedTo) >> 8) & 0xff); + posDel.write(stream, x - originX, y, z - originZ); + idDel.writeChange(stream, combinedFrom, combinedTo); } catch (Throwable e) { MainUtil.handleError(e); @@ -172,43 +340,25 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet { private MutableBlockChange last = read(); public MutableBlockChange read() { try { - int read0 = is.read(); - if (read0 == -1) { - return null; - } - int x = ((byte) read0 & 0xFF) + ((byte) is.read() << 8) + originX; - int z = ((byte) is.read() & 0xFF) + ((byte) is.read() << 8) + originZ; - int y = is.read() & 0xff; - change.x = x; - change.y = y; - change.z = z; - if (dir) { - is.skip(2); - int to1 = is.read(); - int to2 = is.read(); - change.id = (short) ((to2 << 4) + (to1 >> 4)); - change.data = (byte) (to1 & 0xf); - } else { - int from1 = is.read(); - int from2 = is.read(); - is.skip(2); - change.id = (short) ((from2 << 4) + (from1 >> 4)); - change.data = (byte) (from1 & 0xf); - } + change.x = posDel.readX(is) + originX; + change.y = posDel.readY(is); + change.z = posDel.readZ(is) + originZ; + idDel.readCombined(is, change, dir); return change; - } catch (Exception ignoreEOF) { - MainUtil.handleError(ignoreEOF); + } catch (EOFException ignoreOEF) { + return null; + } catch (Exception e) { + MainUtil.handleError(e); } return null; } @Override public boolean hasNext() { - if (last == null) { - last = read(); - } if (last != null) { return true; + } else if ((last = read()) != null) { + return true; } try { is.close(); @@ -242,21 +392,15 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet { private MutableFullBlockChange last = read(); public MutableFullBlockChange read() { try { - int read0 = is.read(); - if (read0 == -1) { - return null; - } - int x = ((byte) read0 & 0xFF) + ((byte) is.read() << 8) + originX; - int z = ((byte) is.read() & 0xFF) + ((byte) is.read() << 8) + originZ; - int y = is.read() & 0xff; - change.x = x; - change.y = y; - change.z = z; - change.from = ((byte) is.read() & 0xFF) + ((byte) is.read() << 8); - change.to = ((byte) is.read() & 0xFF) + ((byte) is.read() << 8); + change.x = posDel.readX(is) + originX; + change.y = posDel.readY(is); + change.z = posDel.readZ(is) + originZ; + idDel.readCombined(is, change, dir); return change; - } catch (Exception ignoreEOF) { - MainUtil.handleError(ignoreEOF); + } catch (EOFException ignoreOEF) { + return null; + } catch (Exception e) { + MainUtil.handleError(e); } return null; } diff --git a/core/src/main/java/com/boydti/fawe/object/changeset/MemoryOptimizedHistory.java b/core/src/main/java/com/boydti/fawe/object/changeset/MemoryOptimizedHistory.java index 1037d8bb..db5c2500 100644 --- a/core/src/main/java/com/boydti/fawe/object/changeset/MemoryOptimizedHistory.java +++ b/core/src/main/java/com/boydti/fawe/object/changeset/MemoryOptimizedHistory.java @@ -113,9 +113,7 @@ public class MemoryOptimizedHistory extends FaweStreamChangeSet { setOrigin(x, z); idsStream = new FastByteArrayOutputStream(Settings.HISTORY.BUFFER_SIZE); idsStreamZip = getCompressedOS(idsStream); - idsStreamZip.write(FaweStreamChangeSet.MODE); - idsStreamZip.writeInt(x); - idsStreamZip.writeInt(z); + writeHeader(idsStreamZip, x, y, z); return idsStreamZip; } @@ -125,7 +123,7 @@ public class MemoryOptimizedHistory extends FaweStreamChangeSet { return null; } FaweInputStream result = MainUtil.getCompressedIS(new FastByteArraysInputStream(ids)); - result.skip(FaweStreamChangeSet.HEADER_SIZE); + readHeader(result); return result; } diff --git a/core/src/main/java/com/boydti/fawe/object/extent/FastWorldEditExtent.java b/core/src/main/java/com/boydti/fawe/object/extent/FastWorldEditExtent.java index 373a8a8f..ec0d65f3 100644 --- a/core/src/main/java/com/boydti/fawe/object/extent/FastWorldEditExtent.java +++ b/core/src/main/java/com/boydti/fawe/object/extent/FastWorldEditExtent.java @@ -2,6 +2,7 @@ package com.boydti.fawe.object.extent; import com.boydti.fawe.FaweCache; import com.boydti.fawe.object.FaweQueue; +import com.boydti.fawe.object.HasFaweQueue; import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.ReflectionUtils; import com.sk89q.jnbt.CompoundTag; @@ -24,9 +25,9 @@ import com.sk89q.worldedit.world.biome.BaseBiome; import java.util.List; import java.util.Map; -public class FastWorldEditExtent extends AbstractDelegateExtent { +public class FastWorldEditExtent extends AbstractDelegateExtent implements HasFaweQueue { - private final FaweQueue queue; + private FaweQueue queue; private final int maxY; public FastWorldEditExtent(final World world, FaweQueue queue) { diff --git a/core/src/main/java/com/boydti/fawe/object/extent/MCAExtent.java b/core/src/main/java/com/boydti/fawe/object/extent/MCAExtent.java index fd1b5e6a..fcc3094f 100644 --- a/core/src/main/java/com/boydti/fawe/object/extent/MCAExtent.java +++ b/core/src/main/java/com/boydti/fawe/object/extent/MCAExtent.java @@ -2,6 +2,7 @@ package com.boydti.fawe.object.extent; import com.boydti.fawe.jnbt.anvil.MCAFile; import com.boydti.fawe.object.FaweQueue; +import com.boydti.fawe.object.HasFaweQueue; import com.boydti.fawe.util.MathMan; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; @@ -21,7 +22,7 @@ import java.util.List; import java.util.Map; import javax.annotation.Nullable; -public class MCAExtent extends AbstractDelegateExtent { +public class MCAExtent extends AbstractDelegateExtent implements HasFaweQueue { private final FaweQueue queue; private final File folder; diff --git a/core/src/main/java/com/boydti/fawe/object/extent/ProcessedWEExtent.java b/core/src/main/java/com/boydti/fawe/object/extent/ProcessedWEExtent.java index 90fafdfe..13dd5fb8 100644 --- a/core/src/main/java/com/boydti/fawe/object/extent/ProcessedWEExtent.java +++ b/core/src/main/java/com/boydti/fawe/object/extent/ProcessedWEExtent.java @@ -4,6 +4,7 @@ import com.boydti.fawe.FaweCache; import com.boydti.fawe.config.BBC; import com.boydti.fawe.object.FaweLimit; import com.boydti.fawe.object.RegionWrapper; +import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.WEManager; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; @@ -38,7 +39,7 @@ public class ProcessedWEExtent extends FaweRegionExtent { } if (WEManager.IMP.maskContains(this.mask, location.getBlockX(), location.getBlockZ())) { if (!limit.MAX_ENTITIES()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES); + WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_ENTITIES); return null; } return super.createEntity(location, entity); @@ -63,11 +64,14 @@ public class ProcessedWEExtent extends FaweRegionExtent { return super.getEntities(region); } + int count = 0; + @Override public BaseBlock getLazyBlock(int x, int y, int z) { + count++; if (WEManager.IMP.maskContains(this.mask, x, z)) { if (!limit.MAX_CHECKS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES); + WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); return EditSession.nullBlock; } else { return extent.getLazyBlock(x, y, z); diff --git a/core/src/main/java/com/boydti/fawe/object/function/mask/AbstractDelegateMask.java b/core/src/main/java/com/boydti/fawe/object/function/mask/AbstractDelegateMask.java index fdd92282..7c541e1b 100644 --- a/core/src/main/java/com/boydti/fawe/object/function/mask/AbstractDelegateMask.java +++ b/core/src/main/java/com/boydti/fawe/object/function/mask/AbstractDelegateMask.java @@ -7,20 +7,20 @@ import javax.annotation.Nullable; public class AbstractDelegateMask implements Mask { - private final Mask parent; + private final Mask mask; public AbstractDelegateMask(Mask parent) { - this.parent = parent; + this.mask = parent; } @Override public boolean test(Vector vector) { - return parent.test(vector); + return mask.test(vector); } @Nullable @Override public Mask2D toMask2D() { - return parent.toMask2D(); + return mask.toMask2D(); } } diff --git a/core/src/main/java/com/boydti/fawe/object/mask/AngleMask.java b/core/src/main/java/com/boydti/fawe/object/mask/AngleMask.java new file mode 100644 index 00000000..13f5868d --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/mask/AngleMask.java @@ -0,0 +1,186 @@ +package com.boydti.fawe.object.mask; + +import com.boydti.fawe.Fawe; +import com.boydti.fawe.util.MathMan; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockType; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.Mask2D; +import java.util.HashMap; +import javax.annotation.Nullable; + +public class AngleMask implements Mask, ResettableMask { + private final Extent extent; + private final int max; + private final int min; + private int maxY; + + public AngleMask(Extent extent, int min, int max) { + this.extent = extent; + this.maxY = extent.getMaximumPoint().getBlockY(); + this.min = min; + this.max = max; + } + + private HashMap angles = new HashMap<>(); + private long tick = 0; + + @Override + public boolean test(Vector vector) { + long currentTick = Fawe.get().getTimer().getTick(); + if (tick != (tick = currentTick)) { + angles.clear(); + tick = currentTick; + } + long pair = MathMan.pairInt(vector.getBlockX(), vector.getBlockZ()); + if (!angles.isEmpty()) { + Boolean value = angles.get(pair); + if (value != null) { + return value; + } + } + boolean result = getAngle(vector); + angles.put(pair, result); + return result; + } + + @Override + public void reset() { + this.angles.clear(); + } + + public boolean getAngle(Vector vector) { + int x = vector.getBlockX(); + int z = vector.getBlockZ(); + boolean n = false; + int o = getHighestTerrainBlock(x, z, 0, maxY, n); + if (getHighestTerrainBlock(x - 1, z, o - min, o - max, n) != -1) { + return true; + } + if (getHighestTerrainBlock(x + 1, z, o - min, o - max, n) != -1) { + return true; + } + if (getHighestTerrainBlock(x, z - 1, o - min, o - max, n) != -1) { + return true; + } + if (getHighestTerrainBlock(x, z + 1, o - min, o - max, n) != -1) { + return true; + } + return false; + } + + private Vector mutable = new Vector(); + + private int getHighestTerrainBlock(final int x, final int z, int minY, int maxY, final boolean naturalOnly) { + maxY = Math.min(this.maxY, Math.max(0, maxY)); + minY = Math.max(0, minY); + mutable.x = x; + mutable.z = z; + for (int y = maxY; y >= minY; --y) { + mutable.y = y; + BaseBlock block = extent.getLazyBlock(mutable); + final int id = block.getId(); + int data; + switch (id) { + case 0: { + continue; + } + case 2: + case 4: + case 13: + case 14: + case 15: + case 20: + case 21: + case 22: + case 25: + case 30: + case 32: + case 37: + case 39: + case 40: + case 41: + case 42: + case 45: + case 46: + case 47: + case 48: + case 49: + case 51: + case 52: + case 54: + case 55: + case 56: + case 57: + case 58: + case 60: + case 61: + case 62: + case 7: + case 8: + case 9: + case 10: + case 11: + case 73: + case 74: + case 78: + case 79: + case 80: + case 81: + case 82: + case 83: + case 84: + case 85: + case 87: + case 88: + case 101: + case 102: + case 103: + case 110: + case 112: + case 113: + case 117: + case 121: + case 122: + case 123: + case 124: + case 129: + case 133: + case 138: + case 137: + case 140: + case 165: + case 166: + case 169: + case 170: + case 172: + case 173: + case 174: + case 176: + case 177: + case 181: + case 182: + case 188: + case 189: + case 190: + case 191: + case 192: + return y; + default: + data = 0; + } + if (naturalOnly ? BlockType.isNaturalTerrainBlock(id, data) : !BlockType.canPassThrough(id, data)) { + return y; + } + } + return -1; + } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/mask/DataMask.java b/core/src/main/java/com/boydti/fawe/object/mask/DataMask.java new file mode 100644 index 00000000..ea1a1e9d --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/mask/DataMask.java @@ -0,0 +1,39 @@ +package com.boydti.fawe.object.mask; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.Mask2D; +import javax.annotation.Nullable; + +public class DataMask implements Mask, ResettableMask { + + private final Extent extent; + + public DataMask(Extent extent) { + this.extent = extent; + } + + int data = -1; + + @Override + public boolean test(Vector vector) { + if (data != -1) { + return extent.getLazyBlock(vector).getData() == data; + } else { + data = extent.getLazyBlock(vector).getData(); + return true; + } + } + + @Override + public void reset() { + this.data = -1; + } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/mask/IdDataMask.java b/core/src/main/java/com/boydti/fawe/object/mask/IdDataMask.java new file mode 100644 index 00000000..34ea5f73 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/mask/IdDataMask.java @@ -0,0 +1,40 @@ +package com.boydti.fawe.object.mask; + +import com.boydti.fawe.FaweCache; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.Mask2D; +import javax.annotation.Nullable; + +public class IdDataMask implements Mask, ResettableMask { + + private final Extent extent; + + public IdDataMask(Extent extent) { + this.extent = extent; + } + + int combined = -1; + + @Override + public boolean test(Vector vector) { + if (combined != -1) { + return FaweCache.getCombined(extent.getLazyBlock(vector)) == combined; + } else { + combined = FaweCache.getCombined(extent.getLazyBlock(vector)); + return true; + } + } + + @Override + public void reset() { + this.combined = -1; + } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/mask/IdMask.java b/core/src/main/java/com/boydti/fawe/object/mask/IdMask.java new file mode 100644 index 00000000..ba9df5d4 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/mask/IdMask.java @@ -0,0 +1,39 @@ +package com.boydti.fawe.object.mask; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.Mask2D; +import javax.annotation.Nullable; + +public class IdMask implements Mask, ResettableMask { + + private Extent extent; + + public IdMask(Extent extent) { + this.extent = extent; + } + + int id = -1; + + @Override + public boolean test(Vector vector) { + if (id != -1) { + return extent.getLazyBlock(vector).getId() == id; + } else { + id = extent.getLazyBlock(vector).getId(); + return true; + } + } + + @Override + public void reset() { + this.id = -1; + } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/mask/ResettableMask.java b/core/src/main/java/com/boydti/fawe/object/mask/ResettableMask.java new file mode 100644 index 00000000..67d9a00a --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/mask/ResettableMask.java @@ -0,0 +1,5 @@ +package com.boydti.fawe.object.mask; + +public interface ResettableMask { + void reset(); +} diff --git a/core/src/main/java/com/boydti/fawe/object/mask/XAxisMask.java b/core/src/main/java/com/boydti/fawe/object/mask/XAxisMask.java new file mode 100644 index 00000000..2fd4f082 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/mask/XAxisMask.java @@ -0,0 +1,33 @@ +package com.boydti.fawe.object.mask; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.Mask2D; +import javax.annotation.Nullable; + +/** + * Restricts the + */ +public class XAxisMask implements Mask, ResettableMask { + + private int layer = -1; + + @Override + public boolean test(Vector vector) { + if (layer == -1) { + layer = vector.getBlockX(); + } + return vector.getBlockX() == layer; + } + + @Override + public void reset() { + this.layer = -1; + } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/mask/YAxisMask.java b/core/src/main/java/com/boydti/fawe/object/mask/YAxisMask.java new file mode 100644 index 00000000..3724606b --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/mask/YAxisMask.java @@ -0,0 +1,33 @@ +package com.boydti.fawe.object.mask; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.Mask2D; +import javax.annotation.Nullable; + +/** + * Restricts the + */ +public class YAxisMask implements Mask, ResettableMask { + + private int layer = -1; + + @Override + public boolean test(Vector vector) { + if (layer == -1) { + layer = vector.getBlockY(); + } + return vector.getBlockY() == layer; + } + + @Override + public void reset() { + this.layer = -1; + } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/mask/ZAxisMask.java b/core/src/main/java/com/boydti/fawe/object/mask/ZAxisMask.java new file mode 100644 index 00000000..15d5a2ef --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/mask/ZAxisMask.java @@ -0,0 +1,33 @@ +package com.boydti.fawe.object.mask; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.Mask2D; +import javax.annotation.Nullable; + +/** + * Restricts the + */ +public class ZAxisMask implements Mask, ResettableMask { + + private int layer = -1; + + @Override + public boolean test(Vector vector) { + if (layer == -1) { + layer = vector.getBlockZ(); + } + return vector.getBlockZ() == layer; + } + + @Override + public void reset() { + this.layer = -1; + } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/schematic/FaweFormat.java b/core/src/main/java/com/boydti/fawe/object/schematic/FaweFormat.java index bf805ffd..4798c80f 100644 --- a/core/src/main/java/com/boydti/fawe/object/schematic/FaweFormat.java +++ b/core/src/main/java/com/boydti/fawe/object/schematic/FaweFormat.java @@ -84,115 +84,121 @@ public class FaweFormat implements ClipboardReader, ClipboardWriter { BlockArrayClipboard clipboard; int ox, oy, oz; oy = 0; - boolean from = false; - boolean small = true; - switch (mode) { - default: - return null; + boolean small = false; + boolean knownSize = false; + switch(mode) { + case 0: + knownSize = true; + break; + case 1: + small = true; + break; + case 2: + break; case 3: from = true; - case 2: - small = false; - case 1: { // Unknown size - ox = in.readInt(); - oz = in.readInt(); - FaweOutputStream tmp = new FaweOutputStream(new FastByteArrayOutputStream(Settings.HISTORY.BUFFER_SIZE)); - int width = 0; - int height = 0; - int length = 0; - while (true) { + break; + case 4: + small = true; + from = true; + break; + } + if (knownSize) { + int width = in.readUnsignedShort(); + int height = in.readUnsignedShort(); + int length = in.readUnsignedShort(); + ox = in.readShort(); + oy = in.readShort(); + oz = in.readShort(); + + Vector origin = new Vector(0, 0, 0); + CuboidRegion region = new CuboidRegion(origin, origin.add(width, height, length).subtract(Vector.ONE)); + clipboard = new BlockArrayClipboard(region, clipboardId); + try { + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + for (int z = 0; z < length; z++) { + int combined = in.readUnsignedShort(); + int id = FaweCache.getId(combined); + int data = FaweCache.getData(combined); + BaseBlock block = FaweCache.getBlock(id, data); + clipboard.setBlock(x, y, z, block); + } + } + } + } catch (WorldEditException e) { + e.printStackTrace(); + return null; + } + } else { + ox = in.readInt(); + oz = in.readInt(); + FaweOutputStream tmp = new FaweOutputStream(new FastByteArrayOutputStream(Settings.HISTORY.BUFFER_SIZE)); + int width = 0; + int height = 0; + int length = 0; + while (true) { + int x, y, z; + if (small) { + tmp.write(x = in.read()); + tmp.write(y = in.read()); + tmp.write(z = in.read()); + } else { + tmp.writeShort((short) (x = in.readUnsignedShort())); + tmp.write(y = in.read()); + tmp.writeShort((short) (z = in.readUnsignedShort())); + } + if (from) { + in.skip(2); + } + short combined; + tmp.writeShort(combined = in.readShort()); + if (combined == 0 || y == -1) { + break; + } + if (x > width) { + width = x; + } + if (y > height) { + height = y; + } + if(z > length) { + length = z; + } + } + Vector origin = new Vector(0, 0, 0); + CuboidRegion region = new CuboidRegion(origin, origin.add(width, height, length)); + clipboard = new BlockArrayClipboard(region, clipboardId); + width++; + height++; + length++; + byte[] array = ((ByteArrayOutputStream) tmp.getParent()).toByteArray(); + FaweInputStream part = new FaweInputStream(new FastByteArrayInputStream(array)); + try { + for (int i = 0; i< array.length; i+= 9) { int x, y, z; if (small) { - tmp.write(x = in.read()); - tmp.write(y = in.read()); - tmp.write(z = in.read()); + x = in.read(); + y = in.read(); + z = in.read(); } else { - tmp.writeShort((short) (x = in.readUnsignedShort())); - tmp.write(y = in.read()); - tmp.writeShort((short) (z = in.readUnsignedShort())); + x = in.readUnsignedShort(); + y = in.read(); + z = in.readUnsignedShort(); } if (from) { in.skip(2); } - short combined; - tmp.writeShort(combined = in.readShort()); - if (combined == 0 || y == -1) { - break; - } - if (x > width) { - width = x; - } - if (y > height) { - height = y; - } - if(z > length) { - length = z; - } + int combined = in.readShort(); + int id = FaweCache.getId(combined); + int data = FaweCache.getData(combined); + BaseBlock block = FaweCache.getBlock(id, data); + clipboard.setBlock(x, y, z, block); } - Vector origin = new Vector(0, 0, 0); - CuboidRegion region = new CuboidRegion(origin, origin.add(width, height, length)); - clipboard = new BlockArrayClipboard(region, clipboardId); - width++; - height++; - length++; - byte[] array = ((ByteArrayOutputStream) tmp.getParent()).toByteArray(); - FaweInputStream part = new FaweInputStream(new FastByteArrayInputStream(array)); - try { - for (int i = 0; i< array.length; i+= 9) { - int x, y, z; - if (small) { - x = in.read(); - y = in.read(); - z = in.read(); - } else { - x = in.readUnsignedShort(); - y = in.read(); - z = in.readUnsignedShort(); - } - if (from) { - in.skip(2); - } - int combined = in.readShort(); - int id = FaweCache.getId(combined); - int data = FaweCache.getData(combined); - BaseBlock block = FaweCache.getBlock(id, data); - clipboard.setBlock(x, y, z, block); - } - } catch (WorldEditException e) { - e.printStackTrace(); - return null; - } - break; - } - case 0: { - int width = in.readUnsignedShort(); - int height = in.readUnsignedShort(); - int length = in.readUnsignedShort(); - ox = in.readShort(); - oy = in.readShort(); - oz = in.readShort(); - - Vector origin = new Vector(0, 0, 0); - CuboidRegion region = new CuboidRegion(origin, origin.add(width, height, length).subtract(Vector.ONE)); - clipboard = new BlockArrayClipboard(region, clipboardId); - try { - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - for (int z = 0; z < length; z++) { - int combined = in.readUnsignedShort(); - int id = FaweCache.getId(combined); - int data = FaweCache.getData(combined); - BaseBlock block = FaweCache.getBlock(id, data); - clipboard.setBlock(x, y, z, block); - } - } - } - } catch (WorldEditException e) { - e.printStackTrace(); - return null; - } - break; + } catch (WorldEditException e) { + e.printStackTrace(); + return null; } } try { diff --git a/core/src/main/java/com/boydti/fawe/util/MaskTraverser.java b/core/src/main/java/com/boydti/fawe/util/MaskTraverser.java new file mode 100644 index 00000000..71485d64 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/util/MaskTraverser.java @@ -0,0 +1,48 @@ +package com.boydti.fawe.util; + +import com.boydti.fawe.object.mask.ResettableMask; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.Mask; +import java.lang.reflect.Field; +import java.util.Collection; + +public class MaskTraverser { + private final Mask mask; + + public MaskTraverser(Mask start) { + this.mask = start; + } + + public void reset(Extent newExtent) { + reset(mask, newExtent); + } + + private void reset(Mask mask, Extent newExtent) { + if (mask instanceof ResettableMask) { + ((ResettableMask) mask).reset(); + } + Class current = mask.getClass(); + while(current.getSuperclass() != null) { + try { + Field field = current.getDeclaredField("extent"); + field.setAccessible(true); + field.set(mask, newExtent); + } catch (NoSuchFieldException | IllegalAccessException ignore) {} + try { + Field field = current.getDeclaredField("mask"); + field.setAccessible(true); + Mask next = (Mask) field.get(mask); + reset(next, newExtent); + } catch (NoSuchFieldException | IllegalAccessException ignore) {} + try { + Field field = current.getDeclaredField("masks"); + field.setAccessible(true); + Collection masks = (Collection) field.get(mask); + for (Mask next : masks) { + reset(next, newExtent); + } + } catch (NoSuchFieldException | IllegalAccessException ignore) {} + current = current.getSuperclass(); + } + } +} diff --git a/core/src/main/java/com/sk89q/worldedit/EditSession.java b/core/src/main/java/com/sk89q/worldedit/EditSession.java index 99fd1fae..eb62e964 100644 --- a/core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -31,6 +31,7 @@ import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory; import com.boydti.fawe.object.FaweLimit; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FaweQueue; +import com.boydti.fawe.object.HasFaweQueue; import com.boydti.fawe.object.HistoryExtent; import com.boydti.fawe.object.NullChangeSet; import com.boydti.fawe.object.RegionWrapper; @@ -44,7 +45,9 @@ import com.boydti.fawe.object.extent.FastWorldEditExtent; import com.boydti.fawe.object.extent.FaweRegionExtent; import com.boydti.fawe.object.extent.NullExtent; import com.boydti.fawe.object.extent.ProcessedWEExtent; +import com.boydti.fawe.object.mask.ResettableMask; import com.boydti.fawe.util.ExtentTraverser; +import com.boydti.fawe.util.MaskTraverser; import com.boydti.fawe.util.MemUtil; import com.boydti.fawe.util.Perm; import com.boydti.fawe.util.SetQueue; @@ -149,7 +152,7 @@ import static com.sk89q.worldedit.regions.Regions.minimumBlockY; * {@link Extent}s that are chained together. For example, history is logged * using the {@link ChangeSetExtent}.

*/ -public class EditSession extends AbstractWorld { +public class EditSession extends AbstractWorld implements HasFaweQueue { /** * Used by {@link #setBlock(Vector, BaseBlock, Stage)} to * determine which {@link Extent}s should be bypassed. @@ -232,9 +235,6 @@ public class EditSession extends AbstractWorld { if (allowedRegions == null) { if (player != null && !player.hasWorldEditBypass()) { allowedRegions = player.getCurrentRegions(); - if (allowedRegions.length == 1 && allowedRegions[0].isGlobal()) { - allowedRegions = null; - } } } if (autoQueue == null) { @@ -292,7 +292,7 @@ public class EditSession extends AbstractWorld { if (allowedRegions.length == 0) { this.extent = new NullExtent(this.extent, BBC.WORLDEDIT_CANCEL_REASON_NO_REGION); } else { - this.extent = new ProcessedWEExtent(this.extent, allowedRegions, limit); + this.extent = new ProcessedWEExtent(this.extent, allowedRegions, this.limit); } } this.extent = wrapExtent(this.extent, bus, event, Stage.BEFORE_HISTORY); @@ -577,9 +577,15 @@ public class EditSession extends AbstractWorld { public void setMask(Mask mask) { if (mask == null) { mask = Masks.alwaysTrue(); + } else { + new MaskTraverser(mask).reset(this); } ExtentTraverser maskingExtent = new ExtentTraverser(this.extent).find(MaskingExtent.class); - if (maskingExtent != null) { + if (maskingExtent != null && maskingExtent.get() != null) { + Mask oldMask = maskingExtent.get().getMask(); + if (oldMask instanceof ResettableMask) { + ((ResettableMask) oldMask).reset(); + } maskingExtent.get().setMask(mask); } else if (mask != Masks.alwaysTrue()) { this.extent = new MaskingExtent(this.extent, mask); @@ -1159,6 +1165,8 @@ public class EditSession extends AbstractWorld { BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS.send(player); } } + // Reset limit + limit.set(originalLimit); // Enqueue it if (queue == null || queue.size() == 0) { queue.dequeue(); diff --git a/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java b/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java index 1020fd74..9782bd4f 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -31,6 +31,8 @@ import com.boydti.fawe.object.brush.BlendBall; import com.boydti.fawe.object.brush.DoubleActionBrushTool; import com.boydti.fawe.object.brush.ErodeBrush; import com.boydti.fawe.object.brush.LineBrush; +import com.boydti.fawe.object.brush.RecurseBrush; +import com.boydti.fawe.object.mask.IdMask; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandPermissions; @@ -117,6 +119,25 @@ public class BrushCommands { BBC.BRUSH_SPHERE.send(player, radius); } + @Command( + aliases = { "recursive", "recurse", "r" }, + usage = " [radius]", + desc = "Choose the recursive brush", + help = "Chooses the recursive brush", + min = 0, + max = 2 + ) + @CommandPermissions("worldedit.brush.recursive") + public void recursiveBrush(Player player, LocalSession session, EditSession editSession, Pattern fill, @Optional("2") double radius) throws WorldEditException { + worldEdit.checkMaxBrushRadius(radius); + BrushTool tool = session.getBrushTool(player.getItemInHand()); + tool.setSize(radius); + tool.setBrush(new RecurseBrush(tool), "worldedit.brush.recursive"); + tool.setMask(new IdMask(editSession)); + tool.setFill(fill); + BBC.BRUSH_SPHERE.send(player, radius); + } + @Command( aliases = { "line", "l" }, usage = " [radius]", @@ -152,8 +173,7 @@ public class BrushCommands { max = 2 ) @CommandPermissions("worldedit.brush.sphere") - public void sphereBrush(Player player, LocalSession session, EditSession editSession, Pattern fill, - @Optional("2") double radius, @Switch('h') boolean hollow) throws WorldEditException { + public void sphereBrush(Player player, LocalSession session, EditSession editSession, Pattern fill, @Optional("2") double radius, @Switch('h') boolean hollow) throws WorldEditException { worldEdit.checkMaxBrushRadius(radius); BrushTool tool = session.getBrushTool(player.getItemInHand()); diff --git a/core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java b/core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java index 79fd5a4f..5159717c 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java @@ -26,9 +26,11 @@ import com.boydti.fawe.config.Settings; import com.boydti.fawe.database.DBHandler; import com.boydti.fawe.database.RollbackDatabase; import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory; +import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.RegionWrapper; import com.boydti.fawe.object.RunnableVal; import com.boydti.fawe.object.changeset.DiskStorageHistory; +import com.boydti.fawe.util.EditSessionBuilder; import com.boydti.fawe.util.MainUtil; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandContext; @@ -72,7 +74,7 @@ public class HistoryCommands { min = 3, max = 3 ) - @CommandPermissions("worldedit.history.undo") + @CommandPermissions("worldedit.history.rollback") public void faweRollback(final Player player, LocalSession session, final String user, int radius, String time) throws WorldEditException { if (!Settings.HISTORY.USE_DATABASE) { BBC.SETTING_DISABLE.send(player, "history.use-database"); @@ -136,7 +138,7 @@ public class HistoryCommands { return; } radius = Math.max(Math.min(500, radius), 0); - World world = player.getWorld(); + final World world = player.getWorld(); WorldVector origin = player.getPosition(); Vector bot = origin.subtract(radius, radius, radius); bot = bot.setY(Math.max(0, bot.getY())); @@ -144,10 +146,20 @@ public class HistoryCommands { top = top.setY(Math.min(255, top.getY())); RollbackDatabase database = DBHandler.IMP.getDatabase(world); final AtomicInteger count = new AtomicInteger(); + final FawePlayer fp = FawePlayer.wrap(player); database.getPotentialEdits(other, System.currentTimeMillis() - timeDiff, bot, top, new RunnableVal() { @Override public void run(DiskStorageHistory edit) { - EditSession session = edit.toEditSession(null); + EditSession session = new EditSessionBuilder(world) + .player(fp) + .autoQueue(false) + .fastmode(false) + .checkMemory(false) + .changeSet(edit) + .limitUnlimited() + .queue(fp.getMaskedFaweQueue(false)) + .build(); + session.setSize(1); session.undo(session); edit.deleteFiles(); BBC.ROLLBACK_ELEMENT.send(player, Fawe.imp().getWorldName(edit.getWorld()) + "/" + user + "-" + edit.getIndex()); diff --git a/core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java b/core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java index 9b1ec053..d9f1507c 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java @@ -152,7 +152,6 @@ public class ToolCommands { ) @CommandPermissions("worldedit.tool.flood-fill") public void floodFill(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { - LocalConfiguration config = we.getConfiguration(); int range = args.getInteger(1); diff --git a/core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java b/core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java new file mode 100644 index 00000000..ddcd488d --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java @@ -0,0 +1,130 @@ +package com.sk89q.worldedit.command; + +import com.boydti.fawe.config.BBC; +import com.sk89q.minecraft.util.commands.Command; +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandPermissions; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.util.command.parametric.Optional; + +/** + * Tool commands. + */ +public class ToolUtilCommands { + private final WorldEdit we; + + public ToolUtilCommands(WorldEdit we) { + this.we = we; + } + + @Command( + aliases = { "/", "," }, + usage = "[on|off]", + desc = "Toggle the super pickaxe function", + min = 0, + max = 1 + ) + @CommandPermissions("worldedit.superpickaxe") + public void togglePickaxe(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { + String newState = args.getString(0, null); + if (session.hasSuperPickAxe()) { + if ("on".equals(newState)) { + player.printError("Super pick axe already enabled."); + BBC.SUPERPICKAXE_ENABLED.send(player); + return; + } + + session.disableSuperPickAxe(); + player.print("Super pick axe disabled."); + } else { + if ("off".equals(newState)) { + player.printError("Super pick axe already disabled."); + BBC.SUPERPICKAXE_DISABLED.send(player); + return; + } + session.enableSuperPickAxe(); + player.print("Super pick axe enabled."); + BBC.SUPERPICKAXE_ENABLED.send(player); + } + + } + + @Command( + aliases = { "mask" }, + usage = "[mask]", + desc = "Set the brush mask", + min = 0, + max = -1 + ) + @CommandPermissions("worldedit.brush.options.mask") + public void mask(Player player, LocalSession session, EditSession editSession, @Optional CommandContext context) throws WorldEditException { + if (context == null || context.argsLength() == 0) { + session.getBrushTool(player.getItemInHand()).setMask(null); + BBC.BRUSH_MASK_DISABLED.send(player); + } else { + ParserContext parserContext = new ParserContext(); + parserContext.setActor(player); + parserContext.setWorld(player.getWorld()); + parserContext.setSession(session); + parserContext.setExtent(editSession); + Mask mask = we.getMaskFactory().parseFromInput(context.getJoinedStrings(0), parserContext); + session.getBrushTool(player.getItemInHand()).setMask(mask); + BBC.BRUSH_MASK.send(player); + } + } + + @Command( + aliases = { "mat", "material" }, + usage = "[pattern]", + desc = "Set the brush material", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.brush.options.material") + public void material(Player player, LocalSession session, EditSession editSession, Pattern pattern) throws WorldEditException { + session.getBrushTool(player.getItemInHand()).setFill(pattern); + BBC.BRUSH_MATERIAL.send(player); + } + + @Command( + aliases = { "range" }, + usage = "[pattern]", + desc = "Set the brush range", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.brush.options.range") + public void range(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { + int range = args.getInteger(0); + session.getBrushTool(player.getItemInHand()).setRange(range); + BBC.BRUSH_RANGE.send(player); + } + + @Command( + aliases = { "size" }, + usage = "[pattern]", + desc = "Set the brush size", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.brush.options.size") + public void size(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { + + int radius = args.getInteger(0); + we.checkMaxBrushRadius(radius); + + session.getBrushTool(player.getItemInHand()).setSize(radius); + BBC.BRUSH_SIZE.send(player); + } + + public static Class inject() { + return ToolUtilCommands.class; + } +} \ No newline at end of file diff --git a/core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultMaskParser.java b/core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultMaskParser.java new file mode 100644 index 00000000..a316515b --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultMaskParser.java @@ -0,0 +1,187 @@ +package com.sk89q.worldedit.extension.factory; + +import com.boydti.fawe.object.mask.AngleMask; +import com.boydti.fawe.object.mask.DataMask; +import com.boydti.fawe.object.mask.IdDataMask; +import com.boydti.fawe.object.mask.IdMask; +import com.boydti.fawe.object.mask.XAxisMask; +import com.boydti.fawe.object.mask.YAxisMask; +import com.boydti.fawe.object.mask.ZAxisMask; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.BiomeMask2D; +import com.sk89q.worldedit.function.mask.BlockMask; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.mask.ExpressionMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.MaskIntersection; +import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.function.mask.NoiseFilter; +import com.sk89q.worldedit.function.mask.OffsetMask; +import com.sk89q.worldedit.function.mask.RegionMask; +import com.sk89q.worldedit.function.mask.SolidBlockMask; +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.ExpressionException; +import com.sk89q.worldedit.internal.registry.InputParser; +import com.sk89q.worldedit.math.noise.RandomNoise; +import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; +import com.sk89q.worldedit.session.request.Request; +import com.sk89q.worldedit.session.request.RequestSelection; +import com.sk89q.worldedit.world.biome.BaseBiome; +import com.sk89q.worldedit.world.biome.Biomes; +import com.sk89q.worldedit.world.registry.BiomeRegistry; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Parses mask input strings. + */ +public class DefaultMaskParser extends InputParser { + + public DefaultMaskParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Mask parseFromInput(String input, ParserContext context) throws InputParseException { + List masks = new ArrayList(); + + for (String component : input.split(" ")) { + if (component.isEmpty()) { + continue; + } + + Mask current = getBlockMaskComponent(masks, component, context); + + masks.add(current); + } + + switch (masks.size()) { + case 0: + return null; + + case 1: + return masks.get(0); + + default: + return new MaskIntersection(masks); + } + } + + private Mask getBlockMaskComponent(List masks, String component, ParserContext context) throws InputParseException { + Extent extent = Request.request().getEditSession(); + + final char firstChar = component.charAt(0); + switch (firstChar) { + case '#': + switch (component.toLowerCase()) { + case "#existing": + return new ExistingBlockMask(extent); + case "#solid": + return new SolidBlockMask(extent); + case "#dregion": + case "#dselection": + case "#dsel": + return new RegionMask(new RequestSelection()); + case "#selection": + case "#region": + case "#sel": + try { + return new RegionMask(context.requireSession().getSelection(context.requireWorld()).clone()); + } catch (IncompleteRegionException e) { + throw new InputParseException("Please make a selection first."); + } + case "#xaxis": + return new XAxisMask(); + case "#yaxis": + return new YAxisMask(); + case "#zaxis": + return new ZAxisMask(); + case "#id": + return new IdMask(extent); + case "#data": + return new DataMask(extent); + case "#iddata": + return new IdDataMask(extent); + default: + throw new NoMatchException("Unrecognized mask '" + component + "'"); + } + case '\\': + case '/': { + String[] split = component.substring(1).split(","); + if (split.length != 2) { + throw new InputParseException("Unknown angle '" + component + "' (not in form /#,#)"); + } + try { + int y1 = Integer.parseInt(split[0]); + int y2 = Integer.parseInt(split[1]); + return new AngleMask(extent, y1, y2); + } catch (NumberFormatException e) { + throw new InputParseException("Unknown angle '" + component + "' (not in form /#,#)"); + } + } + case '>': + case '<': + Mask submask; + if (component.length() > 1) { + submask = getBlockMaskComponent(masks, component.substring(1), context); + } else { + submask = new ExistingBlockMask(extent); + } + OffsetMask offsetMask = new OffsetMask(submask, new Vector(0, firstChar == '>' ? -1 : 1, 0)); + return new MaskIntersection(offsetMask, Masks.negate(submask)); + + case '$': + Set biomes = new HashSet(); + String[] biomesList = component.substring(1).split(","); + BiomeRegistry biomeRegistry = context.requireWorld().getWorldData().getBiomeRegistry(); + List knownBiomes = biomeRegistry.getBiomes(); + for (String biomeName : biomesList) { + BaseBiome biome = Biomes.findBiomeByName(knownBiomes, biomeName, biomeRegistry); + if (biome == null) { + throw new InputParseException("Unknown biome '" + biomeName + "'"); + } + biomes.add(biome); + } + + return Masks.asMask(new BiomeMask2D(context.requireExtent(), biomes)); + + case '%': + int i = Integer.parseInt(component.substring(1)); + return new NoiseFilter(new RandomNoise(), ((double) i) / 100); + + case '=': + try { + Expression exp = Expression.compile(component.substring(1), "x", "y", "z"); + WorldEditExpressionEnvironment env = new WorldEditExpressionEnvironment( + Request.request().getEditSession(), Vector.ONE, Vector.ZERO); + exp.setEnvironment(env); + return new ExpressionMask(exp); + } catch (ExpressionException e) { + throw new InputParseException("Invalid expression: " + e.getMessage()); + } + + case '!': + if (component.length() > 1) { + return Masks.negate(getBlockMaskComponent(masks, component.substring(1), context)); + } + + default: + ParserContext tempContext = new ParserContext(context); + tempContext.setRestricted(false); + tempContext.setPreferringWildcard(true); + return new BlockMask(extent, worldEdit.getBlockFactory().parseFromListInput(component, tempContext)); + } + } + + public static Class inject() { + return DefaultMaskParser.class; + } +} \ No newline at end of file diff --git a/core/src/main/java/com/sk89q/worldedit/function/mask/Masks.java b/core/src/main/java/com/sk89q/worldedit/function/mask/Masks.java new file mode 100644 index 00000000..d5119042 --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/function/mask/Masks.java @@ -0,0 +1,234 @@ +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.session.request.Request; +import javax.annotation.Nullable; + + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Various utility functions related to {@link Mask} and {@link Mask2D}. + */ +public final class Masks { + + private static final AlwaysTrue ALWAYS_TRUE = new AlwaysTrue(); + private static final AlwaysFalse ALWAYS_FALSE = new AlwaysFalse(); + + private Masks() { + } + + /** + * Return a 3D mask that always returns true; + * + * @return a mask + */ + public static Mask alwaysTrue() { + return ALWAYS_TRUE; + } + + /** + * Return a 2D mask that always returns true; + * + * @return a mask + */ + public static Mask2D alwaysTrue2D() { + return ALWAYS_TRUE; + } + + /** + * Negate the given mask. + * + * @param finalMask the mask + * @return a new mask + */ + public static Mask negate(final Mask finalMask) { + if (finalMask instanceof AlwaysTrue) { + return ALWAYS_FALSE; + } else if (finalMask instanceof AlwaysFalse) { + return ALWAYS_TRUE; + } + checkNotNull(finalMask); + return new AbstractMask() { + private Mask mask = finalMask; + @Override + public boolean test(Vector vector) { + return !mask.test(vector); + } + + @Nullable + @Override + public Mask2D toMask2D() { + Mask2D mask2d = mask.toMask2D(); + if (mask2d != null) { + return negate(mask2d); + } else { + return null; + } + } + }; + } + + /** + * Negate the given mask. + * + * @param mask the mask + * @return a new mask + */ + public static Mask2D negate(final Mask2D mask) { + if (mask instanceof AlwaysTrue) { + return ALWAYS_FALSE; + } else if (mask instanceof AlwaysFalse) { + return ALWAYS_TRUE; + } + + checkNotNull(mask); + return new AbstractMask2D() { + @Override + public boolean test(Vector2D vector) { + return !mask.test(vector); + } + }; + } + + /** + * Return a 3-dimensional version of a 2D mask. + * + * @param mask the mask to make 3D + * @return a 3D mask + */ + public static Mask asMask(final Mask2D mask) { + return new AbstractMask() { + @Override + public boolean test(Vector vector) { + return mask.test(vector.toVector2D()); + } + + @Nullable + @Override + public Mask2D toMask2D() { + return mask; + } + }; + } + + /** + * Wrap an old-style mask and convert it to a new mask. + * + *

Note, however, that this is strongly not recommended because + * {@link com.sk89q.worldedit.masks.Mask#prepare(LocalSession, LocalPlayer, Vector)} + * is not called.

+ * + * @param mask the old-style mask + * @param editSession the edit session to bind to + * @return a new-style mask + * @deprecated Please avoid if possible + */ + @Deprecated + @SuppressWarnings("deprecation") + public static Mask wrap(final com.sk89q.worldedit.masks.Mask mask, final EditSession editSession) { + checkNotNull(mask); + return new AbstractMask() { + @Override + public boolean test(Vector vector) { + return mask.matches(editSession, vector); + } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } + }; + } + + /** + * Wrap an old-style mask and convert it to a new mask. + * + *

As an {@link EditSession} is not provided in this case, one will be + * taken from the {@link Request}, if possible. If not possible, then the + * mask will return false.

+ * + * @param mask the old-style mask + * @return a new-style mask + */ + @SuppressWarnings("deprecation") + public static Mask wrap(final com.sk89q.worldedit.masks.Mask mask) { + checkNotNull(mask); + return new AbstractMask() { + @Override + public boolean test(Vector vector) { + EditSession editSession = Request.request().getEditSession(); + return editSession != null && mask.matches(editSession, vector); + } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } + }; + } + + /** + * Convert a new-style mask to an old-style mask. + * + * @param mask the new-style mask + * @return an old-style mask + */ + @SuppressWarnings("deprecation") + public static com.sk89q.worldedit.masks.Mask wrap(final Mask mask) { + checkNotNull(mask); + return new com.sk89q.worldedit.masks.AbstractMask() { + @Override + public boolean matches(EditSession editSession, Vector position) { + Request.request().setEditSession(editSession); + return mask.test(position); + } + }; + } + + private static class AlwaysTrue implements Mask, Mask2D { + @Override + public boolean test(Vector vector) { + return true; + } + + @Override + public boolean test(Vector2D vector) { + return true; + } + + @Nullable + @Override + public Mask2D toMask2D() { + return this; + } + } + + private static class AlwaysFalse implements Mask, Mask2D { + @Override + public boolean test(Vector vector) { + return false; + } + + @Override + public boolean test(Vector2D vector) { + return false; + } + + @Nullable + @Override + public Mask2D toMask2D() { + return this; + } + } + + public static Class inject() { + return Masks.class; + } +} \ No newline at end of file diff --git a/core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java b/core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java new file mode 100644 index 00000000..78729eb1 --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java @@ -0,0 +1,92 @@ +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.Vector; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Checks whether another mask tests true for a position that is offset + * a given vector. + */ +public class OffsetMask extends AbstractMask { + + private Mask mask; + private Vector offset; + private Vector mutable = new Vector(); + + /** + * Create a new instance. + * + * @param mask the mask + * @param offset the offset + */ + public OffsetMask(Mask mask, Vector offset) { + checkNotNull(mask); + checkNotNull(offset); + this.mask = mask; + this.offset = offset; + } + + /** + * Get the mask. + * + * @return the mask + */ + public Mask getMask() { + return mask; + } + + /** + * Set the mask. + * + * @param mask the mask + */ + public void setMask(Mask mask) { + checkNotNull(mask); + this.mask = mask; + } + + /** + * Get the offset. + * + * @return the offset + */ + public Vector getOffset() { + return offset; + } + + /** + * Set the offset. + * + * @param offset the offset + */ + public void setOffset(Vector offset) { + checkNotNull(offset); + this.offset = offset; + } + + @Override + public boolean test(Vector vector) { + mutable.x = vector.x + offset.x; + mutable.y = vector.y + offset.y; + mutable.z = vector.z + offset.z; + return getMask().test(mutable); + } + + @Nullable + @Override + public Mask2D toMask2D() { + Mask2D childMask = getMask().toMask2D(); + if (childMask != null) { + return new OffsetMask2D(childMask, getOffset().toVector2D()); + } else { + return null; + } + } + + public static Class inject() { + return OffsetMask.class; + } +} diff --git a/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java b/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java index e61e7eb7..d7279a70 100644 --- a/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java +++ b/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java @@ -120,6 +120,9 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { * Clamps the cuboid according to boundaries of the world. */ private void recalculate() { + if (pos1 == null || pos2 == null) { + return; + } pos1 = pos1.clampY(0, world == null ? 255 : world.getMaxY()); pos2 = pos2.clampY(0, world == null ? 255 : world.getMaxY()); Vector min = getMinimumPoint(); 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 173916de..3022a16e 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 @@ -88,7 +88,6 @@ public class CuboidRegionSelector extends com.sk89q.worldedit.regions.CuboidRegi position1 = oldRegion.getMinimumPoint().toBlockVector(); position2 = oldRegion.getMaximumPoint().toBlockVector(); } - region.setPos1(position1); region.setPos2(position2); }