Changed Super Pickaxe to use EditSession.

This fixes WORLDEDIT-3102 and allows the logging of Super Pickaxe
usage via the EditSession Extent pipeline.
This commit is contained in:
sk89q 2014-04-23 00:33:00 -07:00
parent bf062298f1
commit f94be80923
7 changed files with 253 additions and 40 deletions

View File

@ -19,17 +19,17 @@
package com.sk89q.worldedit; 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.BaseBlock;
import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.blocks.BlockID;
import com.sk89q.worldedit.blocks.BlockType; import com.sk89q.worldedit.blocks.BlockType;
import com.sk89q.worldedit.event.extent.EditSessionEvent; import com.sk89q.worldedit.event.extent.EditSessionEvent;
import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.extent.ChangeSetExtent;
import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.expression.runtime.RValue; import com.sk89q.worldedit.extent.MaskingExtent;
import com.sk89q.worldedit.extent.*; 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.inventory.BlockBagExtent;
import com.sk89q.worldedit.extent.reorder.MultiStageReorder; import com.sk89q.worldedit.extent.reorder.MultiStageReorder;
import com.sk89q.worldedit.extent.validation.BlockChangeLimiter; 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.BlockQuirkExtent;
import com.sk89q.worldedit.extent.world.ChunkLoadingExtent; import com.sk89q.worldedit.extent.world.ChunkLoadingExtent;
import com.sk89q.worldedit.extent.world.FastModeExtent; 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.GroundFunction;
import com.sk89q.worldedit.function.RegionMaskingFilter; 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.BlockReplace;
import com.sk89q.worldedit.function.block.Counter;
import com.sk89q.worldedit.function.block.Naturalizer; import com.sk89q.worldedit.function.block.Naturalizer;
import com.sk89q.worldedit.function.generator.GardenPatchGenerator; import com.sk89q.worldedit.function.generator.GardenPatchGenerator;
import com.sk89q.worldedit.function.mask.*; 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.change.BlockChange;
import com.sk89q.worldedit.history.changeset.BlockOptimizedHistory; import com.sk89q.worldedit.history.changeset.BlockOptimizedHistory;
import com.sk89q.worldedit.history.changeset.ChangeSet; 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.masks.Mask;
import com.sk89q.worldedit.math.interpolation.Interpolation; import com.sk89q.worldedit.math.interpolation.Interpolation;
import com.sk89q.worldedit.math.interpolation.KochanekBartelsInterpolation; 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.TreeGenerator;
import com.sk89q.worldedit.util.collection.DoubleArrayList; import com.sk89q.worldedit.util.collection.DoubleArrayList;
import com.sk89q.worldedit.util.eventbus.EventBus; import com.sk89q.worldedit.util.eventbus.EventBus;
import com.sk89q.worldedit.world.NullWorld;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -105,6 +110,7 @@ public class EditSession implements Extent {
private final ChangeSet changeSet = new BlockOptimizedHistory(); private final ChangeSet changeSet = new BlockOptimizedHistory();
private @Nullable FastModeExtent fastModeExtent; private @Nullable FastModeExtent fastModeExtent;
private final SurvivalModeExtent survivalExtent;
private @Nullable ChunkLoadingExtent chunkLoadingExtent; private @Nullable ChunkLoadingExtent chunkLoadingExtent;
private @Nullable LastAccessExtentCache cacheExtent; private @Nullable LastAccessExtentCache cacheExtent;
private @Nullable BlockQuirkExtent quirkExtent; private @Nullable BlockQuirkExtent quirkExtent;
@ -160,6 +166,7 @@ public class EditSession implements Extent {
// This extents are ALWAYS used // This extents are ALWAYS used
extent = fastModeExtent = new FastModeExtent(world, false); extent = fastModeExtent = new FastModeExtent(world, false);
extent = survivalExtent = new SurvivalModeExtent(extent, world);
extent = quirkExtent = new BlockQuirkExtent(extent, world); extent = quirkExtent = new BlockQuirkExtent(extent, world);
extent = chunkLoadingExtent = new ChunkLoadingExtent(extent, world); extent = chunkLoadingExtent = new ChunkLoadingExtent(extent, world);
extent = cacheExtent = new LastAccessExtentCache(extent); extent = cacheExtent = new LastAccessExtentCache(extent);
@ -182,6 +189,7 @@ public class EditSession implements Extent {
this.bypassNone = extent; this.bypassNone = extent;
} else { } else {
Extent extent = new NullExtent(); Extent extent = new NullExtent();
extent = survivalExtent = new SurvivalModeExtent(extent, new NullWorld());
extent = blockBagExtent = new BlockBagExtent(extent, blockBag); extent = blockBagExtent = new BlockBagExtent(extent, blockBag);
extent = reorderExtent = new MultiStageReorder(extent, false); extent = reorderExtent = new MultiStageReorder(extent, false);
extent = maskingExtent = new MaskingExtent(extent, Masks.alwaysTrue()); 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. * Set whether fast mode is enabled.
* </p> * </p>

View File

@ -57,18 +57,16 @@ public class AreaPickaxe implements BlockTool {
} }
EditSession editSession = session.createEditSession(player); EditSession editSession = session.createEditSession(player);
editSession.getSurvivalExtent().setToolUse(config.superPickaxeManyDrop);
try { try {
for (int x = ox - range; x <= ox + range; ++x) { for (int x = ox - range; x <= ox + range; ++x) {
for (int y = oy - range; y <= oy + range; ++y) { for (int y = oy - range; y <= oy + range; ++y) {
for (int z = oz - range; z <= oz + range; ++z) { for (int z = oz - range; z <= oz + range; ++z) {
Vector pos = new Vector(x, y, z); Vector pos = new Vector(x, y, z);
if (world.getBlockType(pos) != initialType) { if (editSession.getBlockType(pos) != initialType) {
continue; continue;
} }
if (config.superPickaxeManyDrop) {
world.simulateBlockMine(pos);
}
world.queueBlockBreakEffect(server, pos, initialType, clicked.distanceSq(pos)); world.queueBlockBreakEffect(server, pos, initialType, clicked.distanceSq(pos));
@ -79,6 +77,7 @@ public class AreaPickaxe implements BlockTool {
} catch (MaxChangedBlocksException e) { } catch (MaxChangedBlocksException e) {
player.printError("Max blocks change limit reached."); player.printError("Max blocks change limit reached.");
} finally { } finally {
editSession.flushQueue();
session.remember(editSession); session.remember(editSession);
} }

View File

@ -19,13 +19,13 @@
package com.sk89q.worldedit.command.tool; package com.sk89q.worldedit.command.tool;
import java.util.HashSet;
import java.util.Set;
import com.sk89q.worldedit.*; import com.sk89q.worldedit.*;
import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BlockID; 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 * A pickaxe mode that recursively finds adjacent blocks within range of
* an initial block and of the same type. * an initial block and of the same type.
@ -59,14 +59,15 @@ public class RecursivePickaxe implements BlockTool {
} }
EditSession editSession = session.createEditSession(player); EditSession editSession = session.createEditSession(player);
editSession.getSurvivalExtent().setToolUse(config.superPickaxeManyDrop);
try { try {
recurse(server, editSession, world, clicked.toBlockVector(), recurse(server, editSession, world, clicked.toBlockVector(),
clicked, range, initialType, new HashSet<BlockVector>(), clicked, range, initialType, new HashSet<BlockVector>());
config.superPickaxeManyDrop);
} catch (MaxChangedBlocksException e) { } catch (MaxChangedBlocksException e) {
player.printError("Max blocks change limit reached."); player.printError("Max blocks change limit reached.");
} finally { } finally {
editSession.flushQueue();
session.remember(editSession); session.remember(editSession);
} }
@ -77,7 +78,6 @@ public class RecursivePickaxe implements BlockTool {
* Helper method. * Helper method.
* *
* @param server * @param server
* @param superPickaxeManyDrop
* @param world * @param world
* @param pos * @param pos
* @param origin * @param origin
@ -88,7 +88,7 @@ public class RecursivePickaxe implements BlockTool {
private static void recurse(ServerInterface server, EditSession editSession, private static void recurse(ServerInterface server, EditSession editSession,
LocalWorld world, BlockVector pos, LocalWorld world, BlockVector pos,
Vector origin, double size, int initialType, Vector origin, double size, int initialType,
Set<BlockVector> visited, boolean drop) Set<BlockVector> visited)
throws MaxChangedBlocksException { throws MaxChangedBlocksException {
final double distanceSq = origin.distanceSq(pos); final double distanceSq = origin.distanceSq(pos);
@ -102,26 +102,22 @@ public class RecursivePickaxe implements BlockTool {
return; return;
} }
if (drop) {
world.simulateBlockMine(pos);
}
world.queueBlockBreakEffect(server, pos, initialType, distanceSq); world.queueBlockBreakEffect(server, pos, initialType, distanceSq);
editSession.setBlock(pos, air); editSession.setBlock(pos, air);
recurse(server, editSession, world, pos.add(1, 0, 0).toBlockVector(), 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(), 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(), 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(), 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(), 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(), recurse(server, editSession, world, pos.add(0, -1, 0).toBlockVector(),
origin, size, initialType, visited, drop); origin, size, initialType, visited);
} }
} }

View File

@ -20,6 +20,7 @@
package com.sk89q.worldedit.command.tool; package com.sk89q.worldedit.command.tool;
import com.sk89q.worldedit.*; import com.sk89q.worldedit.*;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.blocks.BlockID;
/** /**
@ -43,11 +44,16 @@ public class SinglePickaxe implements BlockTool {
return true; return true;
} }
if (config.superPickaxeDrop) { EditSession editSession = session.createEditSession(player);
world.simulateBlockMine(clicked); 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); world.playEffect(clicked, 2001, blockType);

View File

@ -0,0 +1,92 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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.
* </p>
* 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.
* </p>
* 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);
}
}
}

View File

@ -138,10 +138,8 @@ public abstract class AbstractWorld implements World {
public void simulateBlockMine(Vector pt) { public void simulateBlockMine(Vector pt) {
BaseBlock block = getLazyBlock(pt); BaseBlock block = getLazyBlock(pt);
BaseItemStack stack = BlockType.getBlockDrop(block.getId(), (short) block.getData()); BaseItemStack stack = BlockType.getBlockDrop(block.getId(), (short) block.getData());
if (stack == null) {
return;
}
if (stack != null) {
final int amount = stack.getAmount(); final int amount = stack.getAmount();
if (amount > 1) { if (amount > 1) {
dropItem(pt, new BaseItemStack(stack.getType(), 1, stack.getData()), amount); dropItem(pt, new BaseItemStack(stack.getType(), 1, stack.getData()), amount);
@ -150,6 +148,13 @@ public abstract class AbstractWorld implements World {
} }
} }
try {
setBlock(pt, new BaseBlock(BlockID.AIR));
} catch (WorldEditException e) {
throw new RuntimeException(e);
}
}
@Override @Override
public LocalEntity[] getEntities(Region region) { public LocalEntity[] getEntities(Region region) {
return new LocalEntity[0]; return new LocalEntity[0];

View File

@ -0,0 +1,98 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
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);
}
}