diff --git a/src/main/java/com/sk89q/worldedit/EditSession.java b/src/main/java/com/sk89q/worldedit/EditSession.java index b226b5397..3881267ab 100644 --- a/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/src/main/java/com/sk89q/worldedit/EditSession.java @@ -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) { diff --git a/src/main/java/com/sk89q/worldedit/WorldEdit.java b/src/main/java/com/sk89q/worldedit/WorldEdit.java index 839325820..7055c1e9a 100644 --- a/src/main/java/com/sk89q/worldedit/WorldEdit.java +++ b/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -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.*; diff --git a/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java b/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java index 01cc2d8c3..579b14e17 100644 --- a/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java +++ b/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java @@ -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. *
* 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 before the extent fetched from + * {@link #getExtent()} would. + *+ * event.setExtent(new MyExtent(event.getExtent()) + *+ * 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, but 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); + } + } diff --git a/src/main/java/com/sk89q/worldedit/internal/InternalEditSessionFactory.java b/src/main/java/com/sk89q/worldedit/internal/InternalEditSessionFactory.java index 6b4b7682b..308767389 100644 --- a/src/main/java/com/sk89q/worldedit/internal/InternalEditSessionFactory.java +++ b/src/main/java/com/sk89q/worldedit/internal/InternalEditSessionFactory.java @@ -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)); } } \ No newline at end of file