From f94be80923a21e454ed92af43cf773550a8a0a4f Mon Sep 17 00:00:00 2001 From: sk89q Date: Wed, 23 Apr 2014 00:33:00 -0700 Subject: [PATCH] Changed Super Pickaxe to use EditSession. This fixes WORLDEDIT-3102 and allows the logging of Super Pickaxe usage via the EditSession Extent pipeline. --- .../java/com/sk89q/worldedit/EditSession.java | 33 +++++-- .../worldedit/command/tool/AreaPickaxe.java | 7 +- .../command/tool/RecursivePickaxe.java | 30 +++--- .../worldedit/command/tool/SinglePickaxe.java | 14 ++- .../extent/world/SurvivalModeExtent.java | 92 +++++++++++++++++ .../sk89q/worldedit/world/AbstractWorld.java | 19 ++-- .../com/sk89q/worldedit/world/NullWorld.java | 98 +++++++++++++++++++ 7 files changed, 253 insertions(+), 40 deletions(-) create mode 100644 src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/world/NullWorld.java diff --git a/src/main/java/com/sk89q/worldedit/EditSession.java b/src/main/java/com/sk89q/worldedit/EditSession.java index 829ca2412..487395cd1 100644 --- a/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/src/main/java/com/sk89q/worldedit/EditSession.java @@ -19,17 +19,17 @@ package com.sk89q.worldedit; -import com.sk89q.worldedit.extent.buffer.ForgetfulExtentBuffer; -import com.sk89q.worldedit.extent.cache.LastAccessExtentCache; -import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.blocks.BlockType; import com.sk89q.worldedit.event.extent.EditSessionEvent; -import com.sk89q.worldedit.internal.expression.Expression; -import com.sk89q.worldedit.internal.expression.ExpressionException; -import com.sk89q.worldedit.internal.expression.runtime.RValue; -import com.sk89q.worldedit.extent.*; +import com.sk89q.worldedit.extent.ChangeSetExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.MaskingExtent; +import com.sk89q.worldedit.extent.NullExtent; +import com.sk89q.worldedit.extent.buffer.ForgetfulExtentBuffer; +import com.sk89q.worldedit.extent.cache.LastAccessExtentCache; +import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.extent.inventory.BlockBagExtent; import com.sk89q.worldedit.extent.reorder.MultiStageReorder; import com.sk89q.worldedit.extent.validation.BlockChangeLimiter; @@ -37,10 +37,11 @@ import com.sk89q.worldedit.extent.validation.DataValidatorExtent; import com.sk89q.worldedit.extent.world.BlockQuirkExtent; import com.sk89q.worldedit.extent.world.ChunkLoadingExtent; import com.sk89q.worldedit.extent.world.FastModeExtent; +import com.sk89q.worldedit.extent.world.SurvivalModeExtent; import com.sk89q.worldedit.function.GroundFunction; import com.sk89q.worldedit.function.RegionMaskingFilter; -import com.sk89q.worldedit.function.block.Counter; import com.sk89q.worldedit.function.block.BlockReplace; +import com.sk89q.worldedit.function.block.Counter; import com.sk89q.worldedit.function.block.Naturalizer; import com.sk89q.worldedit.function.generator.GardenPatchGenerator; import com.sk89q.worldedit.function.mask.*; @@ -53,6 +54,9 @@ import com.sk89q.worldedit.history.UndoContext; import com.sk89q.worldedit.history.change.BlockChange; import com.sk89q.worldedit.history.changeset.BlockOptimizedHistory; import com.sk89q.worldedit.history.changeset.ChangeSet; +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.ExpressionException; +import com.sk89q.worldedit.internal.expression.runtime.RValue; import com.sk89q.worldedit.masks.Mask; import com.sk89q.worldedit.math.interpolation.Interpolation; import com.sk89q.worldedit.math.interpolation.KochanekBartelsInterpolation; @@ -70,6 +74,7 @@ import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.collection.DoubleArrayList; import com.sk89q.worldedit.util.eventbus.EventBus; +import com.sk89q.worldedit.world.NullWorld; import com.sk89q.worldedit.world.World; import javax.annotation.Nullable; @@ -105,6 +110,7 @@ public class EditSession implements Extent { private final ChangeSet changeSet = new BlockOptimizedHistory(); private @Nullable FastModeExtent fastModeExtent; + private final SurvivalModeExtent survivalExtent; private @Nullable ChunkLoadingExtent chunkLoadingExtent; private @Nullable LastAccessExtentCache cacheExtent; private @Nullable BlockQuirkExtent quirkExtent; @@ -160,6 +166,7 @@ public class EditSession implements Extent { // This extents are ALWAYS used extent = fastModeExtent = new FastModeExtent(world, false); + extent = survivalExtent = new SurvivalModeExtent(extent, world); extent = quirkExtent = new BlockQuirkExtent(extent, world); extent = chunkLoadingExtent = new ChunkLoadingExtent(extent, world); extent = cacheExtent = new LastAccessExtentCache(extent); @@ -182,6 +189,7 @@ public class EditSession implements Extent { this.bypassNone = extent; } else { Extent extent = new NullExtent(); + extent = survivalExtent = new SurvivalModeExtent(extent, new NullWorld()); extent = blockBagExtent = new BlockBagExtent(extent, blockBag); extent = reorderExtent = new MultiStageReorder(extent, false); extent = maskingExtent = new MaskingExtent(extent, Masks.alwaysTrue()); @@ -287,6 +295,15 @@ public class EditSession implements Extent { } } + /** + * Get the {@link SurvivalModeExtent}. + * + * @return the survival simulation extent + */ + public SurvivalModeExtent getSurvivalExtent() { + return survivalExtent; + } + /** * Set whether fast mode is enabled. *

diff --git a/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java b/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java index 5de7d14e0..40f1e4472 100644 --- a/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java @@ -57,18 +57,16 @@ public class AreaPickaxe implements BlockTool { } EditSession editSession = session.createEditSession(player); + editSession.getSurvivalExtent().setToolUse(config.superPickaxeManyDrop); try { for (int x = ox - range; x <= ox + range; ++x) { for (int y = oy - range; y <= oy + range; ++y) { for (int z = oz - range; z <= oz + range; ++z) { Vector pos = new Vector(x, y, z); - if (world.getBlockType(pos) != initialType) { + if (editSession.getBlockType(pos) != initialType) { continue; } - if (config.superPickaxeManyDrop) { - world.simulateBlockMine(pos); - } world.queueBlockBreakEffect(server, pos, initialType, clicked.distanceSq(pos)); @@ -79,6 +77,7 @@ public class AreaPickaxe implements BlockTool { } catch (MaxChangedBlocksException e) { player.printError("Max blocks change limit reached."); } finally { + editSession.flushQueue(); session.remember(editSession); } diff --git a/src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java b/src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java index f886c2e5f..09cbc4340 100644 --- a/src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java @@ -19,13 +19,13 @@ package com.sk89q.worldedit.command.tool; -import java.util.HashSet; -import java.util.Set; - import com.sk89q.worldedit.*; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BlockID; +import java.util.HashSet; +import java.util.Set; + /** * A pickaxe mode that recursively finds adjacent blocks within range of * an initial block and of the same type. @@ -59,14 +59,15 @@ public class RecursivePickaxe implements BlockTool { } EditSession editSession = session.createEditSession(player); + editSession.getSurvivalExtent().setToolUse(config.superPickaxeManyDrop); try { recurse(server, editSession, world, clicked.toBlockVector(), - clicked, range, initialType, new HashSet(), - config.superPickaxeManyDrop); + clicked, range, initialType, new HashSet()); } catch (MaxChangedBlocksException e) { player.printError("Max blocks change limit reached."); } finally { + editSession.flushQueue(); session.remember(editSession); } @@ -77,7 +78,6 @@ public class RecursivePickaxe implements BlockTool { * Helper method. * * @param server - * @param superPickaxeManyDrop * @param world * @param pos * @param origin @@ -88,7 +88,7 @@ public class RecursivePickaxe implements BlockTool { private static void recurse(ServerInterface server, EditSession editSession, LocalWorld world, BlockVector pos, Vector origin, double size, int initialType, - Set visited, boolean drop) + Set visited) throws MaxChangedBlocksException { final double distanceSq = origin.distanceSq(pos); @@ -102,26 +102,22 @@ public class RecursivePickaxe implements BlockTool { return; } - if (drop) { - world.simulateBlockMine(pos); - } - world.queueBlockBreakEffect(server, pos, initialType, distanceSq); editSession.setBlock(pos, air); recurse(server, editSession, world, pos.add(1, 0, 0).toBlockVector(), - origin, size, initialType, visited, drop); + origin, size, initialType, visited); recurse(server, editSession, world, pos.add(-1, 0, 0).toBlockVector(), - origin, size, initialType, visited, drop); + origin, size, initialType, visited); recurse(server, editSession, world, pos.add(0, 0, 1).toBlockVector(), - origin, size, initialType, visited, drop); + origin, size, initialType, visited); recurse(server, editSession, world, pos.add(0, 0, -1).toBlockVector(), - origin, size, initialType, visited, drop); + origin, size, initialType, visited); recurse(server, editSession, world, pos.add(0, 1, 0).toBlockVector(), - origin, size, initialType, visited, drop); + origin, size, initialType, visited); recurse(server, editSession, world, pos.add(0, -1, 0).toBlockVector(), - origin, size, initialType, visited, drop); + origin, size, initialType, visited); } } diff --git a/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java b/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java index f7b662a55..e01c73ea9 100644 --- a/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.command.tool; import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BlockID; /** @@ -43,11 +44,16 @@ public class SinglePickaxe implements BlockTool { return true; } - if (config.superPickaxeDrop) { - world.simulateBlockMine(clicked); - } + EditSession editSession = session.createEditSession(player); + editSession.getSurvivalExtent().setToolUse(config.superPickaxeDrop); - world.setBlockType(clicked, BlockID.AIR); + try { + editSession.setBlock(clicked, new BaseBlock(BlockID.AIR)); + } catch (MaxChangedBlocksException e) { + player.printError("Max blocks change limit reached."); + } finally { + editSession.flushQueue(); + } world.playEffect(clicked, 2001, blockType); diff --git a/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java b/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java new file mode 100644 index 000000000..bbf5b4699 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java @@ -0,0 +1,92 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.world; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockID; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.world.World; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Makes changes to the world as if a player had done so during survival mode. + *

+ * Note that this extent may choose to not call the underlying + * extent and may instead call methods on the {@link World} that is passed + * in the constructor. For that reason, if you wish to "catch" changes, you + * should catch them before the changes reach this extent. + */ +public class SurvivalModeExtent extends AbstractDelegateExtent { + + private final World world; + private boolean toolUse = false; + + /** + * Create a new instance. + * + * @param extent the extent + * @param world the world + */ + public SurvivalModeExtent(Extent extent, World world) { + super(extent); + checkNotNull(world); + this.world = world; + } + + /** + * Return whether changes to the world should be simulated with the + * use of game tools (such as pickaxes) whenever possible and reasonable. + *

+ * For example, we could pretend that the act of setting a coal ore block + * to air (nothing) was the act of a player mining that coal ore block + * with a pickaxe, which would mean that a coal item would be dropped. + * + * @return true if tool use is to be simulated + */ + public boolean hasToolUse() { + return toolUse; + } + + /** + * Set whether changes to the world should be simulated with the + * use of game tools (such as pickaxes) whenever possible and reasonable. + * + * @param toolUse true if tool use is to be simulated + * @see #hasToolUse() for an explanation + */ + public void setToolUse(boolean toolUse) { + this.toolUse = toolUse; + } + + @Override + public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException { + if (toolUse && block.getType() == BlockID.AIR) { + world.simulateBlockMine(location); + return true; + } else { + return super.setBlock(location, block); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java b/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java index 778b4d960..29aa34f78 100644 --- a/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java +++ b/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java @@ -138,15 +138,20 @@ public abstract class AbstractWorld implements World { public void simulateBlockMine(Vector pt) { BaseBlock block = getLazyBlock(pt); BaseItemStack stack = BlockType.getBlockDrop(block.getId(), (short) block.getData()); - if (stack == null) { - return; + + if (stack != null) { + final int amount = stack.getAmount(); + if (amount > 1) { + dropItem(pt, new BaseItemStack(stack.getType(), 1, stack.getData()), amount); + } else { + dropItem(pt, stack, amount); + } } - final int amount = stack.getAmount(); - if (amount > 1) { - dropItem(pt, new BaseItemStack(stack.getType(), 1, stack.getData()), amount); - } else { - dropItem(pt, stack, amount); + try { + setBlock(pt, new BaseBlock(BlockID.AIR)); + } catch (WorldEditException e) { + throw new RuntimeException(e); } } diff --git a/src/main/java/com/sk89q/worldedit/world/NullWorld.java b/src/main/java/com/sk89q/worldedit/world/NullWorld.java new file mode 100644 index 000000000..62edc3352 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/NullWorld.java @@ -0,0 +1,98 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.world; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.blocks.BlockID; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.TreeGenerator.TreeType; + +/** + * A null implementation of {@link World} that drops all changes and + * returns dummy data. + */ +public class NullWorld extends AbstractWorld { + + @Override + public String getName() { + return "null"; + } + + @Override + public boolean setBlock(Vector position, BaseBlock block, boolean notifyAndLight) throws WorldEditException { + return false; + } + + @Override + public int getBlockLightLevel(Vector position) { + return 0; + } + + @Override + public boolean clearContainerBlockContents(Vector position) { + return false; + } + + @Override + public BiomeType getBiome(Vector2D position) { + return null; + } + + @Override + public void setBiome(Vector2D position, BiomeType biome) { + } + + @Override + public void dropItem(Vector position, BaseItemStack item) { + } + + @Override + public int killMobs(Vector origin, double radius, int flags) { + return 0; + } + + @Override + public int removeEntities(EntityType type, Vector origin, int radius) { + return 0; + } + + @Override + public boolean regenerate(Region region, EditSession editSession) { + return false; + } + + @Override + public boolean generateTree(TreeType type, EditSession editSession, Vector position) throws MaxChangedBlocksException { + return false; + } + + @Override + public BaseBlock getBlock(Vector position) { + return new BaseBlock(BlockID.AIR); + } + + @Override + public BaseBlock getLazyBlock(Vector position) { + return new BaseBlock(BlockID.AIR); + } + +}