From 2e904577b7939560c30d5db3cc53e0ff36da8116 Mon Sep 17 00:00:00 2001
From: sk89q
Date: Thu, 3 Apr 2014 18:24:06 -0700
Subject: [PATCH] Added events for each stage of EditSession Extent creation.
---
.../java/com/sk89q/worldedit/EditSession.java | 71 ++++++++++---------
.../java/com/sk89q/worldedit/WorldEdit.java | 2 +
.../event/extent/EditSessionEvent.java | 52 ++++++++++++--
.../internal/InternalEditSessionFactory.java | 8 +--
4 files changed, 90 insertions(+), 43 deletions(-)
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