From 7d468357e32ec69d9478e8bfd8f2fe8d5a1893ba Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Mon, 15 Oct 2018 20:50:09 +1000 Subject: [PATCH] Added "fast mode corrections" --- .../sk89q/worldedit/bukkit/BukkitWorld.java | 11 ++++++ .../bukkit/adapter/BukkitImplAdapter.java | 10 ++++++ .../java/com/sk89q/worldedit/EditSession.java | 20 ++++++++--- .../extent/world/FastModeExtent.java | 36 ++++++++++++++++++- .../history/changeset/ChangeSet.java | 1 + .../com/sk89q/worldedit/world/NullWorld.java | 5 +++ .../java/com/sk89q/worldedit/world/World.java | 13 +++++++ .../com/sk89q/worldedit/forge/ForgeWorld.java | 6 ++++ .../sk89q/worldedit/sponge/SpongeWorld.java | 7 +++- 9 files changed, 103 insertions(+), 6 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index afc6c36de..8bffc3a2e 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -448,6 +448,17 @@ public class BukkitWorld extends AbstractWorld { } } + @Override + public boolean notifyAndLightBlock(BlockVector3 position, com.sk89q.worldedit.world.block.BlockState previousType) throws WorldEditException { + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + if (adapter != null) { + adapter.notifyAndLightBlock(BukkitAdapter.adapt(getWorld(), position), previousType); + return true; + } + + return false; + } + @Override public BaseBiome getBiome(BlockVector2 position) { BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java index 393877581..13631e1d9 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java @@ -24,6 +24,7 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import org.bukkit.Location; @@ -78,6 +79,15 @@ public interface BukkitImplAdapter { */ boolean setBlock(Location location, BlockStateHolder state, boolean notifyAndLight); + /** + * Notifies the simulation that the block at the given location has + * been changed and it must be re-lighted (and issue other events). + * + * @param position position of the block + * @param previousType the type of the previous block that was there + */ + void notifyAndLightBlock(Location position, BlockState previousType); + /** * Get the state for the given entity. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index fabf49f3f..fad8c8850 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -170,6 +170,8 @@ public class EditSession implements Extent, AutoCloseable { private final Extent bypassHistory; private final Extent bypassNone; + private final boolean useFastModeCorrections; + private Mask oldMask; /** @@ -187,12 +189,13 @@ public class EditSession implements Extent, AutoCloseable { checkNotNull(event); this.world = world; + this.useFastModeCorrections = false; if (world != null) { Extent extent; // These extents are ALWAYS used - extent = fastModeExtent = new FastModeExtent(world, false); + extent = fastModeExtent = new FastModeExtent(world, useFastModeCorrections); extent = survivalExtent = new SurvivalModeExtent(extent, world); extent = quirkExtent = new BlockQuirkExtent(extent, world); extent = chunkLoadingExtent = new ChunkLoadingExtent(extent, world); @@ -299,14 +302,16 @@ public class EditSession implements Extent, AutoCloseable { * @return whether the queue is enabled */ public boolean isQueueEnabled() { - return reorderExtent.isEnabled(); + return !useFastModeCorrections && reorderExtent.isEnabled(); } /** * Queue certain types of block for better reproduction of those blocks. */ public void enableQueue() { - reorderExtent.setEnabled(true); + if (!useFastModeCorrections) { + reorderExtent.setEnabled(true); + } } /** @@ -361,7 +366,14 @@ public class EditSession implements Extent, AutoCloseable { */ public void setFastMode(boolean enabled) { if (fastModeExtent != null) { - fastModeExtent.setEnabled(enabled); + // If fast mode corrections are enabled, we're using fast mode for + // multipass support. Thus, we do not actually ever turn the fast mode + // extent off, we instead toggle post edit simulation + if (useFastModeCorrections) { + fastModeExtent.setPostEditSimulationEnabled(!enabled); + } else { + fastModeExtent.setEnabled(enabled); + } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/FastModeExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/FastModeExtent.java index b75156d3b..37f524ad0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/FastModeExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/FastModeExtent.java @@ -29,9 +29,12 @@ import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; +import java.util.ArrayDeque; import java.util.HashSet; import java.util.List; +import java.util.Queue; import java.util.Set; /** @@ -40,8 +43,10 @@ import java.util.Set; public class FastModeExtent extends AbstractDelegateExtent { private final World world; + private final Queue positions = new ArrayDeque<>(); private final Set dirtyChunks = new HashSet<>(); private boolean enabled = true; + private boolean postEditSimulation; /** * Create a new instance with fast mode enabled. @@ -63,6 +68,9 @@ public class FastModeExtent extends AbstractDelegateExtent { checkNotNull(world); this.world = world; this.enabled = enabled; + if (enabled) { + this.postEditSimulation = true; + } } /** @@ -83,11 +91,27 @@ public class FastModeExtent extends AbstractDelegateExtent { this.enabled = enabled; } + public boolean isPostEditSimulationEnabled() { + return postEditSimulation; + } + + public void setPostEditSimulationEnabled(boolean enabled) { + this.postEditSimulation = enabled; + } + @Override public boolean setBlock(BlockVector3 location, BlockStateHolder block) throws WorldEditException { if (enabled) { dirtyChunks.add(BlockVector2.at(location.getBlockX() >> 4, location.getBlockZ() >> 4)); - return world.setBlock(location, block, false); + + if (world.setBlock(location, block, false)) { + if (postEditSimulation) { + positions.offer(location); + } + return true; + } + + return false; } else { return world.setBlock(location, block, true); } @@ -101,6 +125,16 @@ public class FastModeExtent extends AbstractDelegateExtent { if (!dirtyChunks.isEmpty()) { world.fixAfterFastMode(dirtyChunks); } + + if (postEditSimulation) { + while (run.shouldContinue() && !positions.isEmpty()) { + BlockVector3 position = positions.poll(); // Remove from queue + world.notifyAndLightBlock(position, BlockTypes.AIR.getDefaultState()); + } + + return !positions.isEmpty() ? this : null; + } + return null; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java b/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java index fc5adb2e7..003a007b6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java @@ -42,6 +42,7 @@ public interface ChangeSet { * @return whether or not the ChangeSet is set to record changes */ boolean isRecordingChanges(); + /** * Tell the change set whether to record changes or not. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java index 43ee77e39..eec1d47a9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java @@ -64,6 +64,11 @@ public class NullWorld extends AbstractWorld { return false; } + @Override + public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException { + return false; + } + @Override public int getBlockLightLevel(BlockVector3 position) { return 0; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java index 3e7bbf88c..d47723a42 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java @@ -33,10 +33,13 @@ import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.TreeGenerator; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.weather.WeatherType; +import java.util.Vector; + /** * Represents a world (dimension). */ @@ -95,6 +98,16 @@ public interface World extends Extent { */ boolean setBlock(BlockVector3 position, BlockStateHolder block, boolean notifyAndLight) throws WorldEditException; + /** + * Notifies the simulation that the block at the given location has + * been changed and it must be re-lighted (and issue other events). + * + * @param position position of the block + * @param previousType the type of the previous block that was there + * @return true if the block was successfully notified + */ + boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException; + /** * Get the light level at the given block. * diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index 23ea709ff..d3d84d48a 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -212,6 +212,12 @@ public class ForgeWorld extends AbstractWorld { return successful; } + @Override + public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException { + // TODO Implement + return false; + } + // Can't get the "Object" to be right for withProperty w/o this @SuppressWarnings({ "rawtypes", "unchecked" }) private IBlockState applyProperties(BlockStateContainer stateContainer, IBlockState newState, Map, Object> states) { diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java index 74c2a6a3c..e3401190e 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java @@ -41,7 +41,6 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.weather.WeatherType; import com.sk89q.worldedit.world.weather.WeatherTypes; - import org.spongepowered.api.Sponge; import org.spongepowered.api.block.BlockSnapshot; import org.spongepowered.api.block.BlockState; @@ -163,6 +162,12 @@ public abstract class SpongeWorld extends AbstractWorld { return true; } + @Override + public boolean notifyAndLightBlock(BlockVector3 position, com.sk89q.worldedit.world.block.BlockState previousType) throws WorldEditException { + // TODO Move this to adapter + return false; + } + @Override public boolean regenerate(Region region, EditSession editSession) { return false;