Removed EditSessionFactory in favor of event-based system.

This commit is contained in:
sk89q 2014-04-02 18:57:25 -07:00
parent a7d83958ac
commit 6e70e8c862
6 changed files with 277 additions and 222 deletions

View File

@ -23,6 +23,7 @@ import com.sk89q.worldedit.bags.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.expression.Expression;
import com.sk89q.worldedit.expression.ExpressionException;
import com.sk89q.worldedit.expression.runtime.RValue;
@ -59,6 +60,7 @@ import com.sk89q.worldedit.shape.RegionShape;
import com.sk89q.worldedit.shape.WorldEditExpressionEnvironment;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.util.collection.DoubleArrayList;
import com.sk89q.worldedit.util.eventbus.EventBus;
import javax.annotation.Nullable;
import java.util.*;
@ -74,11 +76,8 @@ import static com.sk89q.worldedit.regions.Regions.*;
* Most of the actual functionality is implemented with a number of other
* {@link Extent}s that are chained together. For example, history is logged
* using the {@link ChangeSetExtent}.
* </p>
* Subclasses can override {@link #wrapBeforeHistory(Extent)},
* {@link #wrapBeforeReorder(Extent)} and {@link #wrapBeforeSet(Extent)} to
* inject custom {@link Extent}s.
*/
@SuppressWarnings("FieldCanBeLocal")
public class EditSession implements Extent {
/**
@ -96,8 +95,13 @@ public class EditSession implements Extent {
private final ChangeSet changeSet = new BlockOptimizedHistory();
private final FastModeExtent fastModeExtent;
private final ChunkLoadingExtent chunkLoadingExtent;
private final LastAccessExtentCache cacheExtent;
private final BlockQuirkExtent quirkExtent;
private final DataValidatorExtent validator;
private final BlockBagExtent blockBagExtent;
private final MultiStageReorder reorderExtent;
private final ChangeSetExtent changeSetExtent;
private final MaskingExtent maskingExtent;
private final BlockChangeLimiter changeLimiter;
@ -108,93 +112,51 @@ public class EditSession implements Extent {
@SuppressWarnings("deprecation")
private Mask oldMask;
/**
* Construct the object with a maximum number of blocks.
*
* @param world the world
* @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit
*/
public EditSession(LocalWorld world, int maxBlocks) {
this(world, maxBlocks, null);
}
/**
* Construct the object with a maximum number of blocks and a block bag.
*
* @param eventBus the event bus
* @param world the world
* @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit
* @param blockBag an optional {@link BlockBag} to use, otherwise null
* @param event the event to call with the extent
*/
public EditSession(LocalWorld world, int maxBlocks, @Nullable BlockBag blockBag) {
public EditSession(EventBus eventBus, LocalWorld world, int maxBlocks, @Nullable BlockBag blockBag, EditSessionEvent event) {
checkNotNull(eventBus);
checkNotNull(world);
checkArgument(maxBlocks >= -1, "maxBlocks >= -1 required");
checkNotNull(event);
this.world = world;
Extent wrappedExtent;
// 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();
// This extents are ALWAYS used
fastModeExtent = new FastModeExtent(world, false);
ChunkLoadingExtent chunkLoadingExtent = new ChunkLoadingExtent(fastModeExtent, world);
LastAccessExtentCache cacheExtent = new LastAccessExtentCache(chunkLoadingExtent);
wrappedExtent = checkNotNull(wrapBeforeSet(cacheExtent), "wrapBeforeSet() returned null");
BlockQuirkExtent quirkExtent = new BlockQuirkExtent(wrappedExtent, world);
DataValidatorExtent validator = new DataValidatorExtent(quirkExtent, world);
blockBagExtent = new BlockBagExtent(validator, world, blockBag);
quirkExtent = new BlockQuirkExtent(wrappedExtent, world);
validator = new DataValidatorExtent(quirkExtent, world);
blockBagExtent = new BlockBagExtent(validator, world, blockBag);
// This extent can be skipped by calling rawSetBlock()
reorderExtent = new MultiStageReorder(blockBagExtent, false);
wrappedExtent = checkNotNull(wrapBeforeReorder(reorderExtent), "wrapBeforeReorder() returned null");
reorderExtent = new MultiStageReorder(blockBagExtent, false);
// These extents can be skipped by calling smartSetBlock()
ChangeSetExtent changeSetExtent = new ChangeSetExtent(wrappedExtent, changeSet);
wrappedExtent = checkNotNull(wrapBeforeHistory(changeSetExtent), "wrapBeforeHistory() returned null");
maskingExtent = new MaskingExtent(wrappedExtent, Masks.alwaysTrue());
changeLimiter = new BlockChangeLimiter(maskingExtent, maxBlocks);
changeSetExtent = new ChangeSetExtent(reorderExtent, changeSet);
maskingExtent = new MaskingExtent(changeSetExtent, Masks.alwaysTrue());
changeLimiter = new BlockChangeLimiter(maskingExtent, maxBlocks);
this.bypassReorderHistory = blockBagExtent;
this.bypassHistory = reorderExtent;
this.bypassNone = changeLimiter;
}
/**
* Wrap the given extent at an early point.
* </p>
* Extents added here are called after most of the other extents have been
* called, meaning that it will receive the final changes.
*
* @param extent the extent that needs to be wrapped
* @return the replacement extent
*/
protected Extent wrapBeforeSet(Extent extent) {
return extent;
}
/**
* Wrap the given extent at a point before reordering is done.
* </p>
* Extents added here are called before changes are re-ordered.
*
* @param extent the extent that needs to be wrapped
* @return the replacement extent
*/
protected Extent wrapBeforeReorder(Extent extent) {
return extent;
}
/**
* Wrap the given extent at a point before history is logged.
* </p>
* Extents added here are called before the changes are stored
* in history.
*
* @param extent the extent that needs to be wrapped
* @return the replacement extent
*/
protected Extent wrapBeforeHistory(Extent extent) {
return extent;
}
/**
* Get the world.
*

View File

@ -1,51 +1,89 @@
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit;
import com.sk89q.worldedit.bags.BlockBag;
import com.sk89q.worldedit.event.extent.EditSessionEvent;
import com.sk89q.worldedit.util.eventbus.EventBus;
public class EditSessionFactory {
import static com.google.common.base.Preconditions.checkNotNull;
/**
* A factory for {@link EditSession}s.
*/
public final class EditSessionFactory {
private final EventBus eventBus;
/**
* Create a new factory.
*
* @param eventBus the event bus
*/
public EditSessionFactory(EventBus eventBus) {
checkNotNull(eventBus);
this.eventBus = eventBus;
}
/**
* Construct an edit session with a maximum number of blocks.
*
* @param world
* @param maxBlocks
* @param world the world
* @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit
*/
public EditSession getEditSession(LocalWorld world, int maxBlocks) {
return new EditSession(world, maxBlocks);
return new EditSession(eventBus, world, maxBlocks, null, new EditSessionEvent(world, null, maxBlocks));
}
/**
* Construct an edit session with a maximum number of blocks.
*
* @param world
* @param maxBlocks
* @param player
* @param world the world
* @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit
* @param player the player that the {@link EditSession} is for
*/
public EditSession getEditSession(LocalWorld world, int maxBlocks, LocalPlayer player) {
return this.getEditSession(world, maxBlocks);
return new EditSession(eventBus, world, maxBlocks, null, new EditSessionEvent(world, player, maxBlocks));
}
/**
* Construct an edit session with a maximum number of blocks and a block bag.
*
* @param world
* @param maxBlocks
* @param blockBag
* @param world the world
* @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit
* @param blockBag an optional {@link BlockBag} to use, otherwise null
*/
public EditSession getEditSession(LocalWorld world, int maxBlocks, BlockBag blockBag) {
return new EditSession(world, maxBlocks, blockBag);
return new EditSession(eventBus, world, maxBlocks, blockBag, new EditSessionEvent(world, null, maxBlocks));
}
/**
* Construct an edit session with a maximum number of blocks and a block bag.
*
* @param world
* @param maxBlocks
* @param blockBag
* @param player
* @param world the world
* @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit
* @param blockBag an optional {@link BlockBag} to use, otherwise null
* @param player the player that the {@link EditSession} is for
*/
public EditSession getEditSession(LocalWorld world, int maxBlocks, BlockBag blockBag, LocalPlayer player) {
return this.getEditSession(world, maxBlocks, blockBag);
return new EditSession(eventBus, world, maxBlocks, blockBag, new EditSessionEvent(world, player, maxBlocks));
}
}

View File

@ -1,7 +1,7 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010 sk89q <http://www.sk89q.com> and contributors
* 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 General Public License as published by
@ -15,155 +15,62 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package com.sk89q.worldedit;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import com.sk89q.minecraft.util.commands.*;
import com.sk89q.minecraft.util.commands.Console;
import com.sk89q.util.StringUtil;
import com.sk89q.worldedit.CuboidClipboard.FlipDirection;
import com.sk89q.worldedit.bags.BlockBag;
import com.sk89q.worldedit.blocks.*;
import com.sk89q.worldedit.commands.*;
import com.sk89q.worldedit.event.extent.EditSessionEvent;
import com.sk89q.worldedit.masks.*;
import com.sk89q.worldedit.patterns.*;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.scripting.CraftScriptContext;
import com.sk89q.worldedit.scripting.CraftScriptEngine;
import com.sk89q.worldedit.scripting.RhinoCraftScriptEngine;
import com.sk89q.worldedit.tools.*;
import com.sk89q.worldedit.util.eventbus.EventBus;
import javax.script.ScriptException;
import java.io.*;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import javax.script.ScriptException;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissionsException;
import com.sk89q.minecraft.util.commands.CommandUsageException;
import com.sk89q.minecraft.util.commands.CommandsManager;
import com.sk89q.minecraft.util.commands.Console;
import com.sk89q.minecraft.util.commands.Logging;
import com.sk89q.minecraft.util.commands.MissingNestedCommandException;
import com.sk89q.minecraft.util.commands.SimpleInjector;
import com.sk89q.minecraft.util.commands.UnhandledCommandException;
import com.sk89q.minecraft.util.commands.WrappedCommandException;
import com.sk89q.util.StringUtil;
import com.sk89q.worldedit.CuboidClipboard.FlipDirection;
import com.sk89q.worldedit.bags.BlockBag;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BlockType;
import com.sk89q.worldedit.blocks.ClothColor;
import com.sk89q.worldedit.blocks.ItemType;
import com.sk89q.worldedit.blocks.MobSpawnerBlock;
import com.sk89q.worldedit.blocks.NoteBlock;
import com.sk89q.worldedit.blocks.SignBlock;
import com.sk89q.worldedit.blocks.SkullBlock;
import com.sk89q.worldedit.commands.BiomeCommands;
import com.sk89q.worldedit.commands.ChunkCommands;
import com.sk89q.worldedit.commands.ClipboardCommands;
import com.sk89q.worldedit.commands.GeneralCommands;
import com.sk89q.worldedit.commands.GenerationCommands;
import com.sk89q.worldedit.commands.HistoryCommands;
import com.sk89q.worldedit.commands.InsufficientArgumentsException;
import com.sk89q.worldedit.commands.NavigationCommands;
import com.sk89q.worldedit.commands.RegionCommands;
import com.sk89q.worldedit.commands.ScriptingCommands;
import com.sk89q.worldedit.commands.SelectionCommands;
import com.sk89q.worldedit.commands.SnapshotUtilCommands;
import com.sk89q.worldedit.commands.ToolCommands;
import com.sk89q.worldedit.commands.ToolUtilCommands;
import com.sk89q.worldedit.commands.UtilityCommands;
import com.sk89q.worldedit.masks.BiomeTypeMask;
import com.sk89q.worldedit.masks.BlockMask;
import com.sk89q.worldedit.masks.CombinedMask;
import com.sk89q.worldedit.masks.DynamicRegionMask;
import com.sk89q.worldedit.masks.ExistingBlockMask;
import com.sk89q.worldedit.masks.InvertedMask;
import com.sk89q.worldedit.masks.Mask;
import com.sk89q.worldedit.masks.RandomMask;
import com.sk89q.worldedit.masks.RegionMask;
import com.sk89q.worldedit.masks.SolidBlockMask;
import com.sk89q.worldedit.masks.UnderOverlayMask;
import com.sk89q.worldedit.patterns.BlockChance;
import com.sk89q.worldedit.patterns.ClipboardPattern;
import com.sk89q.worldedit.patterns.Pattern;
import com.sk89q.worldedit.patterns.RandomFillPattern;
import com.sk89q.worldedit.patterns.SingleBlockPattern;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.scripting.CraftScriptContext;
import com.sk89q.worldedit.scripting.CraftScriptEngine;
import com.sk89q.worldedit.scripting.RhinoCraftScriptEngine;
import com.sk89q.worldedit.tools.BlockTool;
import com.sk89q.worldedit.tools.DoubleActionBlockTool;
import com.sk89q.worldedit.tools.DoubleActionTraceTool;
import com.sk89q.worldedit.tools.Tool;
import com.sk89q.worldedit.tools.TraceTool;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* This class is the main entry point for WorldEdit. All events are routed
* to an instance of this controller for processing by WorldEdit. For
* integrating WorldEdit in other platforms, an instance of this class
* should be created and events should be redirected to it.
*
* @author sk89q
* The current instance of WorldEdit.
*/
public class WorldEdit {
/**
* Logger for debugging.
*/
public static final Logger logger = Logger.getLogger("Minecraft.WorldEdit");
public final Logger commandLogger = Logger.getLogger("Minecraft.WorldEdit.CommandLogger");
/**
* Holds the current instance of this class, for static access
*/
private static WorldEdit instance;
/**
* Holds WorldEdit's version.
*/
private static String version;
/**
* Interface to the server.
*/
private final ServerInterface server;
/**
* Configuration. This is a subclass.
*/
private final LocalConfiguration config;
/**
* List of commands.
*/
private final CommandsManager<LocalPlayer> commands;
/**
* Holds the factory responsible for the creation of edit sessions
*/
private EditSessionFactory editSessionFactory = new EditSessionFactory();
/**
* Stores a list of WorldEdit sessions, keyed by players' names. Sessions
* persist only for the user's session. On disconnect, the session will be
* removed. Sessions are created only when they are needed and those
* without any WorldEdit abilities or never use WorldEdit in a session will
* not have a session object generated for them.
*/
private final EventBus eventBus = new EventBus();
private final EditSessionFactory editSessionFactory = new EditSessionFactory(eventBus);
private final HashMap<String, LocalSession> sessions = new HashMap<String, LocalSession>();
/**
* Initialize statically.
*/
static {
getVersion();
}
/**
* Construct an instance of the plugin
* Construct an instance of WorldEdit.
*
* @param server
* @param config
@ -290,6 +197,15 @@ public class WorldEdit {
return instance;
}
/**
* Get the event bus for WorldEdit.
*
* @return the event bus
*/
public EventBus getEventBus() {
return eventBus;
}
/**
* Gets the LocalSession for a player name if it exists
*
@ -1679,25 +1595,24 @@ public class WorldEdit {
}
/**
* Get the edit session factory
*
* @return
* Get a factory for {@link EditSession}s.
*/
public EditSessionFactory getEditSessionFactory() {
return this.editSessionFactory;
return editSessionFactory;
}
/**
* Set the edit session factory
*
* @param factory
* @deprecated EditSessionFactories are no longer used. Please register an {@link EditSessionEvent} event
* with the event bus in order to override or catch changes to the world
*/
@Deprecated
public void setEditSessionFactory(EditSessionFactory factory) {
if (factory == null) {
throw new IllegalArgumentException("New EditSessionFactory may not be null");
}
logger.info("Accepted EditSessionFactory of type " + factory.getClass().getName() + " from " + factory.getClass().getPackage().getName());
this.editSessionFactory = factory;
checkNotNull(factory);
logger.severe("Got request to set EditSessionFactory of type " +
factory.getClass().getName() + " from " + factory.getClass().getPackage().getName() +
" but EditSessionFactories have been removed in favor of extending EditSession's extents.\n\n" +
"This may mean that any block logger / intercepters addons/plugins/mods that you have installed will not " +
"intercept WorldEdit's changes! Please notify the maintainer of the other addon about this.");
}
/**

View File

@ -0,0 +1,28 @@
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.event;
import com.sk89q.worldedit.util.eventbus.EventBus;
/**
* An abstract base class for all WorldEdit events.
*/
public abstract class Event {
}

View File

@ -0,0 +1,106 @@
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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.event.Event;
import com.sk89q.worldedit.extent.Extent;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Raised 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.
*/
public class EditSessionEvent extends Event {
private final LocalWorld world;
private final LocalPlayer player;
private final int maxBlocks;
private Extent extent;
/**
* Create a new event.
*
* @param player the player, or null if not available
* @param world the world
* @param maxBlocks the maximum number of block changes
*/
public EditSessionEvent(LocalWorld world, LocalPlayer player, int maxBlocks) {
checkNotNull(world);
this.world = world;
this.player = player;
this.maxBlocks = maxBlocks;
}
/**
* Get the player for this event.
*
* @return the player, which may be null if unavailable
*/
public @Nullable LocalPlayer getPlayer() {
return player;
}
/**
* Get the world.
*
* @return the world
*/
public LocalWorld getWorld() {
return world;
}
/**
* Get the maximum number of blocks that may be set.
*
* @return the maximum number of blocks, which is -1 if unlimited
*/
public int getMaxBlocks() {
return maxBlocks;
}
/**
* Get the {@link Extent} that can be wrapped.
*
* @return the extent
*/
public Extent getExtent() {
return extent;
}
/**
* Set a new extent that should be used. It should wrap the extent
* returned from {@link #getExtent()}.
*
* @param extent the extent
*/
public void setExtent(Extent extent) {
checkNotNull(extent);
this.extent = extent;
}
}

View File

@ -33,16 +33,22 @@ public abstract class AbstractLoggingExtent extends ExtentDelegate {
*
* @param extent the extent
*/
public AbstractLoggingExtent(Extent extent) {
protected AbstractLoggingExtent(Extent extent) {
super(extent);
}
protected void onBlockSet(Vector position, BaseBlock newBlock) {
/**
* Called when a block is being changed.
*
* @param position the position
* @param newBlock the new block to replace the old one
*/
protected void onBlockChange(Vector position, BaseBlock newBlock) {
}
@Override
public final boolean setBlock(Vector position, BaseBlock block) throws WorldEditException {
onBlockSet(position, block);
onBlockChange(position, block);
return super.setBlock(position, block);
}