diff --git a/src/main/java/com/sk89q/worldedit/EditSession.java b/src/main/java/com/sk89q/worldedit/EditSession.java index ff56140b4..37382775d 100644 --- a/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/src/main/java/com/sk89q/worldedit/EditSession.java @@ -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}. - *

- * 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. - *

- * 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. - *

- * 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. - *

- * 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. * diff --git a/src/main/java/com/sk89q/worldedit/EditSessionFactory.java b/src/main/java/com/sk89q/worldedit/EditSessionFactory.java index 90beb7caa..07b946de5 100644 --- a/src/main/java/com/sk89q/worldedit/EditSessionFactory.java +++ b/src/main/java/com/sk89q/worldedit/EditSessionFactory.java @@ -1,51 +1,89 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * 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 . + */ + 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)); } } diff --git a/src/main/java/com/sk89q/worldedit/WorldEdit.java b/src/main/java/com/sk89q/worldedit/WorldEdit.java index 8da24d03c..c00a76613 100644 --- a/src/main/java/com/sk89q/worldedit/WorldEdit.java +++ b/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -1,7 +1,7 @@ -// $Id$ /* - * WorldEdit - * Copyright (C) 2010 sk89q and contributors + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * 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 . -*/ + */ 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 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 sessions = new HashMap(); - /** - * 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."); } /** diff --git a/src/main/java/com/sk89q/worldedit/event/Event.java b/src/main/java/com/sk89q/worldedit/event/Event.java new file mode 100644 index 000000000..0691391e2 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/event/Event.java @@ -0,0 +1,28 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * 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 . + */ + +package com.sk89q.worldedit.event; + +import com.sk89q.worldedit.util.eventbus.EventBus; + +/** + * An abstract base class for all WorldEdit events. + */ +public abstract class Event { +} diff --git a/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java b/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java new file mode 100644 index 000000000..01cc2d8c3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java @@ -0,0 +1,106 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * 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 . + */ + +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. + *

+ * 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; + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/AbstractLoggingExtent.java b/src/main/java/com/sk89q/worldedit/extent/AbstractLoggingExtent.java index b8b0dc398..4baa97e3e 100644 --- a/src/main/java/com/sk89q/worldedit/extent/AbstractLoggingExtent.java +++ b/src/main/java/com/sk89q/worldedit/extent/AbstractLoggingExtent.java @@ -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); }