Added events for each stage of EditSession Extent creation.

This commit is contained in:
sk89q 2014-04-03 18:24:06 -07:00
parent c8e455cd6f
commit 2e904577b7
4 changed files with 90 additions and 43 deletions

View File

@ -90,13 +90,13 @@ import static com.sk89q.worldedit.regions.Regions.*;
public class EditSession implements Extent {
/**
* Used by {@link #setBlock(Vector, BaseBlock, Level)} to
* Used by {@link #setBlock(Vector, BaseBlock, Stage)} to
* determine which {@link Extent}s should be bypassed.
*/
public enum Level {
NORMAL,
NO_HISTORY_REORDER,
NO_HISTORY
public enum Stage {
BEFORE_HISTORY,
BEFORE_REORDER,
BEFORE_CHANGE
}
@SuppressWarnings("ProtectedField")
@ -138,32 +138,37 @@ public class EditSession implements Extent {
this.world = world;
// This extents are ALWAYS used
fastModeExtent = new FastModeExtent(world, false);
chunkLoadingExtent = new ChunkLoadingExtent(fastModeExtent, world);
cacheExtent = new LastAccessExtentCache(chunkLoadingExtent);
// Call the event a plugin can wrap the extent
event.setExtent(cacheExtent);
eventBus.post(event);
Extent wrappedExtent = event.getExtent();
Extent extent;
// This extents are ALWAYS used
quirkExtent = new BlockQuirkExtent(wrappedExtent, world);
validator = new DataValidatorExtent(quirkExtent, world);
blockBagExtent = new BlockBagExtent(validator, world, blockBag);
extent = fastModeExtent = new FastModeExtent(world, false);
extent = chunkLoadingExtent = new ChunkLoadingExtent(extent, world);
extent = cacheExtent = new LastAccessExtentCache(extent);
extent = wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE);
extent = quirkExtent = new BlockQuirkExtent(extent, world);
extent = validator = new DataValidatorExtent(extent, world);
extent = blockBagExtent = new BlockBagExtent(extent, world, blockBag);
// This extent can be skipped by calling rawSetBlock()
reorderExtent = new MultiStageReorder(blockBagExtent, false);
extent = reorderExtent = new MultiStageReorder(extent, false);
extent = wrapExtent(extent, eventBus, event, Stage.BEFORE_REORDER);
// These extents can be skipped by calling smartSetBlock()
changeSetExtent = new ChangeSetExtent(reorderExtent, changeSet);
maskingExtent = new MaskingExtent(changeSetExtent, Masks.alwaysTrue());
changeLimiter = new BlockChangeLimiter(maskingExtent, maxBlocks);
extent = changeSetExtent = new ChangeSetExtent(extent, changeSet);
extent = maskingExtent = new MaskingExtent(extent, Masks.alwaysTrue());
extent = changeLimiter = new BlockChangeLimiter(extent, maxBlocks);
extent = wrapExtent(extent, eventBus, event, Stage.BEFORE_HISTORY);
this.bypassReorderHistory = blockBagExtent;
this.bypassHistory = reorderExtent;
this.bypassNone = changeLimiter;
this.bypassNone = extent;
}
private Extent wrapExtent(Extent extent, EventBus eventBus, EditSessionEvent event, Stage stage) {
event = event.clone(stage);
event.setExtent(extent);
eventBus.post(event);
return event.getExtent();
}
/**
@ -402,16 +407,16 @@ public class EditSession implements Extent {
*
* @param position the position to set the block at
* @param block the block
* @param level the level
* @param stage the level
* @return whether the block changed
*/
public boolean setBlock(Vector position, BaseBlock block, Level level) throws WorldEditException {
switch (level) {
case NORMAL:
public boolean setBlock(Vector position, BaseBlock block, Stage stage) throws WorldEditException {
switch (stage) {
case BEFORE_HISTORY:
return bypassNone.setBlock(position, block);
case NO_HISTORY_REORDER:
case BEFORE_CHANGE:
return bypassHistory.setBlock(position, block);
case NO_HISTORY:
case BEFORE_REORDER:
return bypassReorderHistory.setBlock(position, block);
}
@ -424,12 +429,10 @@ public class EditSession implements Extent {
* @param position the position to set the block at
* @param block the block
* @return whether the block changed
* @deprecated Use {@link #setBlock(Vector, BaseBlock, Level)}
*/
@Deprecated
public boolean rawSetBlock(Vector position, BaseBlock block) {
try {
return setBlock(position, block, Level.NO_HISTORY_REORDER);
return setBlock(position, block, Stage.BEFORE_CHANGE);
} catch (WorldEditException e) {
throw new RuntimeException("Unexpected exception", e);
}
@ -441,12 +444,10 @@ public class EditSession implements Extent {
* @param position the position to set the block at
* @param block the block
* @return whether the block changed
* @deprecated Use {@link #setBlock(Vector, BaseBlock, Level)}
*/
@Deprecated
public boolean smartSetBlock(Vector position, BaseBlock block) {
try {
return setBlock(position, block, Level.NO_HISTORY);
return setBlock(position, block, Stage.BEFORE_REORDER);
} catch (WorldEditException e) {
throw new RuntimeException("Unexpected exception", e);
}
@ -455,7 +456,7 @@ public class EditSession implements Extent {
@Override
public boolean setBlock(Vector position, BaseBlock block) throws MaxChangedBlocksException {
try {
return setBlock(position, block, Level.NORMAL);
return setBlock(position, block, Stage.BEFORE_HISTORY);
} catch (MaxChangedBlocksException e) {
throw e;
} catch (WorldEditException e) {

View File

@ -33,6 +33,7 @@ import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.registry.BlockRegistry;
import com.sk89q.worldedit.extension.registry.MaskRegistry;
import com.sk89q.worldedit.extension.registry.PatternRegistry;
import com.sk89q.worldedit.extent.ExtentDelegate;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.function.pattern.Patterns;
@ -46,6 +47,7 @@ import com.sk89q.worldedit.scripting.RhinoCraftScriptEngine;
import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.util.LogFormat;
import com.sk89q.worldedit.util.eventbus.EventBus;
import com.sk89q.worldedit.util.eventbus.Subscribe;
import javax.script.ScriptException;
import java.io.*;

View File

@ -22,39 +22,63 @@ package com.sk89q.worldedit.event.extent;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalPlayer;
import com.sk89q.worldedit.LocalWorld;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.event.Event;
import com.sk89q.worldedit.extent.Extent;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.EditSession.Stage;
/**
* Raised when a new {@link EditSession} is being instantiated.
* Raised (several times) when a new {@link EditSession} is being instantiated.
* </p>
* Block loggers, as well as block set interceptors, can use this event to wrap
* the given {@link Extent} with their own, which would allow them to intercept
* all changes made to the world.
* all changes made to the world. For example, the code below would wrap the
* existing extent with a custom one, and the custom extent would receive
* all method calls <strong>before</strong> the extent fetched from
* {@link #getExtent()} would.
* <pre>
* event.setExtent(new MyExtent(event.getExtent())
* </pre>
* This event is fired several times during the creation of a single
* {@link EditSession}, but {@link #getStage()} will differ each time.
* The stage determines at which point {@link Extent}s added to this event
* will be called. For example, if you inject an extent when the stage
* is set to {@link Stage#BEFORE_HISTORY}, then you can drop (or log) changes
* before the change has reached the history, reordering, and actual change
* extents, <em>but</em> that means that any changes made with
* {@link EditSession#rawSetBlock(Vector, BaseBlock)} will skip your
* custom {@link Extent} because that method bypasses history (and reorder).
* It is thus recommended that loggers intercept at {@link Stage#BEFORE_CHANGE}
* and block interceptors intercept at BOTH {@link Stage#BEFORE_CHANGE} and
* {@link Stage#BEFORE_HISTORY}.
*/
public class EditSessionEvent extends Event {
private final LocalWorld world;
private final LocalPlayer player;
private final int maxBlocks;
private final Stage stage;
private Extent extent;
/**
* Create a new event.
*
* @param player the player, or null if not available
* @param world the world
* @param player the player, or null if not available
* @param maxBlocks the maximum number of block changes
* @param stage the stage
*/
public EditSessionEvent(LocalWorld world, LocalPlayer player, int maxBlocks) {
public EditSessionEvent(LocalWorld world, LocalPlayer player, int maxBlocks, Stage stage) {
checkNotNull(world);
this.world = world;
this.player = player;
this.maxBlocks = maxBlocks;
this.stage = stage;
}
/**
@ -93,6 +117,15 @@ public class EditSessionEvent extends Event {
return extent;
}
/**
* Get the stage that is being wrapped.
*
* @return the stage
*/
public Stage getStage() {
return stage;
}
/**
* Set a new extent that should be used. It should wrap the extent
* returned from {@link #getExtent()}.
@ -103,4 +136,15 @@ public class EditSessionEvent extends Event {
checkNotNull(extent);
this.extent = extent;
}
/**
* Create a clone of this event with the given stage.
*
* @param stage the stage
* @return a new event
*/
public EditSessionEvent clone(Stage stage) {
return new EditSessionEvent(world, player, maxBlocks, stage);
}
}

View File

@ -49,22 +49,22 @@ public final class InternalEditSessionFactory extends EditSessionFactory {
@Override
public EditSession getEditSession(LocalWorld world, int maxBlocks) {
return new EditSession(eventBus, world, maxBlocks, null, new EditSessionEvent(world, null, maxBlocks));
return new EditSession(eventBus, world, maxBlocks, null, new EditSessionEvent(world, null, maxBlocks, null));
}
@Override
public EditSession getEditSession(LocalWorld world, int maxBlocks, LocalPlayer player) {
return new EditSession(eventBus, world, maxBlocks, null, new EditSessionEvent(world, player, maxBlocks));
return new EditSession(eventBus, world, maxBlocks, null, new EditSessionEvent(world, player, maxBlocks, null));
}
@Override
public EditSession getEditSession(LocalWorld world, int maxBlocks, BlockBag blockBag) {
return new EditSession(eventBus, world, maxBlocks, blockBag, new EditSessionEvent(world, null, maxBlocks));
return new EditSession(eventBus, world, maxBlocks, blockBag, new EditSessionEvent(world, null, maxBlocks, null));
}
@Override
public EditSession getEditSession(LocalWorld world, int maxBlocks, BlockBag blockBag, LocalPlayer player) {
return new EditSession(eventBus, world, maxBlocks, blockBag, new EditSessionEvent(world, player, maxBlocks));
return new EditSession(eventBus, world, maxBlocks, blockBag, new EditSessionEvent(world, player, maxBlocks, null));
}
}