diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/Blocks.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/Blocks.java index 09bd50ff22..939fb7e7e6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/Blocks.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/Blocks.java @@ -36,6 +36,28 @@ public final class Blocks { private Blocks() { } + /** + * HashSet for shouldPlaceLate. + */ + private static final Set shouldPlaceLate = new HashSet<>(); + static { + shouldPlaceLate.add(BlockTypes.WATER); + shouldPlaceLate.add(BlockTypes.LAVA); + shouldPlaceLate.add(BlockTypes.GRAVEL); + shouldPlaceLate.add(BlockTypes.SAND); + } + /** + * Checks to see whether a block should be placed in the final queue. + * + * This applies to blocks that can be attached to other blocks that have an attachment. + * + * @param type the type of the block + * @return whether the block is in the late queue + */ + public static boolean shouldPlaceLate(BlockType type) { + return shouldPlaceLate.contains(type); + } + /** * HashSet for shouldPlaceLast. */ diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java index 3ef74dd7ac..d6e3d26575 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.extent.reorder; -import com.google.common.collect.Iterables; import com.sk89q.worldedit.BlockVector; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; @@ -38,6 +37,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockTypes; +import java.util.ArrayList; import java.util.Deque; import java.util.HashMap; import java.util.HashSet; @@ -51,29 +51,34 @@ */ public class MultiStageReorder extends AbstractDelegateExtent implements ReorderingExtent { - private LocatedBlockList stage1 = new LocatedBlockList(); - private LocatedBlockList stage2 = new LocatedBlockList(); - private LocatedBlockList stage3 = new LocatedBlockList(); + private static final int STAGE_COUNT = 4; + + private List stages = new ArrayList<>(); + private boolean enabled; /** - * Create a new instance. + * Create a new instance when the re-ordering is enabled. * * @param extent the extent - * @param enabled true to enable */ - public MultiStageReorder(Extent extent, boolean enabled) { - super(extent); - this.enabled = enabled; + public MultiStageReorder(Extent extent) { + this(extent, true); } /** - * Create a new instance when the re-ordering is enabled. + * Create a new instance. * * @param extent the extent + * @param enabled true to enable */ - public MultiStageReorder(Extent extent) { - this(extent, true); + public MultiStageReorder(Extent extent, boolean enabled) { + super(extent); + this.enabled = enabled; + + for (int i = 0; i < STAGE_COUNT; ++i) { + stages.add(new LocatedBlockList()); + } } /** @@ -94,55 +99,73 @@ public void setEnabled(boolean enabled) { this.enabled = enabled; } + /** + * Gets the stage priority of the block. + * + * @param block The block + * @return The priority + */ + public int getPlacementPriority(BlockStateHolder block) { + if (Blocks.shouldPlaceLate(block.getBlockType())) { + return 1; + } else if (Blocks.shouldPlaceLast(block.getBlockType())) { + // Place torches, etc. last + return 2; + } else if (Blocks.shouldPlaceFinal(block.getBlockType())) { + // Place signs, reed, etc even later + return 3; + } else { + return 0; + } + } + @Override public boolean setBlock(Vector location, BlockStateHolder block) throws WorldEditException { - BlockState existing = getBlock(location); - if (!enabled) { return super.setBlock(location, block); } - if (Blocks.shouldPlaceLast(block.getBlockType())) { - // Place torches, etc. last - stage2.add(location.toBlockVector(), block); - return !existing.equalsFuzzy(block); - } else if (Blocks.shouldPlaceFinal(block.getBlockType())) { - // Place signs, reed, etc even later - stage3.add(location.toBlockVector(), block); - return !existing.equalsFuzzy(block); - } else if (Blocks.shouldPlaceLast(existing.getBlockType())) { + BlockState existing = getBlock(location); + int priority = getPlacementPriority(block); + int srcPriority = getPlacementPriority(existing); + + if (srcPriority == 1 || srcPriority == 2) { // Destroy torches, etc. first super.setBlock(location, BlockTypes.AIR.getDefaultState()); return super.setBlock(location, block); - } else { - stage1.add(location.toBlockVector(), block); - return !existing.equalsFuzzy(block); } + + stages.get(priority).add(location.toBlockPoint(), block); + return !existing.equalsFuzzy(block); } @Override public Operation commitBefore() { - return new OperationQueue( - new SetLocatedBlocks( - getExtent(), - Iterables.concat(stage1, stage2)), - new Stage3Committer()); + List operations = new ArrayList<>(); + for (int i = 0; i < stages.size() - 1; ++i) { + operations.add(new SetLocatedBlocks(getExtent(), stages.get(i))); + } + + operations.add(new FinalStageCommitter()); + return new OperationQueue(operations); } - private class Stage3Committer implements Operation { + private class FinalStageCommitter implements Operation { + private Extent extent = getExtent(); - @Override - public Operation resume(RunContext run) throws WorldEditException { - Extent extent = getExtent(); + private final Set blocks = new HashSet<>(); + private final Map blockTypes = new HashMap<>(); - final Set blocks = new HashSet<>(); - final Map blockTypes = new HashMap<>(); - for (LocatedBlock entry : stage3) { + public FinalStageCommitter() { + for (LocatedBlock entry : stages.get(stages.size() - 1)) { final BlockVector pt = entry.getLocation().toBlockVector(); blocks.add(pt); blockTypes.put(pt, entry.getBlock()); } + } + @Override + public Operation resume(RunContext run) throws WorldEditException { while (!blocks.isEmpty()) { BlockVector current = blocks.iterator().next(); if (!blocks.contains(current)) { @@ -198,11 +221,14 @@ public Operation resume(RunContext run) throws WorldEditException { } } - stage1.clear(); - stage2.clear(); - stage3.clear(); + if (blocks.isEmpty()) { + for (LocatedBlockList stage : stages) { + stage.clear(); + } + return null; + } - return null; + return this; } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ArrayListHistory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ArrayListHistory.java index bc13a57550..d014835d30 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ArrayListHistory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ArrayListHistory.java @@ -35,10 +35,24 @@ public class ArrayListHistory implements ChangeSet { private final List changes = new ArrayList<>(); + private boolean recordChanges = true; + @Override public void add(Change change) { checkNotNull(change); - changes.add(change); + if (recordChanges) { + changes.add(change); + } + } + + @Override + public boolean isRecordingChanges() { + return recordChanges; + } + + @Override + public void setRecordChanges(boolean recordChanges) { + this.recordChanges = recordChanges; } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java b/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java index 0b018bcb94..fc5adb2e7b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java @@ -36,6 +36,19 @@ public interface ChangeSet { */ void add(Change change); + /** + * Whether or not the ChangeSet is recording changes. + * + * @return whether or not the ChangeSet is set to record changes + */ + boolean isRecordingChanges(); + /** + * Tell the change set whether to record changes or not. + * + * @param recordChanges whether to record changes or not + */ + void setRecordChanges(boolean recordChanges); + /** * Get a backward directed iterator that can be used for undo. *