From 9c74d0b98115fe5cccdf6cd416796ec6857fa0f1 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Sun, 26 Feb 2017 16:39:00 +1100 Subject: [PATCH] Various (unfinished) Fixes #439 Update to Java 8 Adds scrollable brushes to the API (action on brush scroll) - Clipboard - Mask - Pattern - Range - Size Adds movable brushes to the API (action on brush move) Adds different targeting modes for brushes (see enum TargetMode) Adds VisualBrush to API (sends client block changes instead of changing the world) Updater now checks every 30m for updates Adds in game updater changelog (/fawe changelog) Adds language option to config Adds german translations Adds CircleBrush (WIP) Simplify DoubleActionBrush and DoubleActionBrushTool to extend Brush/BrushTool Use ImmutableBlock instead of anonymous BaseBlock for cache Fixes CuboidRegion iteration (affected some commands) Fixes WorldCopyClipboard schematic saving Optimize FawePlayer -> Player by caching value Simplified pattern and mask API by extending legacy versions Optimize sphere, cylinder and deform Added brush cancellation by SHIFT + LEFT CLICK Probably some other stuff --- build.gradle | 4 +- .../com/boydti/fawe/bukkit/BrushListener.java | 135 ++++++ .../com/boydti/fawe/bukkit/BukkitMain.java | 10 + .../com/boydti/fawe/bukkit/BukkitPlayer.java | 2 +- .../com/boydti/fawe/bukkit/FaweBukkit.java | 1 + .../boydti/fawe/bukkit/v0/BukkitQueue_0.java | 58 ++- .../bukkit/v1_10/BukkitChunk_1_10_Copy.java | 80 ++++ .../fawe/bukkit/v1_10/BukkitQueue_1_10.java | 169 ++++--- .../compression/CompressionOptimizer.java | 118 +++++ core/build.gradle | 3 - core/src/main/java/com/boydti/fawe/Fawe.java | 38 +- .../main/java/com/boydti/fawe/FaweCache.java | 36 +- .../java/com/boydti/fawe/command/Reload.java | 22 +- .../main/java/com/boydti/fawe/config/BBC.java | 1 + .../java/com/boydti/fawe/config/Settings.java | 7 +- .../fawe/example/NullQueueCharFaweChunk.java | 34 ++ .../com/boydti/fawe/jnbt/anvil/MCAQueue.java | 4 +- .../com/boydti/fawe/object/FaweChunk.java | 15 + .../com/boydti/fawe/object/FawePlayer.java | 19 +- .../com/boydti/fawe/object/FaweQueue.java | 3 +- .../boydti/fawe/object/brush/CircleBrush.java | 48 ++ .../fawe/object/brush/CopyPastaBrush.java | 7 +- .../fawe/object/brush/DoubleActionBrush.java | 12 +- .../object/brush/DoubleActionBrushTool.java | 239 ---------- .../boydti/fawe/object/brush/ErodeBrush.java | 3 +- .../fawe/object/brush/FlattenBrush.java | 7 +- .../boydti/fawe/object/brush/HeightBrush.java | 13 +- .../boydti/fawe/object/brush/LineBrush.java | 3 +- .../fawe/object/brush/MovableBrush.java | 7 + .../boydti/fawe/object/brush/RaiseBrush.java | 3 +- .../boydti/fawe/object/brush/SplineBrush.java | 42 +- .../boydti/fawe/object/brush/TargetMode.java | 8 + .../object/brush/scroll/ScrollAction.java | 11 + .../object/brush/scroll/ScrollClipboard.java | 4 + .../fawe/object/brush/scroll/ScrollMask.java | 25 ++ .../object/brush/scroll/ScrollPattern.java | 25 ++ .../fawe/object/brush/scroll/ScrollRange.java | 19 + .../fawe/object/brush/scroll/ScrollSize.java | 18 + .../object/brush/scroll/ScrollableBrush.java | 5 + .../visualization/DelegateVisualBrush.java | 32 ++ .../brush/visualization/VisualBrush.java | 142 ++++++ .../brush/visualization/VisualChunk.java | 171 +++++++ .../brush/visualization/VisualExtent.java | 110 +++++ .../brush/visualization/VisualMode.java | 7 + .../brush/visualization/VisualQueue.java | 66 +++ .../object/changeset/DiskStorageHistory.java | 15 +- .../fawe/object/changeset/FaweChangeSet.java | 5 + .../object/clipboard/WorldCopyClipboard.java | 43 +- .../com/boydti/fawe/object/io/PGZIPBlock.java | 43 ++ .../fawe/object/io/PGZIPOutputStream.java | 55 +-- .../com/boydti/fawe/object/io/PGZIPState.java | 19 + .../fawe/object/io/PGZIPThreadLocal.java | 15 + .../fawe/object/visitor/FaweChunkVisitor.java | 12 + .../boydti/fawe/util/DelegateFaweQueue.java | 5 +- .../java/com/boydti/fawe/util/MainUtil.java | 24 + .../java/com/boydti/fawe/util/MathMan.java | 30 ++ .../java/com/boydti/fawe/util/Updater.java | 16 +- .../com/boydti/fawe/wrappers/FakePlayer.java | 2 +- .../java/com/sk89q/worldedit/BlockVector.java | 4 + .../com/sk89q/worldedit/CuboidClipboard.java | 4 +- .../java/com/sk89q/worldedit/EditSession.java | 156 ++++++- .../com/sk89q/worldedit/LocalSession.java | 57 ++- .../sk89q/worldedit/MutableBlockVector.java | 11 + .../com/sk89q/worldedit/blocks/BaseBlock.java | 421 ++++++++++++++++++ .../worldedit/blocks/ImmutableBlock.java | 36 ++ .../blocks/ImmutableDatalessBlock.java | 26 ++ .../worldedit/command/BrushCommands.java | 90 ++-- .../sk89q/worldedit/command/ToolCommands.java | 20 +- .../worldedit/command/ToolUtilCommands.java | 27 +- .../worldedit/command/tool/BrushTool.java | 67 ++- .../extension/platform/PlatformManager.java | 20 +- .../transform/BlockTransformExtent.java | 2 +- .../sk89q/worldedit/function/mask/Mask.java | 59 +++ .../pattern}/Pattern.java | 43 +- .../worldedit/function/pattern/Patterns.java | 3 + .../function/visitor/BreadthFirstSearch.java | 18 +- .../function/visitor/RegionVisitor.java | 1 + .../sk89q/worldedit/regions/CuboidRegion.java | 23 +- core/src/main/resources/de/messages.yml | 311 +++++++++++++ forge110/build.gradle | 3 - .../com/boydti/fawe/forge/ForgePlayer.java | 2 +- forge111/build.gradle | 3 - .../com/boydti/fawe/forge/ForgePlayer.java | 2 +- forge1710/build.gradle | 3 - .../com/boydti/fawe/forge/ForgePlayer.java | 2 +- forge189/build.gradle | 3 - .../com/boydti/fawe/forge/ForgePlayer.java | 2 +- forge194/build.gradle | 3 - .../com/boydti/fawe/forge/ForgePlayer.java | 4 +- .../fawe/nukkit/optimization/FaweNukkit.java | 2 + .../nukkit/optimization/FaweNukkitPlayer.java | 2 +- sponge/build.gradle | 3 - .../com/boydti/fawe/sponge/SpongePlayer.java | 2 +- 93 files changed, 2779 insertions(+), 726 deletions(-) create mode 100644 bukkit/src/main/java/com/boydti/fawe/bukkit/BrushListener.java create mode 100644 bukkit/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitChunk_1_10_Copy.java create mode 100644 bukkit/src/main/java/com/boydti/fawe/bukkit/v1_11/compression/CompressionOptimizer.java create mode 100644 core/src/main/java/com/boydti/fawe/example/NullQueueCharFaweChunk.java create mode 100644 core/src/main/java/com/boydti/fawe/object/brush/CircleBrush.java delete mode 100644 core/src/main/java/com/boydti/fawe/object/brush/DoubleActionBrushTool.java create mode 100644 core/src/main/java/com/boydti/fawe/object/brush/MovableBrush.java create mode 100644 core/src/main/java/com/boydti/fawe/object/brush/TargetMode.java create mode 100644 core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollAction.java create mode 100644 core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollClipboard.java create mode 100644 core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollMask.java create mode 100644 core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollPattern.java create mode 100644 core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollRange.java create mode 100644 core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollSize.java create mode 100644 core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollableBrush.java create mode 100644 core/src/main/java/com/boydti/fawe/object/brush/visualization/DelegateVisualBrush.java create mode 100644 core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualBrush.java create mode 100644 core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualChunk.java create mode 100644 core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualExtent.java create mode 100644 core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualMode.java create mode 100644 core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualQueue.java create mode 100644 core/src/main/java/com/boydti/fawe/object/io/PGZIPBlock.java create mode 100644 core/src/main/java/com/boydti/fawe/object/io/PGZIPState.java create mode 100644 core/src/main/java/com/boydti/fawe/object/io/PGZIPThreadLocal.java create mode 100644 core/src/main/java/com/boydti/fawe/object/visitor/FaweChunkVisitor.java create mode 100644 core/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java create mode 100644 core/src/main/java/com/sk89q/worldedit/blocks/ImmutableBlock.java create mode 100644 core/src/main/java/com/sk89q/worldedit/blocks/ImmutableDatalessBlock.java create mode 100644 core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java rename core/src/main/java/com/sk89q/worldedit/{patterns => function/pattern}/Pattern.java (50%) create mode 100644 core/src/main/resources/de/messages.yml diff --git a/build.gradle b/build.gradle index da307cec..1aa3af9e 100644 --- a/build.gradle +++ b/build.gradle @@ -74,8 +74,8 @@ subprojects { apply plugin: 'eclipse' apply plugin: 'idea' - sourceCompatibility = 1.7 - targetCompatibility = 1.7 + sourceCompatibility = 1.8 + targetCompatibility = 1.8 repositories { mavenCentral() diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/BrushListener.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/BrushListener.java new file mode 100644 index 00000000..29ff0ed7 --- /dev/null +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/BrushListener.java @@ -0,0 +1,135 @@ +package com.boydti.fawe.bukkit; + +import com.boydti.fawe.config.BBC; +import com.boydti.fawe.object.FawePlayer; +import com.boydti.fawe.object.brush.MovableBrush; +import com.boydti.fawe.object.brush.scroll.ScrollableBrush; +import com.boydti.fawe.object.brush.visualization.VisualBrush; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.tool.BrushTool; +import com.sk89q.worldedit.command.tool.InvalidToolBindException; +import com.sk89q.worldedit.command.tool.Tool; +import com.sk89q.worldedit.command.tool.brush.Brush; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerItemHeldEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.plugin.Plugin; + +public class BrushListener implements Listener { + public BrushListener(Plugin plugin) { + Bukkit.getPluginManager().registerEvents(this, plugin); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerItemHoldEvent(final PlayerItemHeldEvent event) { + final Player bukkitPlayer = event.getPlayer(); + if (bukkitPlayer.isSneaking()) { + return; + } + FawePlayer fp = FawePlayer.wrap(bukkitPlayer); + com.sk89q.worldedit.entity.Player player = fp.getPlayer(); + LocalSession session = fp.getSession(); + Tool tool = session.getTool(player); + if (tool != null) { + ScrollableBrush scrollable; + if (tool instanceof ScrollableBrush) { + scrollable = (ScrollableBrush) tool; + } else if (tool instanceof BrushTool) { + Brush brush = ((BrushTool) tool).getBrush(); + scrollable = brush instanceof ScrollableBrush ? (ScrollableBrush) brush : null; + } else { + return; + } + if (scrollable != null) { + final int slot = event.getNewSlot(); + final int oldSlot = event.getPreviousSlot(); + final int ri; + if ((((slot - oldSlot) <= 4) && ((slot - oldSlot) > 0)) || (((slot - oldSlot) < -4))) { + ri = 1; + } else { + ri = -1; + } + if (scrollable.increment(ri)) { + final PlayerInventory inv = bukkitPlayer.getInventory(); + final ItemStack item = inv.getItem(slot); + final ItemStack newItem = inv.getItem(oldSlot); + inv.setItem(slot, newItem); + inv.setItem(oldSlot, item); + bukkitPlayer.updateInventory(); + if (scrollable instanceof VisualBrush) { + try { + ((VisualBrush) scrollable).queueVisualization(fp); + } catch (Throwable e) { + WorldEdit.getInstance().getPlatformManager().handleThrowable(e, player); + } + } + } + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerMove(PlayerMoveEvent event) { + Location from = event.getFrom(); + Location to = event.getTo(); + if ((from.getYaw() != to.getYaw() && from.getPitch() != to.getPitch()) || from.getBlockX() != to.getBlockX() || from.getBlockZ() != to.getBlockZ() || from.getBlockY() != to.getBlockY()) { + Player bukkitPlayer = event.getPlayer(); + FawePlayer fp = FawePlayer.wrap(bukkitPlayer); + com.sk89q.worldedit.entity.Player player = fp.getPlayer(); + LocalSession session = fp.getSession(); + Tool tool = session.getTool(player); + if (tool != null) { + if (tool instanceof MovableBrush) { + ((MovableBrush) tool).move(player); + } else if (tool instanceof BrushTool) { + Brush brush = ((BrushTool) tool).getBrush(); + if (brush instanceof MovableBrush) { + if (((MovableBrush) brush).move(player)) { + if (brush instanceof VisualBrush) { + try { + ((VisualBrush) brush).queueVisualization(fp); + } catch (Throwable e) { + WorldEdit.getInstance().getPlatformManager().handleThrowable(e, player); + } + } + } + } + } + } + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerInteract(final PlayerInteractEvent event) { + switch (event.getAction()) { + case LEFT_CLICK_AIR: + case LEFT_CLICK_BLOCK: + Player bukkitPlayer = event.getPlayer(); + if (!bukkitPlayer.isSneaking()) { + return; + } + FawePlayer fp = FawePlayer.wrap(bukkitPlayer); + com.sk89q.worldedit.entity.Player player = fp.getPlayer(); + LocalSession session = fp.getSession(); + int item = player.getItemInHand(); + Tool tool = session.getTool(item); + if (tool != null) { + try { + session.setTool(item, null, player); + BBC.TOOL_NONE.send(player); + } catch (InvalidToolBindException e) { + e.printStackTrace(); + } + } + } + } +} diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitMain.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitMain.java index 5048e878..20ba3026 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitMain.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitMain.java @@ -5,6 +5,7 @@ import com.boydti.fawe.bukkit.v0.BukkitQueue_0; import com.boydti.fawe.bukkit.v0.BukkitQueue_All; import com.boydti.fawe.bukkit.v1_10.BukkitQueue_1_10; import com.boydti.fawe.bukkit.v1_11.BukkitQueue_1_11; +import com.boydti.fawe.bukkit.v1_11.compression.CompressionOptimizer; import com.boydti.fawe.bukkit.v1_7.BukkitQueue17; import com.boydti.fawe.bukkit.v1_8.BukkitQueue18R3; import com.boydti.fawe.bukkit.v1_9.BukkitQueue_1_9_R1; @@ -68,6 +69,15 @@ public class BukkitMain extends JavaPlugin { break; } catch (IllegalStateException e) {} } + switch (version) { + case v1_11_R1: + try { + CompressionOptimizer optimizer = new CompressionOptimizer(); +// optimizer.optimize(); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } } private enum Version { diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitPlayer.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitPlayer.java index c843035e..e83c4c2c 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitPlayer.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitPlayer.java @@ -92,7 +92,7 @@ public class BukkitPlayer extends FawePlayer { } @Override - public com.sk89q.worldedit.entity.Player getPlayer() { + public com.sk89q.worldedit.entity.Player toWorldEditPlayer() { return PlayerWrapper.wrap(Fawe. imp().getWorldEditPlugin().wrapPlayer(this.parent)); } diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java index d23c83f3..6fce129f 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java @@ -70,6 +70,7 @@ public class FaweBukkit implements IFawe, Listener { try { Fawe.set(this); setupInjector(); + new BrushListener(plugin); if (Bukkit.getVersion().contains("git-Spigot")) { debug("====== USE PAPER ======"); debug("DOWNLOAD: https://ci.destroystokyo.com/job/PaperSpigot/"); diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java index 6c4c6094..c978a14f 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java @@ -9,6 +9,7 @@ import com.boydti.fawe.example.NMSMappedFaweQueue; import com.boydti.fawe.object.FaweChunk; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.RunnableVal; +import com.boydti.fawe.object.visitor.FaweChunkVisitor; import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.TaskManager; import com.sk89q.worldedit.bukkit.WorldEditPlugin; @@ -142,9 +143,9 @@ public abstract class BukkitQueue_0 extends NMSMa if ((BukkitQueue_0.adapter = adapter) != null) { fieldAdapter.set(instance, adapter); } else { - BukkitQueue_0.adapter = (BukkitImplAdapter) fieldAdapter.get(instance); + BukkitQueue_0.adapter = adapter = (BukkitImplAdapter) fieldAdapter.get(instance); } - for (Method method : BukkitQueue_0.adapter.getClass().getDeclaredMethods()) { + for (Method method : adapter.getClass().getDeclaredMethods()) { switch (method.getName()) { case "toNative": methodToNative = method; @@ -237,28 +238,41 @@ public abstract class BukkitQueue_0 extends NMSMa } @Override - public void sendBlockUpdate(Map> blockMap, FawePlayer... players) { - for (FawePlayer player : players) { - Player bukkitPlayer = ((BukkitPlayer) player).parent; - World world = bukkitPlayer.getWorld(); - for (Map.Entry> entry : blockMap.entrySet()) { - long chunkHash = entry.getKey(); - int cx = MathMan.unpairIntX(chunkHash); - int cz = MathMan.unpairIntY(chunkHash); - Map blocks = entry.getValue(); - for (Map.Entry blockEntry : blocks.entrySet()) { - short blockHash = blockEntry.getKey(); - int x = (blockHash >> 12 & 0xF) + (cx << 4); - int y = (blockHash & 0xFF); - int z = (blockHash >> 8 & 0xF) + (cz << 4); - char combined = blockEntry.getValue(); - int id = FaweCache.getId(combined); - byte data = (byte) FaweCache.getData(combined); - Location loc = new Location(world, x, y, z); - bukkitPlayer.sendBlockChange(loc, id, data); - } + public void sendBlockUpdate(final FaweChunk chunk, FawePlayer... players) { + if (players.length == 0) { + return; + } + int cx = chunk.getX(); + int cz = chunk.getZ(); + int view = Bukkit.getServer().getViewDistance(); + boolean sendAny = false; + boolean[] send = new boolean[players.length]; + for (int i = 0; i < players.length; i++) { + FawePlayer player = players[i]; + Player bp = ((BukkitPlayer) player).parent; + Location loc = bp.getLocation(); + if (Math.abs((loc.getBlockX() >> 4) - cx) <= view && Math.abs((loc.getBlockZ() >> 4) - cz) <= view) { + sendAny = true; + send[i] = true; } } + if (!sendAny) { + return; + } + final World world = getWorld(); + final int bx = cx << 4; + final int bz = cz << 4; + chunk.forEachQueuedBlock(new FaweChunkVisitor() { + @Override + public void run(int localX, int y, int localZ, int combined) { + Location loc = new Location(world, bx + localX, y, bz + localZ); + for (int i = 0; i < players.length; i++) { + if (send[i]) { + ((BukkitPlayer) players[i]).parent.sendBlockChange(loc, FaweCache.getId(combined), (byte) FaweCache.getData(combined)); + } + } + } + }); } @Override diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitChunk_1_10_Copy.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitChunk_1_10_Copy.java new file mode 100644 index 00000000..3d19dc5b --- /dev/null +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitChunk_1_10_Copy.java @@ -0,0 +1,80 @@ +package com.boydti.fawe.bukkit.v1_10; + +import com.boydti.fawe.object.FaweQueue; +import net.minecraft.server.v1_10_R1.ChunkSection; +import net.minecraft.server.v1_10_R1.DataPaletteBlock; +import net.minecraft.server.v1_10_R1.NibbleArray; + +public class BukkitChunk_1_10_Copy extends BukkitChunk_1_10 { + public final byte[][] idsBytes; + public final byte[][] datasBytes; + + public BukkitChunk_1_10_Copy(FaweQueue parent, int x, int z) { + super(parent, x, z); + idsBytes = new byte[16][]; + datasBytes = new byte[16][]; + } + + public void set(int i, byte[] ids, byte[] data) { + this.idsBytes[i] = ids; + this.datasBytes[i] = data; + } + + public boolean storeSection(ChunkSection section, int layer) throws IllegalAccessException { + if (section == null) { + return false; + } + DataPaletteBlock blocks = section.getBlocks(); + byte[] ids = new byte[4096]; + NibbleArray data = new NibbleArray(); + blocks.exportData(ids, data); + set(layer, ids, data.asBytes()); + short solid = (short) getParent().fieldNonEmptyBlockCount.getInt(section); + count[layer] = solid; + air[layer] = (short) (4096 - solid); + return true; + } + + @Override + public char[][] getCombinedIdArrays() { + for (int i = 0; i < ids.length; i++) { + getIdArray(i); + } + return super.getCombinedIdArrays(); + } + + @Override + public char[] getIdArray(int i) { + char[] combined = this.ids[i]; + if (combined != null) { + return combined; + } + byte[] idsBytesArray = idsBytes[i]; + if (idsBytesArray == null) { + return null; + } + byte[] datasBytesArray = datasBytes[i]; + + idsBytes[i] = null; + datasBytes[i] = null; + + this.ids[i] = combined = new char[4096]; + for (int j = 0, k = 0; j < 2048; j++, k += 2) { + combined[k] = (char) (((idsBytesArray[k] & 0xFF) << 4) + (datasBytesArray[j] & 15)); + } + for (int j = 0, k = 1; j < 2048; j++, k += 2) { + combined[k] = (char) (((idsBytesArray[k] & 0xFF) << 4) + ((datasBytesArray[j] >> 4) & 15)); + } + return combined; + } + + @Override + public void setBlock(int x, int y, int z, int id) { + throw new UnsupportedOperationException("This chunk is an immutable copy"); + } + + @Override + public void setBlock(int x, int y, int z, int id, int data) { + throw new UnsupportedOperationException("This chunk is an immutable copy"); + } +} diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitQueue_1_10.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitQueue_1_10.java index 15724e60..e8fd2283 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitQueue_1_10.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitQueue_1_10.java @@ -25,10 +25,13 @@ import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.ExecutorCompletionService; +import net.minecraft.server.v1_10_R1.BiomeBase; +import net.minecraft.server.v1_10_R1.BiomeCache; import net.minecraft.server.v1_10_R1.Block; import net.minecraft.server.v1_10_R1.BlockPosition; +import net.minecraft.server.v1_10_R1.ChunkProviderGenerate; +import net.minecraft.server.v1_10_R1.ChunkProviderServer; import net.minecraft.server.v1_10_R1.ChunkSection; -import net.minecraft.server.v1_10_R1.DataBits; import net.minecraft.server.v1_10_R1.DataPaletteBlock; import net.minecraft.server.v1_10_R1.Entity; import net.minecraft.server.v1_10_R1.EntityPlayer; @@ -47,6 +50,7 @@ import net.minecraft.server.v1_10_R1.PlayerChunk; import net.minecraft.server.v1_10_R1.PlayerChunkMap; import net.minecraft.server.v1_10_R1.ServerNBTManager; import net.minecraft.server.v1_10_R1.TileEntity; +import net.minecraft.server.v1_10_R1.WorldChunkManager; import net.minecraft.server.v1_10_R1.WorldData; import net.minecraft.server.v1_10_R1.WorldManager; import net.minecraft.server.v1_10_R1.WorldServer; @@ -68,6 +72,8 @@ public class BukkitQueue_1_10 extends BukkitQueue_0> 4).fromLegacyData(i & 0xF); } catch (Throwable ignore) {} @@ -140,6 +150,40 @@ public class BukkitQueue_1_10 extends BukkitQueue_0 tilesGeneric, Collection[] entitiesGeneric, Set createdEntities, boolean all) throws Exception { Map tiles = (Map) tilesGeneric; Collection[] entities = (Collection[]) entitiesGeneric; - BukkitChunk_1_10 previous = getFaweChunk(fs.getX(), fs.getZ()); // Copy blocks - char[][] idPrevious = previous.getCombinedIdArrays(); + BukkitChunk_1_10_Copy previous = new BukkitChunk_1_10_Copy(this, fs.getX(), fs.getZ()); for (int layer = 0; layer < sections.length; layer++) { if (fs.getCount(layer) != 0 || all) { ChunkSection section = sections[layer]; if (section != null) { - short solid = 0; - char[] previousLayer = idPrevious[layer] = new char[4096]; DataPaletteBlock blocks = section.getBlocks(); - for (int j = 0; j < 4096; j++) { - int x = FaweCache.CACHE_X[0][j]; - int y = FaweCache.CACHE_Y[0][j]; - int z = FaweCache.CACHE_Z[0][j]; - IBlockData ibd = blocks.a(x, y, z); - Block block = ibd.getBlock(); - int combined = Block.getId(block); - if (FaweCache.hasData(combined)) { - combined = (combined << 4) + block.toLegacyData(ibd); - } else { - combined = combined << 4; - } - if (combined > 1) { - solid++; - } - previousLayer[j] = (char) combined; - } + byte[] ids = new byte[4096]; + NibbleArray data = new NibbleArray(); + blocks.exportData(ids, data); + previous.set(layer, ids, data.asBytes()); + short solid = (short) fieldNonEmptyBlockCount.getInt(section); previous.count[layer] = solid; previous.air[layer] = (short) (4096 - solid); } @@ -605,7 +602,7 @@ public class BukkitQueue_1_10 extends BukkitQueue_0 constructor = $0.getClass().getDeclaredClasses()[0].getConstructors()[0]; +// constructor.setAccessible(true); +// return $0.d($1, $2) ? null : new java.io.DataOutputStream(new java.io.BufferedOutputStream(new com.boydti.fawe.object.io.PGZIPOutputStream((OutputStream) constructor.newInstance($1, $2)))); + } + } + + public static Object newInstance(Constructor constructor, RegionFile file, int a, int b) throws IllegalAccessException, InvocationTargetException, InstantiationException { + return constructor.newInstance(file, a, b); + } +} diff --git a/core/build.gradle b/core/build.gradle index 0e0cb565..2d184af7 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -14,9 +14,6 @@ dependencies { } } -sourceCompatibility = 1.7 -targetCompatibility = 1.7 - processResources { from('src/main/resources') { include 'fawe.properties' diff --git a/core/src/main/java/com/boydti/fawe/Fawe.java b/core/src/main/java/com/boydti/fawe/Fawe.java index 14e6aa3c..cc3c80f2 100644 --- a/core/src/main/java/com/boydti/fawe/Fawe.java +++ b/core/src/main/java/com/boydti/fawe/Fawe.java @@ -8,6 +8,7 @@ import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.Commands; import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.FawePlayer; +import com.boydti.fawe.object.brush.visualization.VisualQueue; import com.boydti.fawe.regions.general.plot.PlotSquaredFeature; import com.boydti.fawe.util.FaweTimer; import com.boydti.fawe.util.MainUtil; @@ -26,6 +27,7 @@ import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BlockData; import com.sk89q.worldedit.command.BiomeCommands; import com.sk89q.worldedit.command.BrushCommands; @@ -69,6 +71,7 @@ import com.sk89q.worldedit.extent.transform.BlockTransformExtent; import com.sk89q.worldedit.function.entity.ExtentEntityCopy; import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.function.mask.FuzzyBlockMask; +import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.MaskUnion; import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.function.mask.OffsetMask; @@ -77,6 +80,7 @@ import com.sk89q.worldedit.function.operation.ChangeSetExecutor; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.ClipboardPattern; +import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Patterns; import com.sk89q.worldedit.function.pattern.RandomPattern; import com.sk89q.worldedit.function.visitor.BreadthFirstSearch; @@ -167,6 +171,8 @@ public class Fawe { */ private final FaweTimer timer; private FaweVersion version; + private VisualQueue visualQueue; + private Updater updater; /** * Get the implementation specific class @@ -242,7 +248,7 @@ public class Fawe { * Instance independent stuff */ this.setupMemoryListener(); - timer = new FaweTimer(); + this.timer = new FaweTimer(); Fawe.this.IMP.setupVault(); // Delayed worldedit setup @@ -250,6 +256,7 @@ public class Fawe { @Override public void run() { try { + visualQueue = new VisualQueue(); WEManager.IMP.managers.addAll(Fawe.this.IMP.getMaskManagers()); WEManager.IMP.managers.add(new PlotSquaredFeature()); Fawe.debug("Plugin 'PlotSquared' found. Using it now."); @@ -265,7 +272,8 @@ public class Fawe { TaskManager.IMP.repeatAsync(new Runnable() { @Override public void run() { - Updater.update(IMP.getPlatform(), getVersion()); + updater = new Updater(); + updater.update(IMP.getPlatform(), getVersion()); } }, 36000); } @@ -277,6 +285,15 @@ public class Fawe { return isJava8; } + /** + * The FAWE updater class + * - Use to get basic update information (changelog/version etc) + * @return + */ + public Updater getUpdater() { + return updater; + } + /** * The FaweTimer is a useful class for monitoring TPS * @return FaweTimer @@ -285,6 +302,14 @@ public class Fawe { return timer; } + /** + * The visual queue is used to queue visualizations + * @return + */ + public VisualQueue getVisualQueue() { + return visualQueue; + } + /** * The FAWE version * - Unofficial jars may be lacking version information @@ -306,6 +331,7 @@ public class Fawe { } public void setupConfigs() { + MainUtil.copyFile(MainUtil.getJarFile(), "de/messages.yml", null); // Setting up config.yml File file = new File(this.IMP.getDirectory(), "config.yml"); Settings.IMP.PLATFORM = IMP.getPlatform().replace("\"", ""); @@ -345,7 +371,7 @@ public class Fawe { Commands.inject(); // Translations EditSession.inject(); // Custom block placer + optimizations EditSessionEvent.inject(); // Add EditSession to event (API) - LocalSession.inject(); // Add remember order / queue flushing / Optimizations for disk + LocalSession.inject(); // Add remember order / queue flushing / Optimizations for disk / brush visualization SessionManager.inject(); // Faster custom session saving + Memory improvements Request.inject(); // Custom pattern extent // Commands @@ -381,7 +407,7 @@ public class Fawe { LongRangeBuildTool.inject(); AreaPickaxe.inject(); // Fixes RecursivePickaxe.inject(); // Fixes - BrushTool.inject(); // Add transform + BrushTool.inject(); // Add transform + support for double action brushes + visualizations // Selectors CuboidRegionSelector.inject(); // Translations EllipsoidRegion.inject(); // Optimizations @@ -415,13 +441,17 @@ public class Fawe { BlockVector.inject(); // Optimizations Vector.inject(); // Optimizations Vector2D.inject(); // Optimizations + // Block + BaseBlock.inject(); // Optimizations // Pattern + Pattern.inject(); // Simplify API Patterns.inject(); // Optimizations (reduce object creation) RandomPattern.inject(); // Optimizations ClipboardPattern.inject(); // Optimizations HashTagPatternParser.inject(); // Add new patterns DefaultBlockParser.inject(); // Fix block lookups // Mask + Mask.inject(); // Extend deprecated mask BlockMask.inject(); // Optimizations SolidBlockMask.inject(); // Optimizations FuzzyBlockMask.inject(); // Optimizations diff --git a/core/src/main/java/com/boydti/fawe/FaweCache.java b/core/src/main/java/com/boydti/fawe/FaweCache.java index 0869e0df..526b25c7 100644 --- a/core/src/main/java/com/boydti/fawe/FaweCache.java +++ b/core/src/main/java/com/boydti/fawe/FaweCache.java @@ -14,9 +14,10 @@ import com.sk89q.jnbt.LongTag; import com.sk89q.jnbt.ShortTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.CuboidClipboard; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.blocks.ImmutableBlock; +import com.sk89q.worldedit.blocks.ImmutableDatalessBlock; import com.sk89q.worldedit.world.biome.BaseBiome; import com.sk89q.worldedit.world.registry.BundledBlockData; import java.awt.Color; @@ -171,34 +172,11 @@ public class FaweCache { for (int i = 0; i < Character.MAX_VALUE; i++) { int id = i >> 4; int data = i & 0xf; - CACHE_BLOCK[i] = new BaseBlock(id, data) { - @Override - public void setData(int data) { - throw new IllegalStateException("Cannot set data"); - } - - @Override - public void setId(int id) { - throw new IllegalStateException("Cannot set id"); - } - - @Override - public BaseBlock flip() { - BaseBlock clone = new BaseBlock(getId(), getData(), getNbtData()); - return clone.flip(); - } - - @Override - public BaseBlock flip(CuboidClipboard.FlipDirection direction) { - BaseBlock clone = new BaseBlock(getId(), getData(), getNbtData()); - return clone.flip(direction); - } - - @Override - public boolean hasWildcardData() { - return true; - } - }; + if (FaweCache.hasData(id)) { + CACHE_BLOCK[i] = new ImmutableBlock(id, data); + } else { + CACHE_BLOCK[i] = new ImmutableDatalessBlock(id); + } CACHE_ITEM[i] = new BaseItem(id, (short) data) { @Override diff --git a/core/src/main/java/com/boydti/fawe/command/Reload.java b/core/src/main/java/com/boydti/fawe/command/Reload.java index d9942ad3..f6ac7709 100644 --- a/core/src/main/java/com/boydti/fawe/command/Reload.java +++ b/core/src/main/java/com/boydti/fawe/command/Reload.java @@ -7,12 +7,14 @@ import com.boydti.fawe.object.FaweCommand; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.util.HastebinUtility; import com.boydti.fawe.util.MainUtil; +import com.boydti.fawe.util.Updater; import java.io.File; import java.io.IOException; -import java.time.LocalDate; +import java.net.URL; import java.util.Date; import java.util.GregorianCalendar; import java.util.Map; +import java.util.Scanner; public class Reload extends FaweCommand { @@ -23,7 +25,7 @@ public class Reload extends FaweCommand { @Override public boolean execute(final FawePlayer player, final String... args) { if (args.length != 1) { - BBC.COMMAND_SYNTAX.send(player, "/fawe [reload|version|debugpaste|threads]"); + BBC.COMMAND_SYNTAX.send(player, "/fawe [reload|version|debugpaste|threads|changelog]"); return false; } switch (args[0].toLowerCase()) { @@ -54,6 +56,22 @@ public class Reload extends FaweCommand { } return true; } + case "changelog": { + try { + Updater updater = Fawe.get().getUpdater(); + String changes = updater != null ? updater.getChanges() : null; + if (changes == null) { + try (Scanner scanner = new Scanner(new URL("http://boydti.com/fawe/cl?" + Integer.toHexString(Fawe.get().getVersion().hash)).openStream(), "UTF-8")) { + changes = scanner.useDelimiter("\\A").next(); + } + } + player.sendMessage(BBC.getPrefix() + changes); + return true; + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } case "debugpaste": case "paste": { try { diff --git a/core/src/main/java/com/boydti/fawe/config/BBC.java b/core/src/main/java/com/boydti/fawe/config/BBC.java index 46eeb66f..da2ac025 100644 --- a/core/src/main/java/com/boydti/fawe/config/BBC.java +++ b/core/src/main/java/com/boydti/fawe/config/BBC.java @@ -123,6 +123,7 @@ public enum BBC { BRUSH_SPLINE_SECONDARY("Created spline", "WorldEdit.Brush"), BRUSH_BLEND_BALL("Blend ball brush equipped (%s0).", "WorldEdit.Brush"), BRUSH_ERODE("Erode brush equipped (%s0). Right click to erode, left click to pull.", "WorldEdit.Brush"), + BRUSH_CIRCLE("Circle brush equipped (%s0). Right click to create a circle.", "WorldEdit.Brush"), BRUSH_RECURSIVE("Recursive brush equipped (%s0).", "WorldEdit.Brush"), BRUSH_PASTE_NONE("Nothing to paste", "WorldEdit.Brush"), BRUSH_SIZE("Brush size set", "WorldEdit.Brush"), diff --git a/core/src/main/java/com/boydti/fawe/config/Settings.java b/core/src/main/java/com/boydti/fawe/config/Settings.java index a1830bd5..24681852 100644 --- a/core/src/main/java/com/boydti/fawe/config/Settings.java +++ b/core/src/main/java/com/boydti/fawe/config/Settings.java @@ -2,7 +2,6 @@ package com.boydti.fawe.config; import com.boydti.fawe.object.FaweLimit; import com.boydti.fawe.object.FawePlayer; -import com.sk89q.worldedit.LocalSession; import java.io.File; import java.util.ArrayList; import java.util.Collection; @@ -26,6 +25,9 @@ public class Settings extends Config { @Final public String PLATFORM; // These values are set from FAWE before loading + @Comment({"Options: de", + "Create a PR to contribute a translation: https://github.com/boy0001/FastAsyncWorldedit/new/master/core/src/main/resources",}) + public String LANGUAGE = ""; @Comment("Allow the plugin to update") public boolean UPDATE = true; @Comment("Send anonymous usage statistics to MCStats.org") @@ -330,9 +332,6 @@ public class Settings extends Config { public void reload(File file) { load(file); save(file); - if (HISTORY.USE_DISK) { - LocalSession.MAX_HISTORY_SIZE = Integer.MAX_VALUE; - } } public FaweLimit getLimit(FawePlayer player) { diff --git a/core/src/main/java/com/boydti/fawe/example/NullQueueCharFaweChunk.java b/core/src/main/java/com/boydti/fawe/example/NullQueueCharFaweChunk.java new file mode 100644 index 00000000..bee7e991 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/example/NullQueueCharFaweChunk.java @@ -0,0 +1,34 @@ +package com.boydti.fawe.example; + +import com.boydti.fawe.object.FaweChunk; +import com.boydti.fawe.util.MainUtil; + +public class NullQueueCharFaweChunk extends CharFaweChunk { + + public NullQueueCharFaweChunk(int cx, int cz) { + super(null, cx, cz); + } + + public NullQueueCharFaweChunk(int x, int z, char[][] ids, short[] count, short[] air, byte[] heightMap) { + super(null, x, z, ids, count, air, heightMap); + } + + @Override + public Object getNewChunk() { + return null; + } + + @Override + public CharFaweChunk copy(boolean shallow) { + if (shallow) { + return new NullQueueCharFaweChunk(getX(), getZ(), ids, count, air, heightMap); + } else { + return new NullQueueCharFaweChunk(getX(), getZ(), (char[][]) MainUtil.copyNd(ids), count.clone(), air.clone(), heightMap.clone()); + } + } + + @Override + public FaweChunk call() { + return null; + } +} diff --git a/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueue.java b/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueue.java index 8be99df1..4c3c1a94 100644 --- a/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueue.java +++ b/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueue.java @@ -350,9 +350,9 @@ public class MCAQueue extends NMSMappedFaweQueue> blockMap, FawePlayer... players) { + public void sendBlockUpdate(FaweChunk chunk, FawePlayer... players) { if (parent != null) { - parentNMS.sendBlockUpdate(blockMap, players); + parentNMS.sendBlockUpdate(chunk, players); } } } diff --git a/core/src/main/java/com/boydti/fawe/object/FaweChunk.java b/core/src/main/java/com/boydti/fawe/object/FaweChunk.java index ef346b2c..b21fe936 100644 --- a/core/src/main/java/com/boydti/fawe/object/FaweChunk.java +++ b/core/src/main/java/com/boydti/fawe/object/FaweChunk.java @@ -1,6 +1,7 @@ package com.boydti.fawe.object; import com.boydti.fawe.FaweCache; +import com.boydti.fawe.object.visitor.FaweChunkVisitor; import com.boydti.fawe.util.MainUtil; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.blocks.BaseBlock; @@ -146,6 +147,20 @@ public abstract class FaweChunk implements Callable { public abstract byte[] getBiomeArray(); + public void forEachQueuedBlock(FaweChunkVisitor onEach) { + for (int y = 0; y < HEIGHT; y++) { + for (int z = 0; z < 16; z++) { + for (int x = 0; x < 16; x++) { + int combined = getBlockCombinedId(x, y, z); + if (combined == 0) { + continue; + } + onEach.run(x, y, z, combined); + } + } + } + } + public char[][] getCombinedIdArrays() { char[][] ids = new char[HEIGHT >> 4][]; for (int y = 0; y < HEIGHT >> 4; y++) { diff --git a/core/src/main/java/com/boydti/fawe/object/FawePlayer.java b/core/src/main/java/com/boydti/fawe/object/FawePlayer.java index a20f8dc9..e92c4359 100644 --- a/core/src/main/java/com/boydti/fawe/object/FawePlayer.java +++ b/core/src/main/java/com/boydti/fawe/object/FawePlayer.java @@ -209,7 +209,7 @@ public abstract class FawePlayer extends Metadatable { try { if (file.exists() && file.length() > 5) { DiskOptimizedClipboard doc = new DiskOptimizedClipboard(file); - Player player = getPlayer(); + Player player = toWorldEditPlayer(); LocalSession session = getSession(); try { if (session.getClipboard() != null) { @@ -331,7 +331,16 @@ public abstract class FawePlayer extends Metadatable { * Get the WorldEdit player object * @return */ - public abstract Player getPlayer(); + public abstract Player toWorldEditPlayer(); + + private Player cachedWorldEditPlayer; + + public Player getPlayer() { + if (cachedWorldEditPlayer == null) { + cachedWorldEditPlayer = toWorldEditPlayer(); + } + return cachedWorldEditPlayer; + } /** * Get the player's current selection (or null) @@ -382,7 +391,7 @@ public abstract class FawePlayer extends Metadatable { * @param selector */ public void setSelection(final RegionSelector selector) { - this.getSession().setRegionSelector(getPlayer().getWorld(), selector); + this.getSession().setRegionSelector(toWorldEditPlayer().getWorld(), selector); } /** @@ -422,7 +431,7 @@ public abstract class FawePlayer extends Metadatable { public void unregister() { if (Settings.IMP.HISTORY.DELETE_ON_LOGOUT) { session = getSession(); - WorldEdit.getInstance().removeSession(getPlayer()); + WorldEdit.getInstance().removeSession(toWorldEditPlayer()); session.setClipboard(null); session.clearHistory(); } @@ -433,7 +442,7 @@ public abstract class FawePlayer extends Metadatable { * Get a new EditSession from this player */ public EditSession getNewEditSession() { - return WorldEdit.getInstance().getEditSessionFactory().getEditSession(getWorld(), -1, getPlayer()); + return WorldEdit.getInstance().getEditSessionFactory().getEditSession(getWorld(), -1, toWorldEditPlayer()); } diff --git a/core/src/main/java/com/boydti/fawe/object/FaweQueue.java b/core/src/main/java/com/boydti/fawe/object/FaweQueue.java index 72a2c4ba..2f9e2ad6 100644 --- a/core/src/main/java/com/boydti/fawe/object/FaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/object/FaweQueue.java @@ -25,7 +25,6 @@ import com.sk89q.worldedit.world.registry.BundledBlockData; import java.io.File; import java.util.Collection; import java.util.HashSet; -import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentLinkedDeque; @@ -308,7 +307,7 @@ public abstract class FaweQueue implements HasFaweQueue { return count; } - public abstract void sendBlockUpdate(Map> blockMap, FawePlayer... players); + public abstract void sendBlockUpdate(FaweChunk chunk, FawePlayer... players); @Deprecated public boolean next() { diff --git a/core/src/main/java/com/boydti/fawe/object/brush/CircleBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/CircleBrush.java new file mode 100644 index 00000000..d2ff316e --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/brush/CircleBrush.java @@ -0,0 +1,48 @@ +package com.boydti.fawe.object.brush; + +import com.boydti.fawe.object.brush.visualization.VisualBrush; +import com.boydti.fawe.object.collection.LocalBlockVectorSet; +import com.boydti.fawe.wrappers.LocationMaskedPlayerWrapper; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.command.tool.BrushTool; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.transform.AffineTransform; + +public class CircleBrush extends VisualBrush { + private final Player player; + + public CircleBrush(BrushTool tool, Player player) { + super(tool); + this.player = LocationMaskedPlayerWrapper.unwrap(player); + } + + @Override + public void build(BrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException { + switch (action) { + case PRIMARY: + LocalBlockVectorSet set = new LocalBlockVectorSet(); + int radius = (int) size; + Vector normal = position.subtract(player.getPosition()); + editSession.makeCircle(position, pattern, size, size, size, false, normal); + break; + case SECONDARY: + break; + } + } + + private static Vector any90Rotate(Vector normal) { + normal = normal.normalize(); + if (normal.getX() == 1 || normal.getY() == 1 || normal.getZ() == 1) { + return new Vector(normal.getZ(), normal.getX(), normal.getY()); + } + AffineTransform affine = new AffineTransform(); + affine = affine.rotateX(90); + affine = affine.rotateY(90); + affine = affine.rotateZ(90); + Vector random = affine.apply(normal); + return random.cross(normal).normalize(); + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/brush/CopyPastaBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/CopyPastaBrush.java index cd66874e..efa81ceb 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/CopyPastaBrush.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/CopyPastaBrush.java @@ -11,6 +11,7 @@ import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.command.tool.BrushTool; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Masks; @@ -23,14 +24,14 @@ import com.sk89q.worldedit.session.ClipboardHolder; public class CopyPastaBrush implements DoubleActionBrush { - private final DoubleActionBrushTool tool; + private final BrushTool tool; - public CopyPastaBrush(DoubleActionBrushTool tool) { + public CopyPastaBrush(BrushTool tool) { this.tool = tool; } @Override - public void build(DoubleActionBrushTool.BrushAction action, final EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException { + public void build(BrushTool.BrushAction action, final EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException { FawePlayer fp = editSession.getPlayer(); LocalSession session = fp.getSession(); switch (action) { diff --git a/core/src/main/java/com/boydti/fawe/object/brush/DoubleActionBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/DoubleActionBrush.java index ae3452bc..d2fd753b 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/DoubleActionBrush.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/DoubleActionBrush.java @@ -3,8 +3,16 @@ package com.boydti.fawe.object.brush; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.command.tool.BrushTool; +import com.sk89q.worldedit.command.tool.brush.Brush; import com.sk89q.worldedit.function.pattern.Pattern; -public interface DoubleActionBrush { - public void build(DoubleActionBrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException; +public interface DoubleActionBrush extends Brush { + + @Override + default void build(EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException { + build(BrushTool.BrushAction.PRIMARY, editSession, position, pattern, size); + } + + public void build(BrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException; } diff --git a/core/src/main/java/com/boydti/fawe/object/brush/DoubleActionBrushTool.java b/core/src/main/java/com/boydti/fawe/object/brush/DoubleActionBrushTool.java deleted file mode 100644 index 688c53ad..00000000 --- a/core/src/main/java/com/boydti/fawe/object/brush/DoubleActionBrushTool.java +++ /dev/null @@ -1,239 +0,0 @@ -package com.boydti.fawe.object.brush; - -import com.boydti.fawe.config.BBC; -import com.boydti.fawe.object.extent.ResettableExtent; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.LocalConfiguration; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.WorldVector; -import com.sk89q.worldedit.command.tool.DoubleActionTraceTool; -import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.extension.platform.Platform; -import com.sk89q.worldedit.extent.inventory.BlockBag; -import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.function.mask.MaskIntersection; -import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.session.request.Request; -import javax.annotation.Nullable; - - -import static com.google.common.base.Preconditions.checkNotNull; - -public class DoubleActionBrushTool implements DoubleActionTraceTool { - - public enum BrushAction { - PRIMARY, - SECONDARY - } - - protected static int MAX_RANGE = 500; - protected int range = -1; - private Mask mask = null; - private Mask sourceMask = null; - private ResettableExtent transform = null; - private DoubleActionBrush brush = null; - @Nullable - private Pattern material; - private double size = 1; - private String permission; - - /** - * Construct the tool. - * - * @param permission the permission to check before use is allowed - */ - public DoubleActionBrushTool(String permission) { - checkNotNull(permission); - this.permission = permission; - } - - @Override - public boolean canUse(Actor player) { - return player.hasPermission(permission); - } - - public ResettableExtent getTransform() { - return transform; - } - - public void setTransform(ResettableExtent transform) { - this.transform = transform; - } - - /** - * Get the filter. - * - * @return the filter - */ - public Mask getMask() { - return mask; - } - - /** - * Get the filter. - * - * @return the filter - */ - public Mask getSourceMask() { - return sourceMask; - } - - /** - * Set the block filter used for identifying blocks to replace. - * - * @param filter the filter to set - */ - public void setMask(Mask filter) { - this.mask = filter; - } - - /** - * Set the block filter used for identifying blocks to replace. - * - * @param filter the filter to set - */ - public void setSourceMask(Mask filter) { - this.sourceMask = filter; - } - - /** - * Set the brush. - * - * @param brush tbe brush - * @param permission the permission - */ - public void setBrush(DoubleActionBrush brush, String permission) { - this.brush = brush; - this.permission = permission; - } - - /** - * Get the current brush. - * - * @return the current brush - */ - public DoubleActionBrush getBrush() { - return brush; - } - - /** - * Set the material. - * - * @param material the material - */ - public void setFill(@Nullable Pattern material) { - this.material = material; - } - - /** - * Get the material. - * - * @return the material - */ - @Nullable public Pattern getMaterial() { - return material; - } - - /** - * Get the set brush size. - * - * @return a radius - */ - public double getSize() { - return size; - } - - /** - * Set the set brush size. - * - * @param radius a radius - */ - public void setSize(double radius) { - this.size = radius; - } - - /** - * Get the set brush range. - * - * @return the range of the brush in blocks - */ - public int getRange() { - return (range < 0) ? MAX_RANGE : Math.min(range, MAX_RANGE); - } - - /** - * Set the set brush range. - * - * @param range the range of the brush in blocks - */ - public void setRange(int range) { - this.range = range; - } - - public boolean act(BrushAction action, Platform server, LocalConfiguration config, Player player, LocalSession session) { - WorldVector target = null; - target = player.getBlockTrace(getRange(), true); - - if (target == null) { - BBC.NO_BLOCK.send(player); - return true; - } - - BlockBag bag = session.getBlockBag(player); - - EditSession editSession = session.createEditSession(player); - Request.request().setEditSession(editSession); - if (mask != null) { - Mask existingMask = editSession.getMask(); - - if (existingMask == null) { - editSession.setMask(mask); - } else if (existingMask instanceof MaskIntersection) { - ((MaskIntersection) existingMask).add(mask); - } else { - MaskIntersection newMask = new MaskIntersection(existingMask); - newMask.add(mask); - editSession.setMask(newMask); - } - } - if (sourceMask != null) { - Mask existingMask = editSession.getSourceMask(); - - if (existingMask == null) { - editSession.setSourceMask(sourceMask); - } else if (existingMask instanceof MaskIntersection) { - ((MaskIntersection) existingMask).add(sourceMask); - } else { - MaskIntersection newMask = new MaskIntersection(existingMask); - newMask.add(sourceMask); - editSession.setSourceMask(newMask); - } - } - if (transform != null) { - editSession.addTransform(transform); - } - try { - brush.build(action, editSession, target, material, size); - } catch (MaxChangedBlocksException e) { - player.printError("Max blocks change limit reached."); // Never happens - } finally { - if (bag != null) { - bag.flushChanges(); - } - session.remember(editSession); - } - return true; - } - - @Override - public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session) { - return act(BrushAction.PRIMARY, server, config, player, session); - } - - @Override - public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session) { - return act(BrushAction.SECONDARY, server, config, player, session); - } -} diff --git a/core/src/main/java/com/boydti/fawe/object/brush/ErodeBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/ErodeBrush.java index 8cba997d..fb35cfc4 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/ErodeBrush.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/ErodeBrush.java @@ -10,6 +10,7 @@ import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.command.tool.BrushTool; import com.sk89q.worldedit.function.pattern.Pattern; import java.util.Arrays; @@ -20,7 +21,7 @@ public class ErodeBrush implements DoubleActionBrush { private static final Vector[] FACES_TO_CHECK = {new Vector(0, 0, 1), new Vector(0, 0, -1), new Vector(0, 1, 0), new Vector(0, -1, 0), new Vector(1, 0, 0), new Vector(-1, 0, 0)}; @Override - public void build(DoubleActionBrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException { + public void build(BrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException { switch (action) { case PRIMARY: { int erodeFaces = 2; diff --git a/core/src/main/java/com/boydti/fawe/object/brush/FlattenBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/FlattenBrush.java index 4ac3dcbc..ed8e1a32 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/FlattenBrush.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/FlattenBrush.java @@ -4,6 +4,7 @@ import com.boydti.fawe.object.brush.heightmap.ScalableHeightMap; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.command.tool.BrushTool; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Masks; @@ -12,18 +13,18 @@ import java.io.InputStream; public class FlattenBrush extends HeightBrush { - public FlattenBrush(InputStream stream, int rotation, double yscale, DoubleActionBrushTool tool, Clipboard clipboard, ScalableHeightMap.Shape shape) { + public FlattenBrush(InputStream stream, int rotation, double yscale, BrushTool tool, Clipboard clipboard, ScalableHeightMap.Shape shape) { super(stream, rotation, yscale, tool, clipboard, shape); } @Override - public void build(DoubleActionBrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double sizeDouble) throws MaxChangedBlocksException { + public void build(BrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double sizeDouble) throws MaxChangedBlocksException { int size = (int) sizeDouble; Mask mask = tool.getMask(); if (mask == Masks.alwaysTrue() || mask == Masks.alwaysTrue2D()) { mask = null; } heightMap.setSize(size); - heightMap.apply(editSession, mask, position, size, rotation, action == DoubleActionBrushTool.BrushAction.PRIMARY ? yscale : -yscale, true, true); + heightMap.apply(editSession, mask, position, size, rotation, action == BrushTool.BrushAction.PRIMARY ? yscale : -yscale, true, true); } } diff --git a/core/src/main/java/com/boydti/fawe/object/brush/HeightBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/HeightBrush.java index 92c2f02c..a5288a7b 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/HeightBrush.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/HeightBrush.java @@ -6,6 +6,7 @@ import com.boydti.fawe.object.exception.FaweException; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.command.tool.BrushTool; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Masks; @@ -18,14 +19,13 @@ public class HeightBrush implements DoubleActionBrush { public final ScalableHeightMap heightMap; public final int rotation; public final double yscale; - public final DoubleActionBrushTool tool; + public final BrushTool tool; - public HeightBrush(InputStream stream, int rotation, double yscale, DoubleActionBrushTool tool, Clipboard clipboard) { + public HeightBrush(InputStream stream, int rotation, double yscale, BrushTool tool, Clipboard clipboard) { this(stream, rotation, yscale, tool, clipboard, ScalableHeightMap.Shape.CONE); } - public HeightBrush(InputStream stream, int rotation, double yscale, DoubleActionBrushTool tool, Clipboard clipboard, ScalableHeightMap.Shape shape) { - this.tool = tool; + public HeightBrush(InputStream stream, int rotation, double yscale, BrushTool tool, Clipboard clipboard, ScalableHeightMap.Shape shape) { this.rotation = (rotation / 90) % 4; this.yscale = yscale; if (stream != null) { @@ -39,16 +39,17 @@ public class HeightBrush implements DoubleActionBrush { } else { heightMap = ScalableHeightMap.fromShape(shape); } + this.tool = tool; } @Override - public void build(DoubleActionBrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double sizeDouble) throws MaxChangedBlocksException { + public void build(BrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double sizeDouble) throws MaxChangedBlocksException { int size = (int) sizeDouble; Mask mask = tool.getMask(); if (mask == Masks.alwaysTrue() || mask == Masks.alwaysTrue2D()) { mask = null; } heightMap.setSize(size); - heightMap.apply(editSession, mask, position, size, rotation, action == DoubleActionBrushTool.BrushAction.PRIMARY ? yscale : -yscale, true, false); + heightMap.apply(editSession, mask, position, size, rotation, action == BrushTool.BrushAction.PRIMARY ? yscale : -yscale, true, false); } } diff --git a/core/src/main/java/com/boydti/fawe/object/brush/LineBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/LineBrush.java index 947f8675..12c717e6 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/LineBrush.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/LineBrush.java @@ -3,6 +3,7 @@ package com.boydti.fawe.object.brush; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.command.tool.BrushTool; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Patterns; @@ -18,7 +19,7 @@ public class LineBrush implements DoubleActionBrush { } @Override - public void build(DoubleActionBrushTool.BrushAction action, EditSession editSession, Vector position, final Pattern pattern, double size) throws MaxChangedBlocksException { + public void build(BrushTool.BrushAction action, EditSession editSession, Vector position, final Pattern pattern, double size) throws MaxChangedBlocksException { switch (action) { case PRIMARY: if (pos1 == null) { diff --git a/core/src/main/java/com/boydti/fawe/object/brush/MovableBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/MovableBrush.java new file mode 100644 index 00000000..b1bde41a --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/brush/MovableBrush.java @@ -0,0 +1,7 @@ +package com.boydti.fawe.object.brush; + +import com.sk89q.worldedit.entity.Player; + +public interface MovableBrush { + public boolean move(Player player); +} diff --git a/core/src/main/java/com/boydti/fawe/object/brush/RaiseBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/RaiseBrush.java index 78146158..dc7c72f1 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/RaiseBrush.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/RaiseBrush.java @@ -3,13 +3,14 @@ package com.boydti.fawe.object.brush; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.command.tool.BrushTool; import com.sk89q.worldedit.function.pattern.Pattern; public class RaiseBrush implements DoubleActionBrush { @Override - public void build(DoubleActionBrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException { + public void build(BrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException { switch (action) { case PRIMARY: break; diff --git a/core/src/main/java/com/boydti/fawe/object/brush/SplineBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/SplineBrush.java index 6b9e3cfb..71f9bbe5 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/SplineBrush.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/SplineBrush.java @@ -1,6 +1,7 @@ package com.boydti.fawe.object.brush; import com.boydti.fawe.config.BBC; +import com.boydti.fawe.object.brush.visualization.VisualExtent; import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.object.mask.IdMask; import com.boydti.fawe.object.visitor.DFSRecursiveVisitor; @@ -9,6 +10,7 @@ import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.tool.BrushTool; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.mask.Mask; @@ -16,8 +18,6 @@ import com.sk89q.worldedit.function.mask.MaskIntersection; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Patterns; -import com.sk89q.worldedit.math.interpolation.Interpolation; -import com.sk89q.worldedit.math.interpolation.KochanekBartelsInterpolation; import com.sk89q.worldedit.math.interpolation.Node; import com.sk89q.worldedit.math.transform.AffineTransform; import java.util.ArrayList; @@ -30,11 +30,11 @@ public class SplineBrush implements DoubleActionBrush { private ArrayList> positionSets; private int numSplines; - private final DoubleActionBrushTool tool; + private final BrushTool tool; private final LocalSession session; private final Player player; - public SplineBrush(Player player, LocalSession session, DoubleActionBrushTool tool) { + public SplineBrush(Player player, LocalSession session, BrushTool tool) { this.tool = tool; this.session = session; this.player = player; @@ -42,15 +42,20 @@ public class SplineBrush implements DoubleActionBrush { } @Override - public void build(DoubleActionBrushTool.BrushAction action, EditSession editSession, final Vector position, Pattern pattern, double size) throws MaxChangedBlocksException { + public void build(BrushTool.BrushAction action, EditSession editSession, final Vector position, Pattern pattern, double size) throws MaxChangedBlocksException { Mask mask = tool.getMask(); if (mask == null) { mask = new IdMask(editSession); } else { mask = new MaskIntersection(mask, new IdMask(editSession)); } + boolean visualization = editSession.getExtent() instanceof VisualExtent; + if (visualization && positionSets.isEmpty()) { + return; + } + int originalSize = numSplines; switch (action) { - case PRIMARY: { // Right + case PRIMARY: { if (positionSets.size() >= MAX_POINTS) { throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); } @@ -62,6 +67,17 @@ public class SplineBrush implements DoubleActionBrush { return true; } }, (int) size, 1); + Collection directions = visitor.getDirections(); + for (int x = -1; x <= 1; x++) { + for (int y = -1; y <= 1; y++) { + for (int z = -1; z <= 1; z++) { + Vector pos = new Vector(x, y, z); + if (!directions.contains(pos)) { + directions.add(pos); + } + } + } + } visitor.visit(position); Operations.completeBlindly(visitor); if (points.size() > numSplines) { @@ -69,7 +85,9 @@ public class SplineBrush implements DoubleActionBrush { } this.positionSets.add(points); player.print(BBC.getPrefix() + BBC.BRUSH_SPLINE_PRIMARY.s()); - break; + if (!visualization) { + break; + } } case SECONDARY: { if (positionSets.size() < 2) { @@ -88,7 +106,6 @@ public class SplineBrush implements DoubleActionBrush { final List nodes = new ArrayList(centroids.size()); - final Interpolation interpol = new KochanekBartelsInterpolation(); for (final Vector nodevector : centroids) { final Node n = new Node(nodevector); n.setTension(tension); @@ -113,8 +130,13 @@ public class SplineBrush implements DoubleActionBrush { editSession.drawSpline(Patterns.wrap(pattern), currentSpline, 0, 0, 0, 10, 0, true); } player.print(BBC.getPrefix() + BBC.BRUSH_SPLINE_SECONDARY.s()); - positionSets.clear(); - numSplines = 0; + if (visualization) { + positionSets.clear(); + numSplines = 0; + } else { + numSplines = originalSize; + positionSets.remove(positionSets.size() - 1); + } break; } } diff --git a/core/src/main/java/com/boydti/fawe/object/brush/TargetMode.java b/core/src/main/java/com/boydti/fawe/object/brush/TargetMode.java new file mode 100644 index 00000000..eb3732c4 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/brush/TargetMode.java @@ -0,0 +1,8 @@ +package com.boydti.fawe.object.brush; + +public enum TargetMode { + TARGET_BLOCK_RANGE, + FOWARD_POINT_PITCH, + TARGET_POINT_HEIGHT, + TARGET_POINT_RANGE, +} diff --git a/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollAction.java b/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollAction.java new file mode 100644 index 00000000..4b61cc0a --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollAction.java @@ -0,0 +1,11 @@ +package com.boydti.fawe.object.brush.scroll; + +import com.sk89q.worldedit.command.tool.BrushTool; + +public abstract class ScrollAction implements ScrollableBrush { + public final BrushTool tool; + + public ScrollAction(BrushTool tool) { + this.tool = tool; + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollClipboard.java b/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollClipboard.java new file mode 100644 index 00000000..f7c3409d --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollClipboard.java @@ -0,0 +1,4 @@ +package com.boydti.fawe.object.brush.scroll; + +public class ScrollClipboard { +} diff --git a/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollMask.java b/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollMask.java new file mode 100644 index 00000000..531232a3 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollMask.java @@ -0,0 +1,25 @@ +package com.boydti.fawe.object.brush.scroll; + +import com.boydti.fawe.util.MathMan; +import com.sk89q.worldedit.command.tool.BrushTool; +import com.sk89q.worldedit.function.mask.Mask; + +public class ScrollMask extends ScrollAction { + private final Mask[] masks; + private int index; + + public ScrollMask(BrushTool tool, Mask... masks) { + super(tool); + this.masks = masks; + } + + + @Override + public boolean increment(int amount) { + if (masks.length > 1) { + tool.setMask(masks[MathMan.wrap(index += amount, 0, masks.length - 1)]); + return true; + } + return false; + } +} \ No newline at end of file diff --git a/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollPattern.java b/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollPattern.java new file mode 100644 index 00000000..3cd0bfbe --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollPattern.java @@ -0,0 +1,25 @@ +package com.boydti.fawe.object.brush.scroll; + +import com.boydti.fawe.util.MathMan; +import com.sk89q.worldedit.command.tool.BrushTool; +import com.sk89q.worldedit.function.pattern.Pattern; + +public class ScrollPattern extends ScrollAction { + private final Pattern[] patterns; + private int index; + + public ScrollPattern(BrushTool tool, Pattern... patterns) { + super(tool); + this.patterns = patterns; + } + + + @Override + public boolean increment(int amount) { + if (patterns.length > 1) { + tool.setFill(patterns[MathMan.wrap(index += amount, 0, patterns.length - 1)]); + return true; + } + return false; + } +} \ No newline at end of file diff --git a/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollRange.java b/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollRange.java new file mode 100644 index 00000000..066f0766 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollRange.java @@ -0,0 +1,19 @@ +package com.boydti.fawe.object.brush.scroll; + +import com.boydti.fawe.util.MathMan; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.tool.BrushTool; + +public class ScrollRange extends ScrollAction { + public ScrollRange(BrushTool tool) { + super(tool); + } + + @Override + public boolean increment(int amount) { + int max = WorldEdit.getInstance().getConfiguration().maxBrushRadius; + int newSize = MathMan.wrap(tool.getRange() + amount, (int) (tool.getSize() + 1), max); + tool.setRange(newSize); + return true; + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollSize.java b/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollSize.java new file mode 100644 index 00000000..d10a9415 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollSize.java @@ -0,0 +1,18 @@ +package com.boydti.fawe.object.brush.scroll; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.tool.BrushTool; + +public class ScrollSize extends ScrollAction { + public ScrollSize(BrushTool tool) { + super(tool); + } + + @Override + public boolean increment(int amount) { + int max = WorldEdit.getInstance().getConfiguration().maxRadius; + double newSize = Math.max(0, Math.min(max, tool.getSize() + amount)); + tool.setSize(newSize); + return true; + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollableBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollableBrush.java new file mode 100644 index 00000000..d04a9af5 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollableBrush.java @@ -0,0 +1,5 @@ +package com.boydti.fawe.object.brush.scroll; + +public interface ScrollableBrush { + public boolean increment(int amount); +} diff --git a/core/src/main/java/com/boydti/fawe/object/brush/visualization/DelegateVisualBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/visualization/DelegateVisualBrush.java new file mode 100644 index 00000000..adddc602 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/brush/visualization/DelegateVisualBrush.java @@ -0,0 +1,32 @@ +package com.boydti.fawe.object.brush.visualization; + +import com.boydti.fawe.object.brush.DoubleActionBrush; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.command.tool.BrushTool; +import com.sk89q.worldedit.command.tool.brush.Brush; +import com.sk89q.worldedit.function.pattern.Pattern; + +public class DelegateVisualBrush extends VisualBrush { + private final Brush brush; + + public DelegateVisualBrush(BrushTool tool, Brush brush) { + super(tool); + this.brush = brush; + } + + @Override + public void build(BrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException { + switch (action) { + case PRIMARY: + brush.build(editSession, position, pattern, size); + break; + case SECONDARY: + if (brush instanceof DoubleActionBrush) { + ((DoubleActionBrush) brush).build(BrushTool.BrushAction.SECONDARY, editSession, position, pattern, size); + } + break; + } + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualBrush.java new file mode 100644 index 00000000..94a63abf --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualBrush.java @@ -0,0 +1,142 @@ +package com.boydti.fawe.object.brush.visualization; + +import com.boydti.fawe.Fawe; +import com.boydti.fawe.FaweCache; +import com.boydti.fawe.object.FawePlayer; +import com.boydti.fawe.object.brush.DoubleActionBrush; +import com.boydti.fawe.object.brush.MovableBrush; +import com.boydti.fawe.object.brush.TargetMode; +import com.boydti.fawe.object.brush.scroll.ScrollableBrush; +import com.boydti.fawe.util.EditSessionBuilder; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.command.tool.BrushTool; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.util.Location; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +public abstract class VisualBrush implements DoubleActionBrush, MovableBrush, ScrollableBrush { + + private Lock lock = new ReentrantLock(); + private final BrushTool tool; + private VisualExtent visualExtent; + private TargetMode mode; + + public VisualBrush(BrushTool tool) { + this.tool = tool; + this.mode = TargetMode.TARGET_POINT_RANGE; + } + + public BrushTool getTool() { + return tool; + } + + public TargetMode getMode() { + return mode; + } + + public void setMode(TargetMode mode) { + this.mode = mode; + } + + @Override + public abstract void build(BrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException; + + public Vector getPosition(EditSession editSession, Player player) { + switch (mode) { + case TARGET_BLOCK_RANGE: + return player.getBlockTrace(tool.getRange(), false); + case FOWARD_POINT_PITCH: { + int d = 0; + Location loc = player.getLocation(); + float pitch = loc.getPitch(); + pitch = 23 - (pitch / 4); + d += (int) (Math.sin(Math.toRadians(pitch)) * 50); + final Vector vector = loc.getDirection().setY(0).normalize().multiply(d); + vector.add(loc.getX(), loc.getY(), loc.getZ()).toBlockVector(); + return vector; + } + case TARGET_POINT_HEIGHT: { + Location loc = player.getLocation(); + final int height = loc.getBlockY(); + final int x = loc.getBlockX(); + final int z = loc.getBlockZ(); + int y; + for (y = height; y > 0; y--) { + BaseBlock block = editSession.getBlock(x, y, z); + if (!FaweCache.isLiquidOrGas(block.getId())) { + break; + } + } + final int distance = (height - y) + 8; + return player.getBlockTrace(distance, true); + } + case TARGET_POINT_RANGE: + return player.getBlockTrace(tool.getRange(), true); + default: + return null; + } + } + + public void queueVisualization(FawePlayer player) { + Fawe.get().getVisualQueue().queue(player); + } + + /** + * Visualize the brush action + * @deprecated It is preferred to visualize only if a visualization is not in progress + * @param action + * @param player + * @throws MaxChangedBlocksException + */ + @Deprecated + public synchronized void visualize(BrushTool.BrushAction action, Player player) throws MaxChangedBlocksException { + FawePlayer fp = FawePlayer.wrap(player); + EditSession editSession = new EditSessionBuilder(player.getWorld()) + .player(fp) + .allowedRegionsEverywhere() + .autoQueue(false) + .blockBag(null) + .changeSetNull() + .combineStages(false) + .build(); + VisualExtent newVisualExtent = new VisualExtent(editSession.getExtent(), editSession.getQueue()); + editSession.setExtent(newVisualExtent); + Vector position = getPosition(editSession, player); + if (position != null) { + build(BrushTool.BrushAction.PRIMARY, editSession, position, tool.getMaterial(), tool.getSize()); + } + if (visualExtent != null) { + // clear old data + visualExtent.clear(newVisualExtent, fp); + } + visualExtent = newVisualExtent; + newVisualExtent.visualize(fp); + } + + public void clear(Player player) { + FawePlayer fp = FawePlayer.wrap(player); + Fawe.get().getVisualQueue().dequeue(fp); + if (visualExtent != null) { + visualExtent.clear(null, fp); + } + } + + @Override + public boolean move(Player player) { + return true; + } + + @Override + public boolean increment(int amount) { + int max = WorldEdit.getInstance().getConfiguration().maxBrushRadius; + double newSize = Math.max(0, Math.min(max, tool.getSize() + amount)); + tool.setSize(newSize); + return true; + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualChunk.java b/core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualChunk.java new file mode 100644 index 00000000..a144abf1 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualChunk.java @@ -0,0 +1,171 @@ +package com.boydti.fawe.object.brush.visualization; + +import com.boydti.fawe.object.FaweChunk; +import com.boydti.fawe.object.collection.SparseBitSet; +import com.boydti.fawe.object.visitor.FaweChunkVisitor; +import com.boydti.fawe.util.MathMan; +import com.sk89q.jnbt.CompoundTag; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +/** + * FAWE visualizations display glass (20) as a placeholder + * - Using a non transparent block can cause FPS lag + */ +public class VisualChunk extends FaweChunk { + + public static int VISUALIZE_BLOCK = (95 << 4); + + private SparseBitSet add; + private SparseBitSet remove; + + /** + * A FaweSections object represents a chunk and the blocks that you wish to change in it. + * + * @param x + * @param z + */ + public VisualChunk(int x, int z) { + super(null, x, z); + this.add = new SparseBitSet(); + this.remove = new SparseBitSet(); + } + + protected VisualChunk(int x, int z, SparseBitSet add, SparseBitSet remove) { + super(null, x, z); + this.add = add; + this.remove = remove; + } + + public int size() { + return add.cardinality() + remove.cardinality(); + } + + private final int getIndex(int x, int y, int z) { + return MathMan.tripleBlockCoordChar(x, y, z); + } + + @Override + public int getBitMask() { + return 0; + } + + @Override + public int getBlockCombinedId(int x, int y, int z) { + int index = getIndex(x, y, z); + if (add.get(index)) { + return VISUALIZE_BLOCK; + } else if (remove.get(index)) { + return 1; + } else { + return 0; + } + } + + @Override + public void forEachQueuedBlock(FaweChunkVisitor onEach) { + int index = -1; + while ((index = add.nextSetBit(index + 1)) != -1) { + int x = MathMan.untripleBlockCoordX(index); + int y = MathMan.untripleBlockCoordY(index); + int z = MathMan.untripleBlockCoordZ(index); + onEach.run(x, y, z, VISUALIZE_BLOCK); + } + index = -1; + while ((index = remove.nextSetBit(index + 1)) != -1) { + int x = MathMan.untripleBlockCoordX(index); + int y = MathMan.untripleBlockCoordY(index); + int z = MathMan.untripleBlockCoordZ(index); + onEach.run(x, y, z, 1); + } + } + + @Override + public byte[] getBiomeArray() { + return new byte[256]; + } + + @Override + public FaweChunk getChunk() { + return this; + } + + @Override + public void setTile(int x, int y, int z, CompoundTag tile) { + // Unsupported + } + + @Override + public void setEntity(CompoundTag entity) { + // Unsupported + } + + @Override + public void removeEntity(UUID uuid) { + // Unsupported + } + + @Override + public void setBlock(int x, int y, int z, int id, int data) { + int index = getIndex(x, y, z); + try { + if (id == 0) { + add.clear(index); + remove.set(index); + } else { + remove.clear(index); + add.set(index); + } + } catch (Throwable e) { + e.printStackTrace(); + } + } + + public void unset(int x, int y, int z) { + int index = getIndex(x, y, z); + remove.clear(index); + add.clear(index); + } + + @Override + public Set getEntities() { + return new HashSet<>(); + } + + @Override + public Set getEntityRemoves() { + return new HashSet<>(); + } + + @Override + public Map getTiles() { + return new HashMap<>(); + } + + @Override + public CompoundTag getTile(int x, int y, int z) { + return null; + } + + @Override + public void setBiome(int x, int z, byte biome) { + // Unsupported + } + + @Override + public FaweChunk copy(boolean shallow) { + if (shallow) { + return new VisualChunk(getX(), getZ(), add, remove); + } else { + return new VisualChunk(getX(), getZ(), add.clone(), remove.clone()); + } + } + + @Override + public FaweChunk call() { + return this; + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualExtent.java b/core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualExtent.java new file mode 100644 index 00000000..470887fa --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualExtent.java @@ -0,0 +1,110 @@ +package com.boydti.fawe.object.brush.visualization; + +import com.boydti.fawe.FaweCache; +import com.boydti.fawe.example.CharFaweChunk; +import com.boydti.fawe.example.NullQueueCharFaweChunk; +import com.boydti.fawe.object.FawePlayer; +import com.boydti.fawe.object.FaweQueue; +import com.boydti.fawe.object.visitor.FaweChunkVisitor; +import com.boydti.fawe.util.MathMan; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.world.biome.BaseBiome; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectIterator; + +public class VisualExtent extends AbstractDelegateExtent { + + private final FaweQueue queue; + private Long2ObjectMap chunks = new Long2ObjectOpenHashMap<>(); + + public VisualExtent(Extent parent, FaweQueue queue) { + super(parent); + this.queue = queue; + } + + @Override + public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException { + return setBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ(), block); + } + + public VisualChunk getChunk(int cx, int cz) { + return chunks.get(MathMan.pairInt(cx, cz)); + } + + @Override + public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException { + BaseBlock previous = super.getLazyBlock(x, y, z); + int cx = x >> 4; + int cz = z >> 4; + long chunkPair = MathMan.pairInt(cx, cz); + VisualChunk chunk = chunks.get(chunkPair); + if (previous.equals(block)) { + if (chunk != null) { + chunk.unset(x, y, z); + } + return false; + } else { + if (chunk == null) { + chunk = new VisualChunk(cx, cz); + chunks.put(chunkPair, chunk); + } + chunk.setBlock(x, y, z, block.getId(), block.getData()); + return true; + } + } + + @Override + public boolean setBiome(Vector2D position, BaseBiome biome) { + // Do nothing + return false; + } + + public void clear(VisualExtent other, FawePlayer... players) { + ObjectIterator> iter = chunks.long2ObjectEntrySet().iterator(); + while (iter.hasNext()) { + Long2ObjectMap.Entry entry = iter.next(); + long pair = entry.getLongKey(); + int cx = MathMan.unpairIntX(pair); + int cz = MathMan.unpairIntY(pair); + VisualChunk chunk = entry.getValue(); + final VisualChunk otherChunk = other != null ? other.getChunk(cx, cz) : null; + final CharFaweChunk newChunk = new NullQueueCharFaweChunk(cx, cz); + final int bx = cx << 4; + final int bz = cz << 4; + if (otherChunk == null) { + chunk.forEachQueuedBlock(new FaweChunkVisitor() { + @Override + public void run(int localX, int y, int localZ, int combined) { + combined = queue.getCombinedId4Data(bx + localX, y, bz + localZ, 0); + newChunk.setBlock(localX, y, localZ, FaweCache.getId(combined), FaweCache.getData(combined)); + } + }); + } else { + chunk.forEachQueuedBlock(new FaweChunkVisitor() { + @Override + public void run(int localX, int y, int localZ, int combined) { + if (combined != otherChunk.getBlockCombinedId(localX, y, localZ)) { + combined = queue.getCombinedId4Data(bx + localX, y, bz + localZ, 0); + newChunk.setBlock(localX, y, localZ, FaweCache.getId(combined), FaweCache.getData(combined)); + } + } + }); + } + if (newChunk.getTotalCount() != 0) { + queue.sendBlockUpdate(newChunk, players); + } + } + } + + public void visualize(FawePlayer players) { + for (VisualChunk chunk : chunks.values()) { + queue.sendBlockUpdate(chunk, players); + } + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualMode.java b/core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualMode.java new file mode 100644 index 00000000..8979312e --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualMode.java @@ -0,0 +1,7 @@ +package com.boydti.fawe.object.brush.visualization; + +public enum VisualMode { + NONE, + POINT, + OUTLINE +} diff --git a/core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualQueue.java b/core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualQueue.java new file mode 100644 index 00000000..9affa8f8 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualQueue.java @@ -0,0 +1,66 @@ +package com.boydti.fawe.object.brush.visualization; + +import com.boydti.fawe.Fawe; +import com.boydti.fawe.object.FawePlayer; +import com.boydti.fawe.util.TaskManager; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.tool.BrushTool; +import com.sk89q.worldedit.command.tool.Tool; +import com.sk89q.worldedit.command.tool.brush.Brush; +import com.sk89q.worldedit.entity.Player; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class VisualQueue { + + private ConcurrentHashMap playerMap; + + public VisualQueue() { + playerMap = new ConcurrentHashMap<>(); + Runnable task = new Runnable() { + @Override + public void run() { + long allowedTick = Fawe.get().getTimer().getTick() - 1; + Iterator> iter = playerMap.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = iter.next(); + Long time = entry.getValue(); + if (time < allowedTick) { + FawePlayer fp = entry.getKey(); + iter.remove(); + LocalSession session = fp.getSession(); + Player player = fp.getPlayer(); + Tool tool = session.getTool(player.getItemInHand()); + Brush brush; + if (tool instanceof BrushTool) { + brush = ((BrushTool) tool).getBrush(); + } else if (tool instanceof VisualBrush) { + brush = (Brush) tool; + } else { + continue; + } + if (brush instanceof VisualBrush) { + try { + ((VisualBrush) brush).visualize(BrushTool.BrushAction.PRIMARY, player); + } catch (Throwable e) { + WorldEdit.getInstance().getPlatformManager().handleThrowable(e, player); + } + } + } + } + TaskManager.IMP.laterAsync(this, 3); + } + }; + TaskManager.IMP.laterAsync(task, 3); + } + + public boolean dequeue(FawePlayer player) { + return playerMap.remove(player) != null; + } + + public void queue(FawePlayer player) { + playerMap.put(player, Fawe.get().getTimer().getTick()); + } +} \ No newline at end of file diff --git a/core/src/main/java/com/boydti/fawe/object/changeset/DiskStorageHistory.java b/core/src/main/java/com/boydti/fawe/object/changeset/DiskStorageHistory.java index a9827528..cbf860fb 100644 --- a/core/src/main/java/com/boydti/fawe/object/changeset/DiskStorageHistory.java +++ b/core/src/main/java/com/boydti/fawe/object/changeset/DiskStorageHistory.java @@ -75,19 +75,8 @@ public class DiskStorageHistory extends FaweStreamChangeSet { private void init(UUID uuid, String worldName) { File folder = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.HISTORY + File.separator + worldName + File.separator + uuid); - int max = 0; - if (folder.exists()) { - for (File file : folder.listFiles()) { - String name = file.getName().split("\\.")[0]; - if (name.matches("\\d+")) { - int index = Integer.parseInt(name); - if (index > max) { - max = index; - } - } - } - } - init(uuid, ++max); + int max = MainUtil.getMaxFileId(folder); + init(uuid, max); } public DiskStorageHistory(String world, UUID uuid, int index) { diff --git a/core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java b/core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java index 62f1e0c2..9d84c618 100644 --- a/core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java +++ b/core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java @@ -69,6 +69,11 @@ public abstract class FaweChangeSet implements ChangeSet { return world; } + @Deprecated + public boolean flushAsync() { + return closeAsync(); + } + public boolean closeAsync() { waitingAsync.incrementAndGet(); TaskManager.IMP.async(new Runnable() { diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/WorldCopyClipboard.java b/core/src/main/java/com/boydti/fawe/object/clipboard/WorldCopyClipboard.java index 183dda68..815066c6 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/WorldCopyClipboard.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/WorldCopyClipboard.java @@ -53,6 +53,7 @@ public class WorldCopyClipboard extends ReadOnlyClipboard { final Vector pos = new Vector(); if (region instanceof CuboidRegion) { if (air) { + ((CuboidRegion) region).setUseOldIterator(true); RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() { @Override public boolean apply(Vector pos) throws WorldEditException { @@ -76,27 +77,33 @@ public class WorldCopyClipboard extends ReadOnlyClipboard { }, editSession); Operations.completeBlindly(visitor); } else { - RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() { + CuboidRegion cuboidEquivalent = new CuboidRegion(region.getMinimumPoint(), region.getMaximumPoint()); + cuboidEquivalent.setUseOldIterator(true); + RegionVisitor visitor = new RegionVisitor(cuboidEquivalent, new RegionFunction() { @Override public boolean apply(Vector pos) throws WorldEditException { - int x = pos.getBlockX(); - int y = pos.getBlockY(); - int z = pos.getBlockZ(); - BaseBlock block = getBlockAbs(x, y, z); - if (block == EditSession.nullBlock) { - return false; + if (region.contains(pos)) { + int x = pos.getBlockX(); + int y = pos.getBlockY(); + int z = pos.getBlockZ(); + BaseBlock block = getBlockAbs(x, y, z); + pos.mutX(x - mx); + pos.mutY(y - my); + pos.mutZ(z - mz); + CompoundTag tag = block.getNbtData(); + if (tag != null) { + Map values = ReflectionUtils.getMap(tag.getValue()); + values.put("x", new IntTag(pos.getBlockX())); + values.put("y", new IntTag(pos.getBlockY())); + values.put("z", new IntTag(pos.getBlockZ())); + } + task.run(pos, block); + } else { + pos.mutX(pos.getBlockX() - mx); + pos.mutY(pos.getBlockY() - my); + pos.mutZ(pos.getBlockZ() - mz); + task.run(pos, EditSession.nullBlock); } - pos.mutX(x - mx); - pos.mutY(y - my); - pos.mutZ(z - mz); - CompoundTag tag = block.getNbtData(); - if (tag != null) { - Map values = ReflectionUtils.getMap(tag.getValue()); - values.put("x", new IntTag(pos.getBlockX())); - values.put("y", new IntTag(pos.getBlockY())); - values.put("z", new IntTag(pos.getBlockZ())); - } - task.run(pos, block); return true; } }, editSession); diff --git a/core/src/main/java/com/boydti/fawe/object/io/PGZIPBlock.java b/core/src/main/java/com/boydti/fawe/object/io/PGZIPBlock.java new file mode 100644 index 00000000..25cc6248 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/io/PGZIPBlock.java @@ -0,0 +1,43 @@ +package com.boydti.fawe.object.io; + +import java.util.concurrent.Callable; + +public class PGZIPBlock implements Callable { + public PGZIPBlock(final PGZIPOutputStream parent) { + STATE = new PGZIPThreadLocal(parent); + } + + /** This ThreadLocal avoids the recycling of a lot of memory, causing lumpy performance. */ + protected final ThreadLocal STATE; + public static final int SIZE = 64 * 1024; + // private final int index; + protected final byte[] in = new byte[SIZE]; + protected int in_length = 0; + + /* + public Block(@Nonnegative int index) { + this.index = index; + } + */ + // Only on worker thread + @Override + public byte[] call() throws Exception { + // LOG.info("Processing " + this + " on " + Thread.currentThread()); + + PGZIPState state = STATE.get(); + // ByteArrayOutputStream buf = new ByteArrayOutputStream(in.length); // Overestimate output size required. + // DeflaterOutputStream def = newDeflaterOutputStream(buf); + state.def.reset(); + state.buf.reset(); + state.str.write(in, 0, in_length); + state.str.flush(); + + // return Arrays.copyOf(in, in_length); + return state.buf.toByteArray(); + } + + @Override + public String toString() { + return "Block" /* + index */ + "(" + in_length + "/" + in.length + " bytes)"; + } +} \ No newline at end of file diff --git a/core/src/main/java/com/boydti/fawe/object/io/PGZIPOutputStream.java b/core/src/main/java/com/boydti/fawe/object/io/PGZIPOutputStream.java index 259f88eb..fccb2a4b 100644 --- a/core/src/main/java/com/boydti/fawe/object/io/PGZIPOutputStream.java +++ b/core/src/main/java/com/boydti/fawe/object/io/PGZIPOutputStream.java @@ -37,7 +37,7 @@ public class PGZIPOutputStream extends FilterOutputStream { private int strategy = Deflater.HUFFMAN_ONLY; @Nonnull - private Deflater newDeflater() { + protected Deflater newDeflater() { Deflater def = new Deflater(level, true); def.setStrategy(strategy); return def; @@ -52,63 +52,16 @@ public class PGZIPOutputStream extends FilterOutputStream { } @Nonnull - private static DeflaterOutputStream newDeflaterOutputStream(@Nonnull OutputStream out, @Nonnull Deflater deflater) { + protected static DeflaterOutputStream newDeflaterOutputStream(@Nonnull OutputStream out, @Nonnull Deflater deflater) { return new DeflaterOutputStream(out, deflater, 512, true); } - private class Block implements Callable { - - private class State { - - private final Deflater def = newDeflater(); - private final ByteArrayOutputStream buf = new ByteArrayOutputStream(SIZE); - private final DeflaterOutputStream str = newDeflaterOutputStream(buf, def); - } - /** This ThreadLocal avoids the recycling of a lot of memory, causing lumpy performance. */ - private final ThreadLocal STATE = new ThreadLocal() { - @Override - protected State initialValue() { - return new State(); - } - }; - public static final int SIZE = 64 * 1024; - // private final int index; - private final byte[] in = new byte[SIZE]; - private int in_length = 0; - - /* - public Block(@Nonnegative int index) { - this.index = index; - } - */ - // Only on worker thread - @Override - public byte[] call() throws Exception { - // LOG.info("Processing " + this + " on " + Thread.currentThread()); - - State state = STATE.get(); - // ByteArrayOutputStream buf = new ByteArrayOutputStream(in.length); // Overestimate output size required. - // DeflaterOutputStream def = newDeflaterOutputStream(buf); - state.def.reset(); - state.buf.reset(); - state.str.write(in, 0, in_length); - state.str.flush(); - - // return Arrays.copyOf(in, in_length); - return state.buf.toByteArray(); - } - - @Override - public String toString() { - return "Block" /* + index */ + "(" + in_length + "/" + in.length + " bytes)"; - } - } // TODO: Share, daemonize. private final ExecutorService executor; private final int nthreads; private final CRC32 crc = new CRC32(); private final BlockingQueue> emitQueue; - private Block block = new Block(/* 0 */); + private PGZIPBlock block = new PGZIPBlock(this/* 0 */); /** Used as a sentinel for 'closed'. */ private int bytesWritten = 0; @@ -201,7 +154,7 @@ public class PGZIPOutputStream extends FilterOutputStream { private void submit() throws IOException { emitUntil(nthreads - 1); emitQueue.add(executor.submit(block)); - block = new Block(/* block.index + 1 */); + block = new PGZIPBlock(this/* block.index + 1 */); } // Emit If Available - submit always diff --git a/core/src/main/java/com/boydti/fawe/object/io/PGZIPState.java b/core/src/main/java/com/boydti/fawe/object/io/PGZIPState.java new file mode 100644 index 00000000..8e31eda7 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/io/PGZIPState.java @@ -0,0 +1,19 @@ +package com.boydti.fawe.object.io; + +import java.io.ByteArrayOutputStream; +import java.util.zip.Deflater; +import java.util.zip.DeflaterOutputStream; + +public class PGZIPState { + protected final DeflaterOutputStream str; + protected final ByteArrayOutputStream buf; + protected final Deflater def; + + public PGZIPState(PGZIPOutputStream parent) { + this.def = parent.newDeflater(); + this.buf = new ByteArrayOutputStream(PGZIPBlock.SIZE); + this.str = parent.newDeflaterOutputStream(buf, def); + } + + +} diff --git a/core/src/main/java/com/boydti/fawe/object/io/PGZIPThreadLocal.java b/core/src/main/java/com/boydti/fawe/object/io/PGZIPThreadLocal.java new file mode 100644 index 00000000..de3c0721 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/io/PGZIPThreadLocal.java @@ -0,0 +1,15 @@ +package com.boydti.fawe.object.io; + +public class PGZIPThreadLocal extends ThreadLocal { + + private final PGZIPOutputStream parent; + + public PGZIPThreadLocal(PGZIPOutputStream parent) { + this.parent = parent; + } + + @Override + protected PGZIPState initialValue() { + return new PGZIPState(parent); + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/visitor/FaweChunkVisitor.java b/core/src/main/java/com/boydti/fawe/object/visitor/FaweChunkVisitor.java new file mode 100644 index 00000000..79daa889 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/visitor/FaweChunkVisitor.java @@ -0,0 +1,12 @@ +package com.boydti.fawe.object.visitor; + +public abstract class FaweChunkVisitor { + /** + * The will run for each set block in the chunk + * @param localX The x position in the chunk (0-15) + * @param y The y position (0 - 255) + * @param localZ The z position in the chunk (0-15) + * @param combined The combined id + */ + public abstract void run(int localX, int y, int localZ, int combined); +} diff --git a/core/src/main/java/com/boydti/fawe/util/DelegateFaweQueue.java b/core/src/main/java/com/boydti/fawe/util/DelegateFaweQueue.java index ca2509ab..6ffb0245 100644 --- a/core/src/main/java/com/boydti/fawe/util/DelegateFaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/util/DelegateFaweQueue.java @@ -16,7 +16,6 @@ import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BaseBiome; import java.io.File; import java.util.Collection; -import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentLinkedDeque; @@ -222,8 +221,8 @@ public class DelegateFaweQueue extends FaweQueue { } @Override - public void sendBlockUpdate(Map> blockMap, FawePlayer... players) { - parent.sendBlockUpdate(blockMap, players); + public void sendBlockUpdate(FaweChunk chunk, FawePlayer... players) { + parent.sendBlockUpdate(chunk, players); } @Deprecated diff --git a/core/src/main/java/com/boydti/fawe/util/MainUtil.java b/core/src/main/java/com/boydti/fawe/util/MainUtil.java index efa4dbfd..09af0afd 100644 --- a/core/src/main/java/com/boydti/fawe/util/MainUtil.java +++ b/core/src/main/java/com/boydti/fawe/util/MainUtil.java @@ -56,6 +56,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.zip.GZIPInputStream; import java.util.zip.ZipEntry; @@ -180,6 +181,29 @@ public class MainUtil { } } + public static int getMaxFileId(File folder) { + final AtomicInteger max = new AtomicInteger(); + if (folder.exists()) { + MainUtil.traverse(folder.toPath(), new RunnableVal2() { + @Override + public void run(Path path, BasicFileAttributes attr) { + try { + String file = path.getFileName().toString(); + int index = file.indexOf('.'); + if (index == -1) { + return; + } + int id = Integer.parseInt(file.substring(0, index)); + if (id > max.get()) { + max.set(id); + } + } catch (NumberFormatException ignore){} + } + }); + } + return max.get() + 1; + } + public static File getFile(File base, String path) { if (Paths.get(path).isAbsolute()) { return new File(path); diff --git a/core/src/main/java/com/boydti/fawe/util/MathMan.java b/core/src/main/java/com/boydti/fawe/util/MathMan.java index 31649a18..4dac4b72 100644 --- a/core/src/main/java/com/boydti/fawe/util/MathMan.java +++ b/core/src/main/java/com/boydti/fawe/util/MathMan.java @@ -43,6 +43,20 @@ public class MathMan { 253, 254, 254, 255 }; + public static final int wrap(int value, int min, int max) { + if (max <= min) { + return value; + } + int diff = max - min + 1; + if (value < min) { + return max - ((min - value) % diff); + } else if (value > max) { + return min + ((value - min) % diff); + } else { + return value; + } + } + public static final long inverseRound(double val) { long round = Math.round(val); return (long) (round + Math.signum(val - round)); @@ -84,6 +98,22 @@ public class MathMan { return (short) ((x & 15) << 12 | (z & 15) << 8 | y); } + public static final char tripleBlockCoordChar(int x, int y, int z) { + return (char) ((x & 15) << 12 | (z & 15) << 8 | y); + } + + public static final int untripleBlockCoordX(int triple) { + return (triple >> 12) & 0xF; + } + + public static final int untripleBlockCoordY(int triple) { + return (triple & 0xFF); + } + + public static final int untripleBlockCoordZ(int triple) { + return (triple >> 8) & 0xF; + } + public static int tripleSearchCoords(int x, int y, int z) { byte b1 = (byte) y; byte b3 = (byte) (x); diff --git a/core/src/main/java/com/boydti/fawe/util/Updater.java b/core/src/main/java/com/boydti/fawe/util/Updater.java index 25b393bb..e97c6d1a 100644 --- a/core/src/main/java/com/boydti/fawe/util/Updater.java +++ b/core/src/main/java/com/boydti/fawe/util/Updater.java @@ -4,15 +4,21 @@ import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweVersion; import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; import java.net.URL; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.util.Scanner; public class Updater { - private static FaweVersion newVersion = null; + private FaweVersion newVersion; + private String changes = "N/A"; - public static void update(String platform, FaweVersion currentVersion) { + public String getChanges() throws IOException { + return changes; + } + + public void update(String platform, FaweVersion currentVersion) { if (currentVersion == null || platform == null) { return; } @@ -42,7 +48,11 @@ public class Updater { fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); } Fawe.debug("Updated FAWE to " + versionString); - MainUtil.sendAdmin("Restart to update FAWE with these changes: " + "http://boydti.com/fawe/cl?" + Integer.toHexString(Fawe.get().getVersion().hash)); + Scanner scanner = new Scanner(new URL("http://boydti.com/fawe/cl?" + Integer.toHexString(Fawe.get().getVersion().hash)).openStream(), "UTF-8"); + changes = scanner.useDelimiter("\\A").next(); + scanner.close(); + MainUtil.sendAdmin("&7Restart to update FAWE with these changes: &c/fawe changelog &7or&c " + "http://boydti.com/fawe/cl?" + Integer.toHexString(currentVersion.hash)); + } } } diff --git a/core/src/main/java/com/boydti/fawe/wrappers/FakePlayer.java b/core/src/main/java/com/boydti/fawe/wrappers/FakePlayer.java index 4d8cd041..d8cd8d2d 100644 --- a/core/src/main/java/com/boydti/fawe/wrappers/FakePlayer.java +++ b/core/src/main/java/com/boydti/fawe/wrappers/FakePlayer.java @@ -122,7 +122,7 @@ public class FakePlayer extends LocalPlayer { } @Override - public Player getPlayer() { + public Player toWorldEditPlayer() { return FakePlayer.this; } }; diff --git a/core/src/main/java/com/sk89q/worldedit/BlockVector.java b/core/src/main/java/com/sk89q/worldedit/BlockVector.java index 84d2e162..20965c52 100644 --- a/core/src/main/java/com/sk89q/worldedit/BlockVector.java +++ b/core/src/main/java/com/sk89q/worldedit/BlockVector.java @@ -84,6 +84,10 @@ public class BlockVector extends Vector { } + public boolean equals(BlockVector obj) { + return obj.getBlockX() == this.getBlockX() && obj.getBlockY() == this.getBlockY() && obj.getBlockZ() == this.getBlockZ(); + } + @Override public int hashCode() { return ((int) getX() ^ ((int) getZ() << 16)) ^ ((int) getY() << 30); diff --git a/core/src/main/java/com/sk89q/worldedit/CuboidClipboard.java b/core/src/main/java/com/sk89q/worldedit/CuboidClipboard.java index 509e756e..d475cf5a 100644 --- a/core/src/main/java/com/sk89q/worldedit/CuboidClipboard.java +++ b/core/src/main/java/com/sk89q/worldedit/CuboidClipboard.java @@ -454,14 +454,14 @@ public class CuboidClipboard { } if (reverse) { for (int i = 0; i < numRotations; ++i) { - if (block.hasWildcardData()) { + if (block.isImmutable()) { block = new BaseBlock(block); } block.rotate90Reverse(); } } else { for (int i = 0; i < numRotations; ++i) { - if (block.hasWildcardData()) { + if (block.isImmutable()) { block = new BaseBlock(block); } block.rotate90(); diff --git a/core/src/main/java/com/sk89q/worldedit/EditSession.java b/core/src/main/java/com/sk89q/worldedit/EditSession.java index 649d230d..97dbd95a 100644 --- a/core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -415,6 +415,22 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting return traverser == null ? null : traverser.get(); } + public Extent getBypassAll() { + return bypassAll; + } + + public Extent getBypassHistory() { + return bypassHistory; + } + + public Extent getExtent() { + return extent; + } + + public void setExtent(AbstractDelegateExtent extent) { + this.extent = extent; + } + /** * Get the FawePlayer or null * @return @@ -2151,20 +2167,26 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting final double invRadiusX = 1 / radiusX; final double invRadiusZ = 1 / radiusZ; + int px = pos.getBlockX(); + int py = pos.getBlockY(); + int pz = pos.getBlockZ(); + MutableBlockVector mutable = new MutableBlockVector(); + final int ceilRadiusX = (int) Math.ceil(radiusX); final int ceilRadiusZ = (int) Math.ceil(radiusZ); - + double dx, dxz, dz; double nextXn = 0; forX: for (int x = 0; x <= ceilRadiusX; ++x) { final double xn = nextXn; nextXn = (x + 1) * invRadiusX; double nextZn = 0; + dx = xn * xn; forZ: for (int z = 0; z <= ceilRadiusZ; ++z) { final double zn = nextZn; nextZn = (z + 1) * invRadiusZ; - - final double distanceSq = this.lengthSq(xn, zn); - if (distanceSq > 1) { + dz = zn * zn; + dxz = dx + dz; + if (dxz > 1) { if (z == 0) { break forX; } @@ -2172,16 +2194,16 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting } if (!filled) { - if ((this.lengthSq(nextXn, zn) <= 1) && (this.lengthSq(xn, nextZn) <= 1)) { + if ((dz + nextXn * nextXn <= 1) && (nextZn * nextZn + dx <= 1)) { continue; } } for (int y = 0; y < height; ++y) { - this.setBlock(pos.add(x, y, z), block); - this.setBlock(pos.add(-x, y, z), block); - this.setBlock(pos.add(x, y, -z), block); - this.setBlock(pos.add(-x, y, -z), block); + this.setBlock(mutable.setComponents(px + x, py + y, pz + z), block); + this.setBlock(mutable.setComponents(px - x, py + y, pz + z), block); + this.setBlock(mutable.setComponents(px + x, py + y, pz - z), block); + this.setBlock(mutable.setComponents(px - x, py + y, pz - z), block); } } } @@ -2189,6 +2211,82 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting return this.changes; } + public int makeCircle(Vector pos, final Pattern block, double radiusX, double radiusY, double radiusZ, boolean filled, Vector normal) throws MaxChangedBlocksException { + radiusX += 0.5; + radiusY += 0.5; + radiusZ += 0.5; + + normal = normal.normalize(); + double nx = normal.getX(); + double ny = normal.getY(); + double nz = normal.getZ(); + + + final double invRadiusX = 1 / radiusX; + final double invRadiusY = 1 / radiusY; + final double invRadiusZ = 1 / radiusZ; + + int px = pos.getBlockX(); + int py = pos.getBlockY(); + int pz = pos.getBlockZ(); + MutableBlockVector mutable = new MutableBlockVector(); + + final int ceilRadiusX = (int) Math.ceil(radiusX); + final int ceilRadiusY = (int) Math.ceil(radiusY); + final int ceilRadiusZ = (int) Math.ceil(radiusZ); + + double threshold = 0.5; + + LocalBlockVectorSet set = new LocalBlockVectorSet(); + + double nextXn = 0; + double dx, dy, dz, dxy, dxyz; + forX: for (int x = 0; x <= ceilRadiusX; ++x) { + final double xn = nextXn; + dx = xn * xn; + nextXn = (x + 1) * invRadiusX; + double nextYn = 0; + forY: for (int y = 0; y <= ceilRadiusY; ++y) { + final double yn = nextYn; + dy = yn * yn; + dxy = dx + dy; + nextYn = (y + 1) * invRadiusY; + double nextZn = 0; + forZ: for (int z = 0; z <= ceilRadiusZ; ++z) { + final double zn = nextZn; + dz = zn * zn; + dxyz = dxy + dz; + nextZn = (z + 1) * invRadiusZ; + if (dxyz > 1) { + if (z == 0) { + if (y == 0) { + break forX; + } + break forY; + } + break forZ; + } + if (!filled) { + if (nextXn * nextXn + dy + dz <= 1 && nextYn * nextYn + dx + dz <= 1 && nextZn * nextZn + dx + dy <= 1) { + continue; + } + } + + if (Math.abs((x) * nx + (y) * ny + (z) * nz) < threshold) setBlock(mutable.setComponents(px + x, py + y, pz + z), block); + if (Math.abs((-x) * nx + (y) * ny + (z) * nz) < threshold) setBlock(mutable.setComponents(px - x, py + y, pz + z), block); + if (Math.abs((x) * nx + (-y) * ny + (z) * nz) < threshold) setBlock(mutable.setComponents(px + x, py - y, pz + z), block); + if (Math.abs((x) * nx + (y) * ny + (-z) * nz) < threshold) setBlock(mutable.setComponents(px + x, py + y, pz - z), block); + if (Math.abs((-x) * nx + (-y) * ny + (z) * nz) < threshold) setBlock(mutable.setComponents(px - x, py - y, pz + z), block); + if (Math.abs((x) * nx + (-y) * ny + (-z) * nz) < threshold) setBlock(mutable.setComponents(px + x, py - y, pz - z), block); + if (Math.abs((-x) * nx + (y) * ny + (-z) * nz) < threshold) setBlock(mutable.setComponents(px - x, py + y, pz - z), block); + if (Math.abs((-x) * nx + (-y) * ny + (-z) * nz) < threshold) setBlock(mutable.setComponents(px - x, py - y, pz - z), block); + } + } + } + + return changes; + } + /** * Makes a sphere. * @@ -2224,25 +2322,34 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting final double invRadiusY = 1 / radiusY; final double invRadiusZ = 1 / radiusZ; + int px = pos.getBlockX(); + int py = pos.getBlockY(); + int pz = pos.getBlockZ(); + MutableBlockVector mutable = new MutableBlockVector(); + final int ceilRadiusX = (int) Math.ceil(radiusX); final int ceilRadiusY = (int) Math.ceil(radiusY); final int ceilRadiusZ = (int) Math.ceil(radiusZ); double nextXn = 0; + double dx, dy, dz, dxy, dxyz; forX: for (int x = 0; x <= ceilRadiusX; ++x) { final double xn = nextXn; + dx = xn * xn; nextXn = (x + 1) * invRadiusX; double nextYn = 0; forY: for (int y = 0; y <= ceilRadiusY; ++y) { final double yn = nextYn; + dy = yn * yn; + dxy = dx + dy; nextYn = (y + 1) * invRadiusY; double nextZn = 0; forZ: for (int z = 0; z <= ceilRadiusZ; ++z) { final double zn = nextZn; + dz = zn * zn; + dxyz = dxy + dz; nextZn = (z + 1) * invRadiusZ; - - final double distanceSq = this.lengthSq(xn, yn, zn); - if (distanceSq > 1) { + if (dxyz > 1) { if (z == 0) { if (y == 0) { break forX; @@ -2253,19 +2360,19 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting } if (!filled) { - if ((this.lengthSq(nextXn, yn, zn) <= 1) && (this.lengthSq(xn, nextYn, zn) <= 1) && (this.lengthSq(xn, yn, nextZn) <= 1)) { + if (nextXn * nextXn + dy + dz <= 1 && nextYn * nextYn + dx + dz <= 1 && nextZn * nextZn + dx + dy <= 1 ) { continue; } } - this.setBlock(pos.add(x, y, z), block); - this.setBlock(pos.add(-x, y, z), block); - this.setBlock(pos.add(x, -y, z), block); - this.setBlock(pos.add(x, y, -z), block); - this.setBlock(pos.add(-x, -y, z), block); - this.setBlock(pos.add(x, -y, -z), block); - this.setBlock(pos.add(-x, y, -z), block); - this.setBlock(pos.add(-x, -y, -z), block); + this.setBlock(mutable.setComponents(px + x, py + y, pz + z), block); + this.setBlock(mutable.setComponents(px - x, py + y, pz + z), block); + this.setBlock(mutable.setComponents(px + x, py - y, pz + z), block); + this.setBlock(mutable.setComponents(px + x, py + y, pz - z), block); + this.setBlock(mutable.setComponents(px - x, py - y, pz + z), block); + this.setBlock(mutable.setComponents(px + x, py - y, pz - z), block); + this.setBlock(mutable.setComponents(px - x, py + y, pz - z), block); + this.setBlock(mutable.setComponents(px - x, py - y, pz - z), block); } } } @@ -2960,9 +3067,11 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting } private Set getBallooned(final Set vset, final double radius) { + if (radius < 1) { + return vset; + } final Set returnset = new LocalBlockVectorSet(); final int ceilrad = (int) Math.ceil(radius); - for (final Vector v : vset) { final int tipx = v.getBlockX(), tipy = v.getBlockY(), tipz = v.getBlockZ(); for (int loopx = tipx - ceilrad; loopx <= (tipx + ceilrad); loopx++) { @@ -2979,6 +3088,9 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting } private Set getStretched(final Set vset, final double radius) { + if (radius < 1) { + return vset; + } final Set returnset = new LocalBlockVectorSet(); final int ceilrad = (int) Math.ceil(radius); for (final Vector v : vset) { diff --git a/core/src/main/java/com/sk89q/worldedit/LocalSession.java b/core/src/main/java/com/sk89q/worldedit/LocalSession.java index 9877d77e..742e30b3 100644 --- a/core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -25,7 +25,7 @@ import com.boydti.fawe.object.FaweInputStream; import com.boydti.fawe.object.FaweOutputStream; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.RunnableVal2; -import com.boydti.fawe.object.brush.DoubleActionBrushTool; +import com.boydti.fawe.object.brush.visualization.VisualBrush; import com.boydti.fawe.object.changeset.DiskStorageHistory; import com.boydti.fawe.object.changeset.FaweChangeSet; import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard; @@ -42,6 +42,7 @@ import com.sk89q.worldedit.command.tool.BrushTool; import com.sk89q.worldedit.command.tool.InvalidToolBindException; import com.sk89q.worldedit.command.tool.SinglePickaxe; import com.sk89q.worldedit.command.tool.Tool; +import com.sk89q.worldedit.command.tool.brush.Brush; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; @@ -440,6 +441,9 @@ public class LocalSession { } public synchronized void remember(final EditSession editSession, final boolean append, final boolean sendMessage, int limitMb) { + if (Settings.IMP.HISTORY.USE_DISK) { + LocalSession.MAX_HISTORY_SIZE = Integer.MAX_VALUE; + } // It should have already been flushed, but just in case! editSession.flushQueue(); if (editSession == null || editSession.getChangeSet() == null || limitMb == 0 || ((historySize >> 20) > limitMb && !append)) { @@ -953,6 +957,14 @@ public class LocalSession { return tools.get(item); } + @Nullable + public Tool getTool(Player player) { + if (tools.isEmpty()) { + return null; + } + return getTool(player.getItemInHand()); + } + /** * Get the brush tool assigned to the item. If there is no tool assigned * or the tool is not assigned, the slot will be replaced with the @@ -963,36 +975,20 @@ public class LocalSession { * @throws InvalidToolBindException if the item can't be bound to that item */ public BrushTool getBrushTool(int item) throws InvalidToolBindException { + return getBrushTool(item, null); + } + + public BrushTool getBrushTool(int item, Player player) throws InvalidToolBindException { Tool tool = getTool(item); if (tool == null || !(tool instanceof BrushTool)) { tool = new BrushTool("worldedit.brush.sphere"); - setTool(item, tool); + setTool(item, tool, player); } return (BrushTool) tool; } - /** - * Get the brush tool assigned to the item. If there is no tool assigned - * or the tool is not assigned, the slot will be replaced with the - * brush tool. - * - * @param item the item type ID - * @return the tool, or {@code null} - * @throws InvalidToolBindException if the item can't be bound to that item - */ - public DoubleActionBrushTool getDoubleActionBrushTool(int item) throws InvalidToolBindException { - Tool tool = getTool(item); - - if (tool == null || !(tool instanceof DoubleActionBrushTool)) { - tool = new DoubleActionBrushTool("worldedit.brush.sphere"); - setTool(item, tool); - } - - return (DoubleActionBrushTool) tool; - } - /** * Set the tool. * @@ -1001,6 +997,10 @@ public class LocalSession { * @throws InvalidToolBindException if the item can't be bound to that item */ public void setTool(int item, @Nullable Tool tool) throws InvalidToolBindException { + setTool(item, tool, null); + } + + public void setTool(int item, @Nullable Tool tool, Player player) throws InvalidToolBindException { if (item > 0 && item < 255) { throw new InvalidToolBindException(item, "Blocks can't be used"); } else if (item == config.wandItem) { @@ -1008,8 +1008,17 @@ public class LocalSession { } else if (item == config.navigationWand) { throw new InvalidToolBindException(item, "Already used for the navigation wand"); } - - this.tools.put(item, tool); + Tool previous = this.tools.put(item, tool); + if (player != null) { + if (previous instanceof BrushTool) { + Brush brush = ((BrushTool) previous).getBrush(); + if (brush instanceof VisualBrush) { + ((VisualBrush) brush).clear(player); + } + } else if (previous instanceof VisualBrush) { + ((VisualBrush) tool).clear(player); + } + } } /** diff --git a/core/src/main/java/com/sk89q/worldedit/MutableBlockVector.java b/core/src/main/java/com/sk89q/worldedit/MutableBlockVector.java index e46d9500..873d5dd0 100644 --- a/core/src/main/java/com/sk89q/worldedit/MutableBlockVector.java +++ b/core/src/main/java/com/sk89q/worldedit/MutableBlockVector.java @@ -1,6 +1,17 @@ package com.sk89q.worldedit; public class MutableBlockVector extends BlockVector { + private static ThreadLocal MUTABLE_CACHE = new ThreadLocal() { + @Override + protected MutableBlockVector initialValue() { + return new MutableBlockVector(); + } + }; + + public static Vector get(int x, int y, int z) { + return MUTABLE_CACHE.get().setComponents(x, y, z); + } + private int x,y,z; public MutableBlockVector(Vector v) { diff --git a/core/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java b/core/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java new file mode 100644 index 00000000..d0da313a --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java @@ -0,0 +1,421 @@ +/* + * 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 Lesser 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.blocks; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.CuboidClipboard.FlipDirection; +import com.sk89q.worldedit.foundation.Block; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.world.registry.WorldData; + +import javax.annotation.Nullable; +import java.util.Collection; + +/** + * Represents a mutable "snapshot" of a block. + * + *

An instance of this block contains all the information needed to + * accurately reproduce the block, provided that the instance was + * made correctly. In some implementations, it may not be possible to get a + * snapshot of blocks correctly, so, for example, the NBT data for a block + * may be missing.

+ * + *

This class identifies blocks using an integer ID. However, IDs for + * a given block may differ between worlds so it is important that users of + * this class convert the ID from one "world space" to another "world space," + * a task that that is assisted with by working with the source and + * destination {@link WorldData} instances. Numeric IDs are utilized because + * they are more space efficient to store, and it also implies that internal + * uses of this class (i.e. history, etc.) do not need to worry about + * interning block string IDs.

+ * + *

A peculiar detail of this class is that it accepts {@code -1} as a + * valid data value. This is due to legacy reasons: WorldEdit uses -1 + * as a "wildcard" block value, even though a {@link Mask} would be + * more appropriate.

+ */ +@SuppressWarnings("deprecation") +public class BaseBlock extends Block implements TileEntityBlock { + + /** + * Indicates the highest possible block ID (inclusive) that can be used. + * This value is subject to change depending on the implementation, but + * internally this class only supports a range of 4096 IDs (for space + * reasons), which coincides with the number of possible IDs that official + * Minecraft supports as of version 1.7. + */ + public static final int MAX_ID = 4095; + + /** + * Indicates the maximum data value (inclusive) that can be used. A future + * version of Minecraft may abolish block data values. + */ + public static final int MAX_DATA = 15; + + // Instances of this class should be _as small as possible_ because there will + // be millions of instances of this object. + + private short id; + private short data; + @Nullable + private CompoundTag nbtData; + + /** + * Construct a block with the given ID and a data value of 0. + * + * @param id ID value + * @see #setId(int) + */ + public BaseBlock(int id) { + internalSetId(id); + internalSetData(0); + } + + /** + * Construct a block with the given ID and data value. + * + * @param id ID value + * @param data data value + * @see #setId(int) + * @see #setData(int) + */ + public BaseBlock(int id, int data) { + internalSetId(id); + internalSetData(data); + } + + /** + * Construct a block with the given ID, data value and NBT data structure. + * + * @param id ID value + * @param data data value + * @param nbtData NBT data, which may be null + */ + public BaseBlock(int id, int data, @Nullable CompoundTag nbtData) { + setId(id); + setData(data); + setNbtData(nbtData); + } + + /** + * Create a clone of another block. + * + * @param other the other block + */ + public BaseBlock(BaseBlock other) { + this(other.getId(), other.getData(), other.getNbtData()); + } + + /** + * Get the ID of the block. + * + * @return ID (between 0 and {@link #MAX_ID}) + */ + @Override + public int getId() { + return id; + } + + /** + * Set the block ID. + * + * @param id block id (between 0 and {@link #MAX_ID}). + */ + protected final void internalSetId(int id) { + if (id > MAX_ID) { + throw new IllegalArgumentException("Can't have a block ID above " + + MAX_ID + " (" + id + " given)"); + } + + if (id < 0) { + throw new IllegalArgumentException("Can't have a block ID below 0"); + } + + this.id = (short) id; + } + + /** + * Set the block ID. + * + * @param id block id (between 0 and {@link #MAX_ID}). + */ + @Override + public void setId(int id) { + internalSetId(id); + } + + /** + * Get the block's data value. + * + * @return data value (0-15) + */ + @Override + public int getData() { + return data; + } + + /** + * Set the block's data value. + * + * @param data block data value (between 0 and {@link #MAX_DATA}). + */ + protected final void internalSetData(int data) { + if (data > MAX_DATA) { + throw new IllegalArgumentException( + "Can't have a block data value above " + MAX_DATA + " (" + + data + " given)"); + } + + if (data < -1) { + throw new IllegalArgumentException("Can't have a block data value below -1"); + } + + this.data = (short) data; + } + + /** + * Set the block's data value. + * + * @param data block data value (between 0 and {@link #MAX_DATA}). + */ + @Override + public void setData(int data) { + internalSetData(data); + } + + /** + * Set both the block's ID and data value. + * + * @param id ID value + * @param data data value + * @see #setId(int) + * @see #setData(int) + */ + @Override + public void setIdAndData(int id, int data) { + setId(id); + setData(data); + } + + /** + * Returns whether the data value is -1, indicating that this block is to be + * used as a wildcard matching block. + * + * @return true if the data value is -1 + */ + @Override + public boolean hasWildcardData() { + return getData() == -1; + } + + @Override + public boolean hasNbtData() { + return getNbtData() != null; + } + + @Override + public String getNbtId() { + CompoundTag nbtData = getNbtData(); + if (nbtData == null) { + return ""; + } + Tag idTag = nbtData.getValue().get("id"); + if (idTag != null && idTag instanceof StringTag) { + return ((StringTag) idTag).getValue(); + } else { + return ""; + } + } + + @Nullable + @Override + public CompoundTag getNbtData() { + return nbtData; + } + + @Override + public void setNbtData(@Nullable CompoundTag nbtData) { + this.nbtData = nbtData; + } + + /** + * Get the type of block. + * + * @return the type + */ + public int getType() { + return getId(); + } + + /** + * Set the type of block. + * + * @param type the type to set + */ + public void setType(int type) { + setId(type); + } + + /** + * Returns true if it's air. + * + * @return if air + */ + public boolean isAir() { + return getType() == BlockID.AIR; + } + + /** + * Rotate this block 90 degrees. + * + * @return new data value + * @deprecated Use {@link BlockData#rotate90(int, int)} + */ + @Deprecated + public int rotate90() { + int newData = BlockData.rotate90(getType(), getData()); + setData(newData); + return newData; + } + + /** + * Rotate this block -90 degrees. + * + * @return new data value + * @deprecated Use {@link BlockData#rotate90Reverse(int, int)} + */ + @Deprecated + public int rotate90Reverse() { + int newData = BlockData.rotate90Reverse(getType(), getData()); + setData((short) newData); + return newData; + } + + /** + * Cycle the damage value of the block forward or backward + * + * @param increment 1 for forward, -1 for backward + * @return new data value + * @deprecated Use {@link BlockData#cycle(int, int, int)} + */ + @Deprecated + public int cycleData(int increment) { + int newData = BlockData.cycle(getType(), getData(), increment); + setData((short) newData); + return newData; + } + + /** + * Flip this block. + * + * @return this block + * @deprecated Use {@link BlockData#flip(int, int)} + */ + @Deprecated + public BaseBlock flip() { + setData((short) BlockData.flip(getType(), getData())); + return this; + } + + /** + * Flip this block. + * + * @param direction direction to flip in + * @return this block + * @deprecated Use {@link BlockData#flip(int, int, FlipDirection)} + */ + @Deprecated + public BaseBlock flip(FlipDirection direction) { + setData((short) BlockData.flip(getType(), getData(), direction)); + return this; + } + + /** + * Checks whether the type ID and data value are equal. + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof BaseBlock)) { + return false; + } + + final BaseBlock otherBlock = (BaseBlock) o; + + return getType() == otherBlock.getType() && getData() == otherBlock.getData(); + + } + + public boolean equals(BaseBlock block) { + return block.getId() == this.getId() && block.getData() == this.getData(); + } + + /** + * Checks if the type is the same, and if data is the same if only data != -1. + * + * @param o other block + * @return true if equal + */ + public boolean equalsFuzzy(BaseBlock o) { + return (getType() == o.getType()) && (getData() == o.getData() || getData() == -1 || o.getData() == -1); + } + + /** + * @deprecated This method is silly, use {@link #containsFuzzy(java.util.Collection, BaseBlock)} instead. + */ + @Deprecated + public boolean inIterable(Iterable iter) { + for (BaseBlock block : iter) { + if (block.equalsFuzzy(this)) { + return true; + } + } + return false; + } + + /** + * @deprecated Use {@link Blocks#containsFuzzy(Collection, BaseBlock)} + */ + @Deprecated + public static boolean containsFuzzy(Collection collection, BaseBlock o) { + return Blocks.containsFuzzy(collection, o); + } + + @Override + public int hashCode() { + int ret = getId() << 3; + if (getData() != (byte) -1) ret |= getData(); + return ret; + } + + @Override + public String toString() { + return "Block{ID:" + getId() + ", Data: " + getData() + "}"; + } + + public boolean isImmutable() { + return false; + } + + public static Class inject() { + return BaseBlock.class; + } +} diff --git a/core/src/main/java/com/sk89q/worldedit/blocks/ImmutableBlock.java b/core/src/main/java/com/sk89q/worldedit/blocks/ImmutableBlock.java new file mode 100644 index 00000000..ef7fee33 --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/blocks/ImmutableBlock.java @@ -0,0 +1,36 @@ +package com.sk89q.worldedit.blocks; + +import com.sk89q.worldedit.CuboidClipboard; + +public class ImmutableBlock extends BaseBlock { + public ImmutableBlock(int id, int data) { + super(id, data); + } + + @Override + public void setData(int data) { + throw new IllegalStateException("Cannot set data"); + } + + @Override + public void setId(int id) { + throw new IllegalStateException("Cannot set id"); + } + + @Override + public BaseBlock flip() { + BaseBlock clone = new BaseBlock(getId(), getData(), getNbtData()); + return clone.flip(); + } + + @Override + public BaseBlock flip(CuboidClipboard.FlipDirection direction) { + BaseBlock clone = new BaseBlock(getId(), getData(), getNbtData()); + return clone.flip(direction); + } + + @Override + public boolean isImmutable() { + return true; + } +} diff --git a/core/src/main/java/com/sk89q/worldedit/blocks/ImmutableDatalessBlock.java b/core/src/main/java/com/sk89q/worldedit/blocks/ImmutableDatalessBlock.java new file mode 100644 index 00000000..da580444 --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/blocks/ImmutableDatalessBlock.java @@ -0,0 +1,26 @@ +package com.sk89q.worldedit.blocks; + +public class ImmutableDatalessBlock extends ImmutableBlock { + public ImmutableDatalessBlock(int id) { + super(id, 0); + } + + @Override + public int getData() { + return 0; + } + + @Override + public boolean equals(BaseBlock block) { + return block.getId() == this.getId(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof BaseBlock) { + return ((BaseBlock) o).getId() == this.getId(); + } else { + return false; + } + } +} diff --git a/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java b/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java index 3eb1f870..0d089368 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -25,9 +25,9 @@ import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.FaweLimit; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.brush.BlendBall; +import com.boydti.fawe.object.brush.CircleBrush; import com.boydti.fawe.object.brush.CommandBrush; import com.boydti.fawe.object.brush.CopyPastaBrush; -import com.boydti.fawe.object.brush.DoubleActionBrushTool; import com.boydti.fawe.object.brush.ErodeBrush; import com.boydti.fawe.object.brush.FlattenBrush; import com.boydti.fawe.object.brush.HeightBrush; @@ -106,9 +106,9 @@ public class BrushCommands { @CommandPermissions("worldedit.brush.blendball") public void blendBallBrush(Player player, LocalSession session, @Optional("5") double radius) throws WorldEditException { worldEdit.checkMaxBrushRadius(radius); - BrushTool tool = session.getBrushTool(player.getItemInHand()); + BrushTool tool = session.getBrushTool(player.getItemInHand(), player); tool.setSize(radius); - tool.setBrush(new BlendBall(), "worldedit.brush.blendball"); + tool.setBrush(new BlendBall(), "worldedit.brush.blendball", player); player.print(BBC.getPrefix() + BBC.BRUSH_BLEND_BALL.f(radius)); } @@ -123,12 +123,30 @@ public class BrushCommands { @CommandPermissions("worldedit.brush.erode") public void erodeBrush(Player player, LocalSession session, @Optional("5") double radius) throws WorldEditException { worldEdit.checkMaxBrushRadius(radius); - DoubleActionBrushTool tool = session.getDoubleActionBrushTool(player.getItemInHand()); + BrushTool tool = session.getBrushTool(player.getItemInHand(), player); tool.setSize(radius); - tool.setBrush(new ErodeBrush(), "worldedit.brush.erode"); + tool.setBrush(new ErodeBrush(), "worldedit.brush.erode", player); player.print(BBC.getPrefix() + BBC.BRUSH_ERODE.f(radius)); } + @Command( + aliases = { "circle" }, + usage = " [radius]", + desc = "Choose the circle brush", + help = "Chooses the circle brush.", + min = 1, + max = 2 + ) + @CommandPermissions("worldedit.brush.sphere") + public void circleBrush(Player player, LocalSession session, Pattern fill, @Optional("5") double radius, @Switch('h') boolean hollow) throws WorldEditException { + worldEdit.checkMaxBrushRadius(radius); + BrushTool tool = session.getBrushTool(player.getItemInHand(), player); + tool.setSize(radius); + tool.setFill(fill); + tool.setBrush(new CircleBrush(tool, player), "worldedit.brush.circle", player); + player.print(BBC.getPrefix() + BBC.BRUSH_CIRCLE.f(radius)); + } + @Command( aliases = { "recursive", "recurse", "r" }, usage = " [radius]", @@ -141,9 +159,9 @@ public class BrushCommands { @CommandPermissions("worldedit.brush.recursive") public void recursiveBrush(Player player, LocalSession session, EditSession editSession, Pattern fill, @Optional("2") double radius, @Switch('d') boolean depthFirst) throws WorldEditException { worldEdit.checkMaxBrushRadius(radius); - BrushTool tool = session.getBrushTool(player.getItemInHand()); + BrushTool tool = session.getBrushTool(player.getItemInHand(), player); tool.setSize(radius); - tool.setBrush(new RecurseBrush(tool, depthFirst), "worldedit.brush.recursive"); + tool.setBrush(new RecurseBrush(tool, depthFirst), "worldedit.brush.recursive", player); tool.setMask(new IdMask(editSession)); tool.setFill(fill); player.print(BBC.getPrefix() + BBC.BRUSH_RECURSIVE.f(radius)); @@ -165,10 +183,10 @@ public class BrushCommands { @CommandPermissions("worldedit.brush.line") public void lineBrush(Player player, LocalSession session, Pattern fill, @Optional("0") double radius, @Switch('h') boolean shell, @Switch('s') boolean select, @Switch('f') boolean flat) throws WorldEditException { worldEdit.checkMaxBrushRadius(radius); - DoubleActionBrushTool tool = session.getDoubleActionBrushTool(player.getItemInHand()); + BrushTool tool = session.getBrushTool(player.getItemInHand(), player); tool.setFill(fill); tool.setSize(radius); - tool.setBrush(new LineBrush(shell, select, flat), "worldedit.brush.line"); + tool.setBrush(new LineBrush(shell, select, flat), "worldedit.brush.line", player); player.print(BBC.getPrefix() + BBC.BRUSH_LINE.f(radius)); } @@ -183,10 +201,10 @@ public class BrushCommands { @CommandPermissions("worldedit.brush.spline") public void splineBrush(Player player, LocalSession session, Pattern fill, @Optional("25") double radius) throws WorldEditException { worldEdit.checkMaxBrushRadius(radius); - DoubleActionBrushTool tool = session.getDoubleActionBrushTool(player.getItemInHand()); + BrushTool tool = session.getBrushTool(player.getItemInHand(), player); tool.setFill(fill); tool.setSize(radius); - tool.setBrush(new SplineBrush(player, session, tool), "worldedit.brush.spline"); + tool.setBrush(new SplineBrush(player, session, tool), "worldedit.brush.spline", player); player.print(BBC.getPrefix() + BBC.BRUSH_SPLINE.f(radius)); } @@ -205,14 +223,14 @@ public class BrushCommands { public void sphereBrush(Player player, LocalSession session, Pattern fill, @Optional("2") double radius, @Switch('h') boolean hollow) throws WorldEditException { worldEdit.checkMaxBrushRadius(radius); - BrushTool tool = session.getBrushTool(player.getItemInHand()); + BrushTool tool = session.getBrushTool(player.getItemInHand(), player); tool.setFill(fill); tool.setSize(radius); if (hollow) { - tool.setBrush(new HollowSphereBrush(), "worldedit.brush.sphere"); + tool.setBrush(new HollowSphereBrush(), "worldedit.brush.sphere", player); } else { - tool.setBrush(new SphereBrush(), "worldedit.brush.sphere"); + tool.setBrush(new SphereBrush(), "worldedit.brush.sphere", player); } if (fill instanceof BlockPattern) { BaseBlock block = ((BlockPattern) fill).getBlock(); @@ -245,14 +263,14 @@ public class BrushCommands { worldEdit.checkMaxBrushRadius(radius); worldEdit.checkMaxBrushRadius(height); - BrushTool tool = session.getBrushTool(player.getItemInHand()); + BrushTool tool = session.getBrushTool(player.getItemInHand(), player); tool.setFill(fill); tool.setSize(radius); if (hollow) { - tool.setBrush(new HollowCylinderBrush(height), "worldedit.brush.cylinder"); + tool.setBrush(new HollowCylinderBrush(height), "worldedit.brush.cylinder", player); } else { - tool.setBrush(new CylinderBrush(height), "worldedit.brush.cylinder"); + tool.setBrush(new CylinderBrush(height), "worldedit.brush.cylinder", player); } player.print(BBC.getPrefix() + BBC.BRUSH_SPHERE.f(radius, height)); } @@ -279,8 +297,8 @@ public class BrushCommands { worldEdit.checkMaxBrushRadius(size.getBlockY()); worldEdit.checkMaxBrushRadius(size.getBlockZ()); - BrushTool tool = session.getBrushTool(player.getItemInHand()); - tool.setBrush(new ClipboardBrush(holder, ignoreAir, usingOrigin), "worldedit.brush.clipboard"); + BrushTool tool = session.getBrushTool(player.getItemInHand(), player); + tool.setBrush(new ClipboardBrush(holder, ignoreAir, usingOrigin), "worldedit.brush.clipboard", player); player.print(BBC.getPrefix() + BBC.BRUSH_CLIPBOARD.s()); } @@ -305,9 +323,9 @@ public class BrushCommands { FawePlayer fp = FawePlayer.wrap(player); FaweLimit limit = Settings.IMP.getLimit(fp); iterations = Math.min(limit.MAX_ITERATIONS, iterations); - BrushTool tool = session.getBrushTool(player.getItemInHand()); + BrushTool tool = session.getBrushTool(player.getItemInHand(), player); tool.setSize(radius); - tool.setBrush(new SmoothBrush(iterations, naturalBlocksOnly), "worldedit.brush.smooth"); + tool.setBrush(new SmoothBrush(iterations, naturalBlocksOnly), "worldedit.brush.smooth", player); player.print(BBC.getPrefix() + BBC.BRUSH_SMOOTH.f(radius, iterations, (naturalBlocksOnly ? "natural blocks only" : "any block"))); } @@ -323,12 +341,12 @@ public class BrushCommands { public void extinguishBrush(Player player, LocalSession session, EditSession editSession, @Optional("5") double radius) throws WorldEditException { worldEdit.checkMaxBrushRadius(radius); - BrushTool tool = session.getBrushTool(player.getItemInHand()); + BrushTool tool = session.getBrushTool(player.getItemInHand(), player); Pattern fill = new BlockPattern(new BaseBlock(0)); tool.setFill(fill); tool.setSize(radius); tool.setMask(new BlockMask(editSession, new BaseBlock(BlockID.FIRE))); - tool.setBrush(new SphereBrush(), "worldedit.brush.ex"); + tool.setBrush(new SphereBrush(), "worldedit.brush.ex", player); BBC.BRUSH_EXTINGUISHER.send(player, radius); player.print(BBC.getPrefix() + BBC.BRUSH_EXTINGUISHER.f(radius)); } @@ -349,9 +367,9 @@ public class BrushCommands { public void gravityBrush(Player player, LocalSession session, @Optional("5") double radius, @Switch('h') boolean fromMaxY) throws WorldEditException { worldEdit.checkMaxBrushRadius(radius); - BrushTool tool = session.getBrushTool(player.getItemInHand()); + BrushTool tool = session.getBrushTool(player.getItemInHand(), player); tool.setSize(radius); - tool.setBrush(new GravityBrush(fromMaxY, tool), "worldedit.brush.gravity"); + tool.setBrush(new GravityBrush(fromMaxY, tool), "worldedit.brush.gravity", player); player.print(BBC.getPrefix() + BBC.BRUSH_GRAVITY.f(radius)); } @@ -431,19 +449,19 @@ public class BrushCommands { } } - DoubleActionBrushTool tool = session.getDoubleActionBrushTool(player.getItemInHand()); + BrushTool tool = session.getBrushTool(player.getItemInHand(), player); tool.setSize(radius); if (flat) { try { - tool.setBrush(new FlattenBrush(stream, rotation, yscale, tool, filename.equalsIgnoreCase("#clipboard") ? session.getClipboard().getClipboard() : null, shape), "worldedit.brush.height"); + tool.setBrush(new FlattenBrush(stream, rotation, yscale, tool, filename.equalsIgnoreCase("#clipboard") ? session.getClipboard().getClipboard() : null, shape), "worldedit.brush.height", player); } catch (EmptyClipboardException ignore) { - tool.setBrush(new FlattenBrush(stream, rotation, yscale, tool, null, shape), "worldedit.brush.height"); + tool.setBrush(new FlattenBrush(stream, rotation, yscale, tool, null, shape), "worldedit.brush.height", player); } } else { try { - tool.setBrush(new HeightBrush(stream, rotation, yscale, tool, filename.equalsIgnoreCase("#clipboard") ? session.getClipboard().getClipboard() : null), "worldedit.brush.height"); + tool.setBrush(new HeightBrush(stream, rotation, yscale, tool, filename.equalsIgnoreCase("#clipboard") ? session.getClipboard().getClipboard() : null), "worldedit.brush.height", player); } catch (EmptyClipboardException ignore) { - tool.setBrush(new HeightBrush(stream, rotation, yscale, tool, null), "worldedit.brush.height"); + tool.setBrush(new HeightBrush(stream, rotation, yscale, tool, null), "worldedit.brush.height", player); } } player.print(BBC.getPrefix() + BBC.BRUSH_HEIGHT.f(radius)); @@ -464,9 +482,9 @@ public class BrushCommands { @CommandPermissions("worldedit.brush.copy") public void copy(Player player, LocalSession session, @Optional("5") double radius) throws WorldEditException { worldEdit.checkMaxBrushRadius(radius); - DoubleActionBrushTool tool = session.getDoubleActionBrushTool(player.getItemInHand()); + BrushTool tool = session.getBrushTool(player.getItemInHand(), player); tool.setSize(radius); - tool.setBrush(new CopyPastaBrush(tool), "worldedit.brush.copy"); + tool.setBrush(new CopyPastaBrush(tool), "worldedit.brush.copy", player); player.print(BBC.getPrefix() + BBC.BRUSH_COPY.f(radius)); } @@ -481,9 +499,9 @@ public class BrushCommands { ) @CommandPermissions("worldedit.brush.command") public void command(Player player, LocalSession session, @Optional("5") double radius, CommandContext args) throws WorldEditException { - BrushTool tool = session.getBrushTool(player.getItemInHand()); + BrushTool tool = session.getBrushTool(player.getItemInHand(), player); String cmd = args.getJoinedStrings(1); - tool.setBrush(new CommandBrush(tool, cmd, radius), "worldedit.brush.copy"); + tool.setBrush(new CommandBrush(tool, cmd, radius), "worldedit.brush.copy", player); player.print(BBC.getPrefix() + BBC.BRUSH_COMMAND.f(cmd)); } @@ -526,9 +544,9 @@ public class BrushCommands { CreatureButcher flags = new CreatureButcher(player); flags.fromCommand(args); - BrushTool tool = session.getBrushTool(player.getItemInHand()); + BrushTool tool = session.getBrushTool(player.getItemInHand(), player); tool.setSize(radius); - tool.setBrush(new ButcherBrush(flags), "worldedit.brush.butcher"); + tool.setBrush(new ButcherBrush(flags), "worldedit.brush.butcher", player); player.print(BBC.getPrefix() + BBC.BRUSH_BUTCHER.f(radius)); } diff --git a/core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java b/core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java index 7a791ae1..605cf1ae 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java @@ -61,7 +61,7 @@ public class ToolCommands { ) @CommandPermissions("worldedit.tool.inspect") public void inspectBrush(Player player, LocalSession session, @Optional("1") double radius) throws WorldEditException { - session.setTool(player.getItemInHand(), new InspectBrush()); + session.setTool(player.getItemInHand(), new InspectBrush(), player); BBC.TOOL_INSPECT.send(player, ItemType.toHeldName(player.getItemInHand())); } @@ -73,7 +73,7 @@ public class ToolCommands { max = 0 ) public void none(Player player, LocalSession session, CommandContext args) throws WorldEditException { - session.setTool(player.getItemInHand(), null); + session.setTool(player.getItemInHand(), null, player); BBC.TOOL_NONE.send(player); } @@ -86,7 +86,7 @@ public class ToolCommands { ) @CommandPermissions("worldedit.tool.info") public void info(Player player, LocalSession session, CommandContext args) throws WorldEditException { - session.setTool(player.getItemInHand(), new QueryTool()); + session.setTool(player.getItemInHand(), new QueryTool(), player); BBC.TOOL_INFO.send(player, ItemType.toHeldName(player.getItemInHand())); } @@ -110,7 +110,7 @@ public class ToolCommands { return; } - session.setTool(player.getItemInHand(), new TreePlanter(new TreeGenerator(type))); + session.setTool(player.getItemInHand(), new TreePlanter(new TreeGenerator(type)), player); BBC.TOOL_TREE.send(player, ItemType.toHeldName(player.getItemInHand())); } @@ -124,7 +124,7 @@ public class ToolCommands { @CommandPermissions("worldedit.tool.replacer") public void repl(Player player, LocalSession session, CommandContext args) throws WorldEditException { BaseBlock targetBlock = we.getBlock(player, args.getString(0)); - session.setTool(player.getItemInHand(), new BlockReplacer(targetBlock)); + session.setTool(player.getItemInHand(), new BlockReplacer(targetBlock), player); BBC.TOOL_REPL.send(player, ItemType.toHeldName(player.getItemInHand())); } @@ -138,7 +138,7 @@ public class ToolCommands { @CommandPermissions("worldedit.tool.data-cycler") public void cycler(Player player, LocalSession session, CommandContext args) throws WorldEditException { - session.setTool(player.getItemInHand(), new BlockDataCyler()); + session.setTool(player.getItemInHand(), new BlockDataCyler(), player); BBC.TOOL_CYCLER.send(player, ItemType.toHeldName(player.getItemInHand())); } @@ -160,7 +160,7 @@ public class ToolCommands { } Pattern pattern = we.getBlockPattern(player, args.getString(0)); - session.setTool(player.getItemInHand(), new FloodFillTool(range, pattern)); + session.setTool(player.getItemInHand(), new FloodFillTool(range, pattern), player); BBC.TOOL_FLOOD_FILL.send(player, ItemType.toHeldName(player.getItemInHand())); } @@ -173,7 +173,7 @@ public class ToolCommands { ) @CommandPermissions("worldedit.tool.deltree") public void deltree(Player player, LocalSession session, CommandContext args) throws WorldEditException { - session.setTool(player.getItemInHand(), new FloatingTreeRemover()); + session.setTool(player.getItemInHand(), new FloatingTreeRemover(), player); BBC.TOOL_DELTREE.send(player, ItemType.toHeldName(player.getItemInHand())); } @@ -186,7 +186,7 @@ public class ToolCommands { ) @CommandPermissions("worldedit.tool.farwand") public void farwand(Player player, LocalSession session, CommandContext args) throws WorldEditException { - session.setTool(player.getItemInHand(), new DistanceWand()); + session.setTool(player.getItemInHand(), new DistanceWand(), player); BBC.TOOL_FARWAND.send(player, ItemType.toHeldName(player.getItemInHand())); } @@ -202,7 +202,7 @@ public class ToolCommands { BaseBlock secondary = we.getBlock(player, args.getString(0)); BaseBlock primary = we.getBlock(player, args.getString(1)); - session.setTool(player.getItemInHand(), new LongRangeBuildTool(primary, secondary)); + session.setTool(player.getItemInHand(), new LongRangeBuildTool(primary, secondary), player); BBC.TOOL_LRBUILD_BOUND.send(player, ItemType.toHeldName(player.getItemInHand())); BBC.TOOL_LRBUILD_INFO.send(player, ItemType.toName(secondary.getType()), ItemType.toName(primary.getType())); } diff --git a/core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java b/core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java index af392378..db574166 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java @@ -1,7 +1,6 @@ package com.sk89q.worldedit.command; import com.boydti.fawe.config.BBC; -import com.boydti.fawe.object.brush.DoubleActionBrushTool; import com.boydti.fawe.object.extent.DefaultTransformParser; import com.boydti.fawe.object.extent.ResettableExtent; import com.sk89q.minecraft.util.commands.Command; @@ -77,8 +76,6 @@ public class ToolUtilCommands { if (context == null || context.argsLength() == 0) { if (tool instanceof BrushTool) { ((BrushTool) tool).setMask(null); - } else if (tool instanceof DoubleActionBrushTool) { - ((DoubleActionBrushTool) tool).setMask(null); } BBC.BRUSH_MASK_DISABLED.send(player); } else { @@ -90,8 +87,6 @@ public class ToolUtilCommands { Mask mask = we.getMaskFactory().parseFromInput(context.getJoinedStrings(0), parserContext); if (tool instanceof BrushTool) { ((BrushTool) tool).setMask(mask); - } else if (tool instanceof DoubleActionBrushTool) { - ((DoubleActionBrushTool) tool).setMask(mask); } BBC.BRUSH_MASK.send(player); } @@ -114,8 +109,6 @@ public class ToolUtilCommands { if (context == null || context.argsLength() == 0) { if (tool instanceof BrushTool) { ((BrushTool) tool).setSourceMask(null); - } else if (tool instanceof DoubleActionBrushTool) { - ((DoubleActionBrushTool) tool).setMask(null); } BBC.BRUSH_SOURCE_MASK_DISABLED.send(player); } else { @@ -127,8 +120,6 @@ public class ToolUtilCommands { Mask mask = we.getMaskFactory().parseFromInput(context.getJoinedStrings(0), parserContext); if (tool instanceof BrushTool) { ((BrushTool) tool).setSourceMask(mask); - } else if (tool instanceof DoubleActionBrushTool) { - ((DoubleActionBrushTool) tool).setSourceMask(mask); } BBC.BRUSH_SOURCE_MASK.send(player); } @@ -150,8 +141,6 @@ public class ToolUtilCommands { if (context == null || context.argsLength() == 0) { if (tool instanceof BrushTool) { ((BrushTool) tool).setTransform(null); - } else if (tool instanceof DoubleActionBrushTool) { - ((DoubleActionBrushTool) tool).setTransform(null); } BBC.BRUSH_TRANSFORM_DISABLED.send(player); } else { @@ -163,8 +152,6 @@ public class ToolUtilCommands { ResettableExtent transform = transformParser.parseFromInput(context.getJoinedStrings(0), parserContext); if (tool instanceof BrushTool) { ((BrushTool) tool).setTransform(transform); - } else if (tool instanceof DoubleActionBrushTool) { - ((DoubleActionBrushTool) tool).setTransform(transform); } BBC.BRUSH_TRANSFORM.send(player); } @@ -181,9 +168,7 @@ public class ToolUtilCommands { public void material(Player player, LocalSession session, Pattern pattern) throws WorldEditException { Tool tool = session.getTool(player.getItemInHand()); if (tool instanceof BrushTool) { - ((BrushTool) tool).setMask(null); - } else if (tool instanceof DoubleActionBrushTool) { - ((DoubleActionBrushTool) tool).setFill(pattern); + ((BrushTool) tool).setFill(pattern); } BBC.BRUSH_MATERIAL.send(player); } @@ -197,12 +182,10 @@ public class ToolUtilCommands { ) @CommandPermissions("worldedit.brush.options.range") public void range(Player player, LocalSession session, CommandContext args) throws WorldEditException { - int range = args.getInteger(0); + int range = Math.max(0, Math.min(256, args.getInteger(0))); Tool tool = session.getTool(player.getItemInHand()); if (tool instanceof BrushTool) { - ((BrushTool) tool).setMask(null); - } else if (tool instanceof DoubleActionBrushTool) { - ((DoubleActionBrushTool) tool).setRange(range); + ((BrushTool) tool).setRange(range); } BBC.BRUSH_RANGE.send(player); } @@ -222,9 +205,7 @@ public class ToolUtilCommands { Tool tool = session.getTool(player.getItemInHand()); if (tool instanceof BrushTool) { - ((BrushTool) tool).setMask(null); - } else if (tool instanceof DoubleActionBrushTool) { - ((DoubleActionBrushTool) tool).setSize(radius); + ((BrushTool) tool).setSize(radius); } BBC.BRUSH_SIZE.send(player); } diff --git a/core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java b/core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java index 03b26eae..b32d5650 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java +++ b/core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java @@ -1,6 +1,8 @@ package com.sk89q.worldedit.command.tool; import com.boydti.fawe.config.BBC; +import com.boydti.fawe.object.brush.DoubleActionBrush; +import com.boydti.fawe.object.brush.visualization.VisualBrush; import com.boydti.fawe.object.extent.ResettableExtent; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalConfiguration; @@ -8,7 +10,6 @@ import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.WorldVector; import com.sk89q.worldedit.command.tool.brush.Brush; -import com.sk89q.worldedit.command.tool.brush.SphereBrush; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Platform; @@ -22,17 +23,19 @@ import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkNotNull; -/** - * Builds a shape at the place being looked at. - */ -public class BrushTool implements TraceTool { +public class BrushTool implements DoubleActionTraceTool { + + public enum BrushAction { + PRIMARY, + SECONDARY + } protected static int MAX_RANGE = 500; protected int range = -1; private Mask mask = null; private Mask sourceMask = null; private ResettableExtent transform = null; - private Brush brush = new SphereBrush(); + private Brush brush = null; @Nullable private Pattern material; private double size = 1; @@ -70,15 +73,6 @@ public class BrushTool implements TraceTool { return mask; } - /** - * Set the block filter used for identifying blocks to replace. - * - * @param filter the filter to set - */ - public void setMask(Mask filter) { - this.mask = filter; - } - /** * Get the filter. * @@ -88,6 +82,15 @@ public class BrushTool implements TraceTool { return sourceMask; } + /** + * Set the block filter used for identifying blocks to replace. + * + * @param filter the filter to set + */ + public void setMask(Mask filter) { + this.mask = filter; + } + /** * Set the block filter used for identifying blocks to replace. * @@ -104,6 +107,13 @@ public class BrushTool implements TraceTool { * @param permission the permission */ public void setBrush(Brush brush, String permission) { + setBrush(brush, permission, null); + } + + public void setBrush(Brush brush, String permission, Player player) { + if (player != null && brush instanceof VisualBrush) { + ((VisualBrush) brush).clear(player); + } this.brush = brush; this.permission = permission; } @@ -171,8 +181,10 @@ public class BrushTool implements TraceTool { this.range = range; } - @Override - public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session) { + public boolean act(BrushAction action, Platform server, LocalConfiguration config, Player player, LocalSession session) { + if (action == BrushAction.SECONDARY && !(brush instanceof DoubleActionBrush)) { + return false; + } WorldVector target = null; target = player.getBlockTrace(getRange(), true); @@ -199,7 +211,7 @@ public class BrushTool implements TraceTool { } } if (sourceMask != null) { - Mask existingMask = editSession.getMask(); + Mask existingMask = editSession.getSourceMask(); if (existingMask == null) { editSession.setSourceMask(sourceMask); @@ -215,7 +227,11 @@ public class BrushTool implements TraceTool { editSession.addTransform(transform); } try { - brush.build(editSession, target, material, size); + if (brush instanceof DoubleActionBrush) { + ((DoubleActionBrush) brush).build(action, editSession, target, material, size); + } else { + brush.build(editSession, target, material, size); + } } catch (MaxChangedBlocksException e) { player.printError("Max blocks change limit reached."); // Never happens } finally { @@ -224,11 +240,20 @@ public class BrushTool implements TraceTool { } session.remember(editSession); } - return true; } + @Override + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session) { + return act(BrushAction.PRIMARY, server, config, player, session); + } + + @Override + public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session) { + return act(BrushAction.SECONDARY, server, config, player, session); + } + public static Class inject() { return BrushTool.class; } -} \ No newline at end of file +} diff --git a/core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java b/core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java index dc492825..c31ea649 100644 --- a/core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java +++ b/core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java @@ -447,14 +447,18 @@ public class PlatformManager { } } } catch (Throwable e) { - FaweException faweException = FaweException.get(e); - if (faweException != null) { - BBC.WORLDEDIT_CANCEL_REASON.send(actor, faweException.getMessage()); - } else { - actor.printError("Please report this error: [See console]"); - actor.printRaw(e.getClass().getName() + ": " + e.getMessage()); - MainUtil.handleError(e); - } + handleThrowable(e, actor); + } + } + + public void handleThrowable(Throwable e, Actor actor) { + FaweException faweException = FaweException.get(e); + if (faweException != null) { + BBC.WORLDEDIT_CANCEL_REASON.send(actor, faweException.getMessage()); + } else { + actor.printError("Please report this error: [See console]"); + actor.printRaw(e.getClass().getName() + ": " + e.getMessage()); + MainUtil.handleError(e); } } diff --git a/core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java b/core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java index 84409fe7..6902fe70 100644 --- a/core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java +++ b/core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java @@ -204,7 +204,7 @@ public class BlockTransformExtent extends ResettableExtent { if (value != null && value.getDirection() != null) { StateValue newValue = getNewStateValue(state, transform, value.getDirection()); if (newValue != null) { - if (changedBlock.hasWildcardData()) { + if (changedBlock.isImmutable()) { changedBlock = new BaseBlock(changedBlock.getId(), changedBlock.getData(), changedBlock.getNbtData()); } newValue.set(changedBlock); diff --git a/core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java b/core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java new file mode 100644 index 00000000..28fa7dba --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java @@ -0,0 +1,59 @@ +/* + * 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 Lesser 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.Vector; + +import javax.annotation.Nullable; + +/** + * Tests whether a given vector meets a criteria. + */ +public interface Mask extends com.sk89q.worldedit.masks.Mask { + + /** + * Returns true if the criteria is met. + * + * @param vector the vector to test + * @return true if the criteria is met + */ + boolean test(Vector vector); + + /** + * Get the 2D version of this mask if one exists. + * + * @return a 2D mask version or {@code null} if this mask can't be 2D + */ + @Nullable + Mask2D toMask2D(); + + default void prepare(LocalSession session, LocalPlayer player, Vector target) {} + + default boolean matches(EditSession editSession, Vector position) { + return test(position); + } + + public static Class inject() { + return Mask.class; + } +} diff --git a/core/src/main/java/com/sk89q/worldedit/patterns/Pattern.java b/core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java similarity index 50% rename from core/src/main/java/com/sk89q/worldedit/patterns/Pattern.java rename to core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java index cd6ba723..3ec30135 100644 --- a/core/src/main/java/com/sk89q/worldedit/patterns/Pattern.java +++ b/core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java @@ -17,39 +17,36 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.patterns; +package com.sk89q.worldedit.function.pattern; -import com.sk89q.worldedit.*; +import com.sk89q.worldedit.MutableBlockVector; +import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; /** - * @deprecated See {@link com.sk89q.worldedit.function.pattern.Pattern} + * Returns a {@link BaseBlock} for a given position. */ -@Deprecated -public interface Pattern { //extends com.sk89q.worldedit.function.pattern.Pattern { +public interface Pattern extends com.sk89q.worldedit.patterns.Pattern { /** - * Get a block for a position. This return value of this method does - * not have to be consistent for the same position. + * Return a {@link BaseBlock} for the given position. * - * @param position the position where a block is needed + * @param position the position * @return a block */ - public BaseBlock next(Vector position); + BaseBlock apply(Vector position); - /** - * Get a block for a position. This return value of this method does - * not have to be consistent for the same position. - * - * @param x the X coordinate - * @param y the Y coordinate - * @param z the Z coordinate - * @return a block - */ - public BaseBlock next(int x, int y, int z); + @Override + default BaseBlock next(Vector position) { + return apply(position); + } -// @Override -// default BaseBlock apply(Vector position) { -// return next(position); -// } + @Override + default BaseBlock next(int x, int y, int z) { + return apply(MutableBlockVector.get(x, y, z)); + } + + public static Class inject() { + return Pattern.class; + } } diff --git a/core/src/main/java/com/sk89q/worldedit/function/pattern/Patterns.java b/core/src/main/java/com/sk89q/worldedit/function/pattern/Patterns.java index f71f3ba8..008da8f6 100644 --- a/core/src/main/java/com/sk89q/worldedit/function/pattern/Patterns.java +++ b/core/src/main/java/com/sk89q/worldedit/function/pattern/Patterns.java @@ -22,6 +22,9 @@ public final class Patterns { * @return a new-style pattern */ public static Pattern wrap(final com.sk89q.worldedit.patterns.Pattern pattern) { + if (pattern instanceof Pattern) { + return (Pattern) pattern; + } checkNotNull(pattern); return new Pattern() { @Override diff --git a/core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java b/core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java index fc38b9f1..1099debb 100644 --- a/core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java +++ b/core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java @@ -14,11 +14,22 @@ import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.RunContext; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; public abstract class BreadthFirstSearch implements Operation { + public static Vector[] DEFAULT_DIRECTIONS = new Vector[6]; + static { + DEFAULT_DIRECTIONS[0] = (new MutableBlockVector(0, -1, 0)); + DEFAULT_DIRECTIONS[1] = (new MutableBlockVector(0, 1, 0)); + DEFAULT_DIRECTIONS[2] = (new MutableBlockVector(-1, 0, 0)); + DEFAULT_DIRECTIONS[3] = (new MutableBlockVector(1, 0, 0)); + DEFAULT_DIRECTIONS[4] = (new MutableBlockVector(0, 0, -1)); + DEFAULT_DIRECTIONS[5] = (new MutableBlockVector(0, 0, 1)); + } + private final RegionFunction function; private final List directions = new ArrayList<>(); private BlockVectorSet visited; @@ -41,12 +52,7 @@ public abstract class BreadthFirstSearch implements Operation { this.queue = new BlockVectorSet(); this.visited = new BlockVectorSet(); this.function = function; - this.directions.add(new Vector(0, -1, 0)); - this.directions.add(new Vector(0, 1, 0)); - this.directions.add(new Vector(-1, 0, 0)); - this.directions.add(new Vector(1, 0, 0)); - this.directions.add(new Vector(0, 0, -1)); - this.directions.add(new Vector(0, 0, 1)); + this.directions.addAll(Arrays.asList(DEFAULT_DIRECTIONS)); this.maxDepth = maxDepth; } diff --git a/core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java b/core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java index 80965575..1ba83fab 100644 --- a/core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java +++ b/core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java @@ -46,6 +46,7 @@ public class RegionVisitor implements Operation { public final Iterable iterable; public final RegionFunction function; private final MappedFaweQueue queue; + private boolean useCuboidIterator = false; public int affected = 0; /** diff --git a/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java b/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java index d4cc1e3b..ed83ac25 100644 --- a/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java +++ b/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java @@ -44,6 +44,7 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { private Vector pos1; private Vector pos2; + private boolean useOldIterator; private int minX,minY,minZ,maxX,maxY,maxZ; /** @@ -80,6 +81,10 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { recalculate(); } + public void setUseOldIterator(boolean useOldIterator) { + this.useOldIterator = useOldIterator; + } + /** * Get the first cuboid-defining corner. * @@ -400,7 +405,7 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { @Override public Iterator iterator() { - if (Settings.IMP.HISTORY.COMPRESSION_LEVEL >= 9) { + if (Settings.IMP.HISTORY.COMPRESSION_LEVEL >= 9 || useOldIterator) { return iterator_old(); } return new Iterator() { @@ -445,7 +450,7 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { y = by; if (x > tx) { x = bx; - if (z >= tz) { + if (z > tz) { if (!hasNext) { throw new NoSuchElementException("End of iterator") { @Override @@ -494,10 +499,11 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { private int nextX = min.getBlockX(); private int nextY = min.getBlockY(); private int nextZ = min.getBlockZ(); + private boolean hasNext = true; @Override public boolean hasNext() { - return (nextZ != Integer.MIN_VALUE); + return hasNext; } @Override @@ -507,10 +513,10 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { mutable.mutZ(nextZ); if (++nextX > max.getBlockX()) { nextX = min.getBlockX(); - if (++nextY > max.getBlockY()) { - nextY = min.getBlockY(); - if (++nextZ > max.getBlockZ()) { - if (nextZ == Integer.MIN_VALUE) { + if (++nextZ > max.getBlockZ()) { + nextZ = min.getBlockZ(); + if (++nextY > max.getBlockY()) { + if (!hasNext) { throw new NoSuchElementException("End of iterator") { @Override public synchronized Throwable fillInStackTrace() { @@ -519,8 +525,9 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { }; } nextX = max.getBlockX(); + nextZ = max.getBlockZ(); nextY = max.getBlockY(); - nextZ = Integer.MIN_VALUE; + hasNext = false; } } } diff --git a/core/src/main/resources/de/messages.yml b/core/src/main/resources/de/messages.yml new file mode 100644 index 00000000..cd2ed55f --- /dev/null +++ b/core/src/main/resources/de/messages.yml @@ -0,0 +1,311 @@ +info: + prefix: '&4&lFAWE:&f&7' + schematic_pasting: '&7Das Schematic wird eingefügt. Dies kann nicht rückgängig gemacht + werden.' + updated_lighting_selection: '&7Updates des Lichts werden in %s0 chunks durchgeführt. + (Es kann einige Sekunden dauern bis die Pakete gesendet wurden.)' + set_region: '&7Markierung wurde auf aktuelle WorldEdit Region übertragen.' + worldedit_command_limit: '&7Bitte warte bist deine momentane Aktion fertig gestellt + wurde.' + worldedit_delayed: '&7Bitte warte während wir deine aktuelle WorldEdit Aktion durchführen...' + worldedit_run: '&7Entschuldige die Verzögerung. Nun führen wir folgende Aktion von + dir aus: %s' + worldedit_complete: '&7WorldEdit Aktion fertiggestellt..' + require_selection_in_mask: '&7%s deiner Auswahl ist nicht innerhalb deiner Maske. + Du kannst du innerhalb erlaubter Regionen Veränderungen durchführen.' + worldedit_volume: '&7Du kannst keine %current% verändern. Die maximale Anzahl an + Blöcken die du verändern kannst ist %max%.' + worldedit_iterations: '&7Du kannst keine Aktion %current% Mal wiederholen. Die maximale + Anzahl an erlaubten Wiederholungen ist %max%.' + worldedit_unsafe: '&7Der Zugang zu diesem Befehl wurde verboten.' + worldedit_dangerous_worldedit: '&cFAWE führt unsicher WorldEdit Aktionen aus! Position: + %s0 Username: %s1' + worldedit_bypass: '&7&oUm deine Beschränkungen zu ignorieren nutze &c/wea' + worldedit_bypassed: '&7Beschränkungen werden nun ignoriert.' + worldedit_unmasked: '&6Deine WorldEdit Beschränkungen sind nun aufgehoben.' + worldedit_restricted: '&6Deine WorldEdit Beschränkungen sind nun aktiv.' + worldedit_oom_admin: |- + &cPossible options: + &8 - &7//fast + &8 - &7Do smaller edits + &8 - &7Allocate more memory + &8 - &7Disable this safeguard + compressed: WorldEdit Verlauf komprimiert. Saved ~ %s0b (%s1x smaller) + action_complete: Aktion fertiggestellt in %s0 Sekunden + lighting_propogate_selection: '&7Licht wurde berechnet in %s0 Chunks. (Info: Um + Licht zu entfernen nutze //removelight)' + worldedit_toggle_tips_on: '&7WorldEdit Tipps deaktiviert.' + worldedit_toggle_tips_off: '&7WorldEdit Tipps aktiviert.' +error: + worldedit_extend: '&cDeine WorldEdit Aktion überschreitet die erlaubte Region' + command_syntax: '&cBenutzung: &7%s0' + no_perm: '&cDir fehlt die Berechtigung: %s0' + setting_disable: '&cFehlende Einstellung: %s0' + schematic_not_found: '&cSchematic nicht gefunden: &7%s0' + no_region: '&cDu hast keine aktive WorldEdit Markierung' + no_mask: '&cDu hast keine Mask gesetzt' + not_player: '&cDieser Befehl kann nur von Spielern ausgeführt werden!' + player_not_found: '&cSpieler nicht gefunden:&7 %s0' + oom: |- + &8[&cCritical&8] &cDetected low memory i.e. < 1%. FAWE will take the following actions: + &8 - &7Terminate WE block placement + &8 - &7Clear WE history + &8 - &7Unload non essential chunks + &8 - &7Kill entities + &8 - &7Garbage collect + &cIgnore this if trying to crash server. + &7Note: Low memory is likely (but not necessarily) caused by WE + worldedit_some_fails: '&c%s0 Blöcke wurden nicht platziert, da sie ausserhalb der + erlaubten Region sind.' + worldedit_some_fails_blockbag: '&cFehlende Blöcke: %s0' +web: + generating_link: Upload %s, Bitte warten... + generating_link_failed: '&cErstellung eines Download-Links fehlgeschlagen!' + download_link: '%s' +worldedit: + general: + mask_disabled: Globale Maske deaktiviert + mask: Globale Maske gesetzt + transform_disabled: Globale Transformation deaktiviert + transform: Globale Transformation gesetzt + source_mask_disabled: Globale Quell-Maske deaktiviert + source_mask: Global Quell-Maske gesetzt + fast_enabled: Fast-Modus aktiviert. Verlauf und Beschränkungen werden ignoriert. + fast_disabled: Fast-Modus deaktiviert + place_enabled: 'Platziere nun an Pos. #1.' + place_disabled: Platziere nun an dem Block in dem du stehst. + copy: + command_copy: '%s0 Blöcke kopiert' + cut: + command_cut_slow: |- + %s0 blocks were cut. + Tip: lazycut is safer + command_cut_lazy: '%s0 Blöcke werden beim einfügen entfernt' + paste: + command_paste: Zwischenablage wurde bei Position %s0 eingefügt + rotate: + command_rotate: Zwischenablage wurde gedreht + flip: + command_flipped: Zwischenablage wurde gespiegelt + regen: + command_regen_0: |- + Region regenerated. + Tip: Use a biome with /regen [biome] + command_regen_1: |- + Region regenerated. + Tip: Use a seed with /regen [biome] [seed] + command_regen_2: Region regeneriert. + tree: + command_tree: '%s0 Bäume erstellt.' + command_pumpkin: '%s0 Kürbis-Patch erstellt.' + flora: + command_flora: '%s0 Pflanzen erstellt.' + history: + command_history_clear: Verlauf gelöscht + command_redo_success: Redo erfolgreich. + command_undo_success: Undo erfolgreich. + command_redo_error: Nothing left to redo. (See also `/inspect` and `/frb`) + command_undo_error: Nothing left to undo. (See also `/inspect` and `/frb`) + command_history_other_error: WorldEdit Verlauf für %s0 konnte nicht gefunden werden. + operation: + operation: Operation wird durchgeführt (%s0) + selection: + selection_wand: 'Linksklick: Markiere Position #1; Rechtsklick: Markiere Position + #2' + selection_wand_disable: Bearbeitungs-Tool deaktiviert. + selection_wand_enable: Bearbeitungs-Tool aktiviert. + selection_chunk: Chunk ausgewählt (%s0) + selection_chunks: Chunks ausgewählt (%s0) - (%s1) + selection_contract: Markierung verkleinert um %s0 Blöcke. + selection_count: '%s0 Blöcke wurden gezählt.' + selection_distr: '# Gesamtanzahl Blöcke: %s0' + selection_expand: Markierung erweitert um %s0 Blöcke + selection_expand_vert: Markierung erweitert um %s0 Blöcke (Maximaler Baubereich) + selection_inset: Markierung verkleinert + selection_outset: Markierung vergößert + selection_shift: Region verschoben + selection_cleared: Auswahl gelöscht + brush: + brush_butcher: Butcher Pinsel ausgerüstet (%s0) + brush_clipboard: Clipboard Pinsel Format ausgerüstet + brush_cylinder: Cylinder Pinsel Format ausgerüstet (%s0 by %s1). + brush_extinguisher: Extinguisher ausgerüstet (%s0). + brush_gravity: Gravity Pinsel ausgerüstet (%s0) + brush_height: Height Pinsel ausgerüstet (%s0) + brush_copy: Copy Pinsel ausgerüstet (%s0) + brush_command: Command Pinsel ausgerüstet (%s0) + brush_height_invalid: Invalid height map file (%s0) + brush_smooth: Smooth Pinsel ausgerüstet (%s0 x %s1 using %s2). + brush_sphere: Sphere Pinsel Format ausgerüstet (%s0). + brush_line: Linien Pinsel Format ausgerüstet (%s0). + brush_spline: Linien Pinsel Format ausgerüstet (%s0). Rechstklicke ein Ende um ein Format hinzuzufügen + brush_spline_primary: Position hinzugefügt, Linksklick zum verbinden! + brush_spline_secondary_error: Nicht genügend Positionen gesetzt! + brush_spline_secondary: Kurve erstellt + brush_blend_ball: Blend ball Pinsel ausgerüstet (%s0). + brush_erode: Erode Pinsel ausgerüstet (%s0). + brush_paste_none: Zwischenablage leer! Nichts zum einfügen! + brush_size: Pinsel Größe gesetzt + brush_range: Pinsel Größe gesetzt + brush_mask_disabled: Pinsel Maske deaktiviert + brush_mask: Pinsel Maske gesetzt + brush_transform_disabled: Pinsel Transformation deaktiviert + brush_transform: Pinsel Transformation gesetzt + brush_material: Pinsel Material gesetzt + brush_recursive: Rekursiver Pinsel ausgerüstet (%s0). + brush_try_other: |- + &cFAWE adds other, more suitable brushes e.g. + &8 - &7//br height [radius=5] [#clipboard|file=null] [rotation=0] [yscale=1.00] + brush_none: You aren't holding a brush! + brush_source_mask_disabled: Pinsel Quell-Maske deaktiviert + brush_source_mask: Pinsel Quell-Maske gesetzt + rollback: + rollback_element: annullierend %s0 + tool: + tool_inspect: Inpektions-Tool gebunden an %s0. + tool_inspect_info: '&7%s0 änderte %s1 zu %s2 %s3 zuvor' + tool_inspect_info_footer: '&6Total: &7%s0 Änderungen' + tool_none: Tool vom aktuellen Item entfernt. + tool_info: Info-Tool gebunden an %s0. + tool_tree: Tree-Tool gebunden an %s0. + tool_tree_error: Baum Typ %s0 ist unbekannt. + tool_repl: Block Replacer-Tool gebunden an %s0. + tool_cycler: Block Data Cycler-Tool gebunden an %s0. + tool_flood_fill: Block Flood Fill-Tool gebunden an %s0. + tool_deltree: Floating Tree Remover-Tool gebunden an %s0. + tool_farwand: Far Wand-Tool gebunden an%s0. + tool_lrbuild_bound: Long-range Building-Tool gebunden an %s0. + tool_lrbuild_info: 'Linksklick: Setze Position %s0; Rechtsklick: Setze Position + %s1' + superpickaxe_enabled: Super Pickaxe aktiviert. + superpickaxe_disabled: Super Pickaxe deaktiviert. + tool_range_error: 'Maximale Reichweite: %s0.' + tool_radius_error: 'Maximal erlaubter Pinsel Radius: %s0.' + superpickaxe_area_enabled: Modus geändert. Linksklick mit einer Spitzhacke. // zum deaktivieren. + schematic: + schematic_delete: Schematic %s0 wurde gelöscht. + schematic_format: 'Verfügbare Zwischenspeicher Formate (Name: Suche Namen)' + schematic_loaded: Schematic %s0 geladen. Platziere es mit //paste + schematic_saved: Schematic %s0 gespeichert. + schematic_page: Seite muss %s sein + schematic_none: Keine Schematics gefunden. + schematic_list: 'Verfügbare Schematics (Filename: Format) [%s0/%s1]:' + clipboard: + clipboard_cleared: Zwischenablage geleert + clipboard_invalid_format: 'Unbekanntes Zwischenspeicher Format: %s0' + visitor: + visitor_block: '%s0 Blöcke betroffen' + visitor_entity: '%s0 Entities betroffen' + visitor_flat: '%s0 Rubriken betroffen' + selector: + selector_cuboid_pos1: Pos 1 gesetzt %s0 %s1. + selector_cuboid_pos2: Pos 2 gesetzt %s0 %s1. + selector_invalid_coordinates: Ungültige Koordinaten %s0 + selector_already_set: Position bereits gesetzt. + selector_fuzzy_pos1: Region gesetzt und expandiert von %s0 %s1. + selector_fuzzy_pos2: Erweiterung hinzugefügt um %s0 %s1. + selector_set_default: Dein Standard Auswahl-Tool ist nun %s0. + command: + command_invalid_syntax: The command was not used properly (no more help available). + snapshot: + snapshot_loaded: Snapshot '%s0' loaded; now restoring... + snapshot_set: 'Snapshot set to: %s0' + snapshot_newest: Now using newest snapshot. + snapshot_list_header: 'Snapshots for world (%s0):' + snapshot_list_footer: Use /snap use [snapshot] or /snap use latest. + biome: + biome_list_header: 'Biome (page %s0/%s1):' + biome_changed: Biome wurden geändert in %s0 Bezirken. + utility: + kill_success: '%s0 Entities in einem Radius von %s1 getötet.' + timezone: + timezone_set: 'Zeitzone für diese Sitzung gesetzt auf: %s0' + timezone_display: 'Aktuelle Zeit in dieser Zeitzone: %s0' +progress: + progress_message: '[ Zwischenspeicher: %s0 | Erledigt: %s1 ]' + progress_finished: '[ Fertiggestellt! ]' +cancel: + worldedit_cancel_count: '&c%s0 Veränderungen abgebrochen.' + worldedit_cancel_reason: '&cDeine WorldEdit Aktion wurde abgebrochen:&7 %s0&c.' + worldedit_cancel_reason_manual: Manueller Abbruch + worldedit_cancel_reason_low_memory: Zu wenig Speicher + worldedit_cancel_reason_max_changes: Zu viele Blöcke bearbeitet + worldedit_cancel_reason_max_checks: Zu viele Blöcke gecheckt + worldedit_cancel_reason_max_tiles: Zu viele Blockstatus + worldedit_cancel_reason_max_entities: Zu viele Entities + worldedit_cancel_reason_max_iterations: Maximale Wiederholungen + worldedit_cancel_reason_max_fails: Ausserhalb erlaubter Regionen (Bypass mit /wea) + worldedit_cancel_reason_no_region: Keine erlaubte Region (Bypass mit /wea) + worldedit_failed_load_chunk: '&cÜberspringe das Laden von Chunk: &7%s0;%s1&c. Versuche + chunk-wait zu erhöhen.' +history: + loading_clipboard: Lade Zwischenablage bitte warten. + indexing_history: Indiziere %s Verlauf auf der Platte, Bitte warten. + indexing_complete: 'Indizierung vollständig. Dauer: %s Sekunden!' +navigation: + ascend_fail: Kein freier Platz über dir gefunden. + ascended_plural: '%s0 Schichten aufgestiegen.' + ascended_singular: Eine Schicht aufgestiegen. + unstuck: Auf gehts! + descend_fail: Kein freier Platz unter dir gefunden. + descend_plural: '%s0 Schichten abgestiegen.' + descend_singular: Eine Schicht abgestiegen. + whoosh: Whoosh! + poof: Poof! + thru_fail: Kein freier Platz vor dir gefunden. + up_fail: Du würdest einen Block treffen! + no_block: Kein Block in Sichweite! (oder zu weit entfernt) +selection: + sel_cuboid: 'Quader: Linksklick für Position1, Rechtsklick für Position2' + sel_cuboid_extend: 'Quader: Linksklick für einen Startpunkt, Rechtsklick zum erweitern' + sel_2d_polygon: '2D Polygon Selektierer: Links/Rechtsklick um eine Markierung hinzuzufügen.' + sel_ellipsiod: 'Ellipsen Selektierer: Linksklick=Mitte, Rechtsklick zum erweitern' + sel_sphere: 'Kugel Selektierer : Linksklick=Mitte, Rechtsklick um den Radius zu + setzen' + sel_cylindrical: 'Zylinder Selektierer: Linksklick=Mitte, Rechtsklick zum erweitern' + sel_max: '%s0 Punkte maximal.' + sel_fuzzy: 'Fuzzy Selektierer: Linksklick um alle verbundenen Blöcke zu markieren, + Rechtsklick zum hinzufügen' + sel_convex_polyhedral: 'Convex polyhedral selector: Left click=First vertex, right + click to add more.' + sel_list: Für eine Liste der Selektoren nutze:&c //sel + sel_modes: 'Wähle einen der unten aufgelisteten Modi:' +tips: + tip_cancel: 'Tip: Du kannst eine Aktion abbrechen mit `//cancel`' + tip_download: 'Tip: Du kannst deinen Zwischenspeicher mit`//download` herunterladen' + tip_sel_list: 'Tip: Liste die verschiedenen Selektoren auf mit &c//sel list' + tip_select_connected: 'Tip: Wähle alle verbundenen Blöcke mit //sel fuzzy' + tip_set_pos1: 'Tip: Nutze pos1 als Muster &c//set pos1' + tip_farwand: 'Tip: Markiere entferne Blöcke mit &c//farwand' + tip_fast: '&7Tip: Platziere schnell und ohne Undo-Historie &c//fast' + tip_mask: '&7Tip: Setze eine Globale Zielmaske mit &c/gmask' + tip_mask_angle: 'Tip: Ersetze aufwärts Steigungen von 3-20 Blöcken mit&c //replace + /-20:-3 bedrock' + tip_set_linear: '&7Tip: Setze Blöcke linear mit&c //set #l3d:wood,bedrock' + tip_surface_spread: '&7Tip: Streue einen flachen Untergrund mit&c //set #surfacespread:5:0:5:#existing' + tip_set_hand: '&7Tip: Setze das Item in deiner Hand mit&c//set hand' + tip_replace_id: '&7Tip: Ersetze nur die Block-ID:&c //replace woodenstair #id:cobblestair' + tip_replace_light: 'Tip: Entferne Licht-Quellen&c //replace #brightness:1:15 0' + tip_tab_complete: 'Tip: Der Replace-Befehl unterstützt Tab-Vervollständigung' + tip_flip: 'Tip: Spiegeln mit &c//flip' + tip_deform: 'Tip: Forme um mit &c//deform' + tip_transform: 'Tip: Platziere eine Umformung mit &c//gtransform' + tip_copypaste: 'Tip: Füge durch Klick ein mit &c//br copypaste' + tip_source_mask: 'Tip: Setze eine Quell-Maske &c/gsmask &7' + tip_replace_marker: 'Tip: Ersetze einen Block mit deinem vollständigen Zwischenspeicher + mit &c//replace wool #fullcopy' + tip_paste: 'Tip: Füge deine Zwischeneinlage mit &c//paste ein' + tip_lazycopy: 'Tip: lazycopy ist schneller' + tip_rotate: 'Tip: Ausrichten mit &c//rotate' + tip_copy_pattern: 'Tip: Um ein Muster zu verwenden nutze &c#copy' + tip_brush_spline: '&7Tip Der spline &c//brush &7verbindet multiple Formen miteinander' + tip_brush_height: '&7Tip: Der Höhe &c//brush &7erhöht oder senkt Terrain sanft' + tip_brush_copy: '&7Tip: Der copypaste &c//brush &7erlaubt dir leichtes kopieren + und einfügen von Objekten.' + tip_brush_mask: '&7Tip: Setze eine brush Ziel-Maske mit &c/mask' + tip_brush_mask_source: '&7Tip: Setze eine brush Quell-Maske mit &c/smask' + tip_brush_transform: '&7Tip: Setze eine brush Transformation mit &c/transform' + tip_brush_relative: '&7Tip: Nutze ein relatives Zwischenspeicher-Muster mit //br + sphere #~:#copy' + tip_brush_command: '&7Tip: Probiere den Befehl &c//br cmd ' + tip_lazycut: '&7Tip: Es ist sicherer den Befehl &c//lazycut zu verwenden.' diff --git a/forge110/build.gradle b/forge110/build.gradle index 4376197b..157620f4 100644 --- a/forge110/build.gradle +++ b/forge110/build.gradle @@ -21,9 +21,6 @@ dependencies { compile 'com.sk89q.worldedit:worldedit-forge-mc1.8.9:6.1.1' } -sourceCompatibility = 1.8 -targetCompatibility = 1.8 - repositories { maven { name = 'forge' diff --git a/forge110/src/main/java/com/boydti/fawe/forge/ForgePlayer.java b/forge110/src/main/java/com/boydti/fawe/forge/ForgePlayer.java index 17cc95e9..e23efdfe 100644 --- a/forge110/src/main/java/com/boydti/fawe/forge/ForgePlayer.java +++ b/forge110/src/main/java/com/boydti/fawe/forge/ForgePlayer.java @@ -71,7 +71,7 @@ public class ForgePlayer extends FawePlayer { } @Override - public Player getPlayer() { + public Player toWorldEditPlayer() { return PlayerWrapper.wrap(ForgeWorldEdit.inst.wrap(this.parent)); } } diff --git a/forge111/build.gradle b/forge111/build.gradle index db87e419..328e7c58 100644 --- a/forge111/build.gradle +++ b/forge111/build.gradle @@ -21,9 +21,6 @@ dependencies { compile 'com.sk89q.worldedit:worldedit-forge-mc1.8.9:6.1.1' } -sourceCompatibility = 1.8 -targetCompatibility = 1.8 - repositories { maven { name = 'forge' diff --git a/forge111/src/main/java/com/boydti/fawe/forge/ForgePlayer.java b/forge111/src/main/java/com/boydti/fawe/forge/ForgePlayer.java index 971974c2..ed2461a6 100644 --- a/forge111/src/main/java/com/boydti/fawe/forge/ForgePlayer.java +++ b/forge111/src/main/java/com/boydti/fawe/forge/ForgePlayer.java @@ -71,7 +71,7 @@ public class ForgePlayer extends FawePlayer { } @Override - public Player getPlayer() { + public Player toWorldEditPlayer() { return PlayerWrapper.wrap(ForgeWorldEdit.inst.wrap(this.parent)); } } diff --git a/forge1710/build.gradle b/forge1710/build.gradle index 621473d0..caf8f53a 100644 --- a/forge1710/build.gradle +++ b/forge1710/build.gradle @@ -21,9 +21,6 @@ dependencies { compile 'net.minecraftforge.gradle:ForgeGradle:1.2-SNAPSHOT' } -sourceCompatibility = 1.7 -targetCompatibility = 1.7 - repositories { maven { name = 'forge' diff --git a/forge1710/src/main/java/com/boydti/fawe/forge/ForgePlayer.java b/forge1710/src/main/java/com/boydti/fawe/forge/ForgePlayer.java index a7e1b5bf..4a350d3c 100644 --- a/forge1710/src/main/java/com/boydti/fawe/forge/ForgePlayer.java +++ b/forge1710/src/main/java/com/boydti/fawe/forge/ForgePlayer.java @@ -73,7 +73,7 @@ public class ForgePlayer extends FawePlayer { } @Override - public Player getPlayer() { + public Player toWorldEditPlayer() { return ForgeWorldEdit.inst.wrap(this.parent); } } diff --git a/forge189/build.gradle b/forge189/build.gradle index 0d99fdcc..b9b68b25 100644 --- a/forge189/build.gradle +++ b/forge189/build.gradle @@ -21,9 +21,6 @@ dependencies { compile 'com.sk89q.worldedit:worldedit-forge-mc1.8.9:6.1.1' } -sourceCompatibility = 1.8 -targetCompatibility = 1.8 - repositories { maven { name = 'forge' diff --git a/forge189/src/main/java/com/boydti/fawe/forge/ForgePlayer.java b/forge189/src/main/java/com/boydti/fawe/forge/ForgePlayer.java index c61cdcf0..75215501 100644 --- a/forge189/src/main/java/com/boydti/fawe/forge/ForgePlayer.java +++ b/forge189/src/main/java/com/boydti/fawe/forge/ForgePlayer.java @@ -74,7 +74,7 @@ public class ForgePlayer extends FawePlayer { } @Override - public Player getPlayer() { + public Player toWorldEditPlayer() { return PlayerWrapper.wrap(ForgeWorldEdit.inst.wrap(this.parent)); } } diff --git a/forge194/build.gradle b/forge194/build.gradle index 045233e2..4bfbc6cf 100644 --- a/forge194/build.gradle +++ b/forge194/build.gradle @@ -20,9 +20,6 @@ dependencies { compile 'com.sk89q.worldedit:worldedit-forge-mc1.8.9:6.1.1' } -sourceCompatibility = 1.8 -targetCompatibility = 1.8 - repositories { maven { name = 'forge' diff --git a/forge194/src/main/java/com/boydti/fawe/forge/ForgePlayer.java b/forge194/src/main/java/com/boydti/fawe/forge/ForgePlayer.java index 161f7d5c..88117dd3 100644 --- a/forge194/src/main/java/com/boydti/fawe/forge/ForgePlayer.java +++ b/forge194/src/main/java/com/boydti/fawe/forge/ForgePlayer.java @@ -22,10 +22,12 @@ public class ForgePlayer extends FawePlayer { @Override public void sendTitle(String head, String sub) { // Not supported + Settings.IMP.QUEUE.PROGRESS.DISPLAY = "false"; } @Override public void resetTitle() { // Not supported + Settings.IMP.QUEUE.PROGRESS.DISPLAY = "false"; } @Override @@ -71,7 +73,7 @@ public class ForgePlayer extends FawePlayer { } @Override - public Player getPlayer() { + public Player toWorldEditPlayer() { return PlayerWrapper.wrap(ForgeWorldEdit.inst.wrap(this.parent)); } } diff --git a/nukkit/src/main/java/com/boydti/fawe/nukkit/optimization/FaweNukkit.java b/nukkit/src/main/java/com/boydti/fawe/nukkit/optimization/FaweNukkit.java index 4619085b..d1df58a7 100644 --- a/nukkit/src/main/java/com/boydti/fawe/nukkit/optimization/FaweNukkit.java +++ b/nukkit/src/main/java/com/boydti/fawe/nukkit/optimization/FaweNukkit.java @@ -14,6 +14,7 @@ import com.boydti.fawe.object.FaweChunk; import com.boydti.fawe.object.FaweCommand; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FaweQueue; +import com.boydti.fawe.object.brush.visualization.VisualChunk; import com.boydti.fawe.regions.FaweMaskManager; import com.boydti.fawe.util.TaskManager; import com.sk89q.worldedit.world.World; @@ -30,6 +31,7 @@ public class FaweNukkit implements IFawe, Listener { public FaweNukkit(NukkitWorldEdit mod) { this.plugin = mod; FaweChunk.HEIGHT = 256; + VisualChunk.VISUALIZE_BLOCK = 241 << 4; plugin.getServer().getPluginManager().registerEvents(this, plugin); } diff --git a/nukkit/src/main/java/com/boydti/fawe/nukkit/optimization/FaweNukkitPlayer.java b/nukkit/src/main/java/com/boydti/fawe/nukkit/optimization/FaweNukkitPlayer.java index f0ba35e6..c223b457 100644 --- a/nukkit/src/main/java/com/boydti/fawe/nukkit/optimization/FaweNukkitPlayer.java +++ b/nukkit/src/main/java/com/boydti/fawe/nukkit/optimization/FaweNukkitPlayer.java @@ -66,7 +66,7 @@ public class FaweNukkitPlayer extends FawePlayer { } @Override - public com.sk89q.worldedit.entity.Player getPlayer() { + public com.sk89q.worldedit.entity.Player toWorldEditPlayer() { return new NukkitPlayer((NukkitPlatform) Fawe. imp().getPlugin().getPlatform(), parent); } diff --git a/sponge/build.gradle b/sponge/build.gradle index dd155115..fc37ab46 100644 --- a/sponge/build.gradle +++ b/sponge/build.gradle @@ -52,9 +52,6 @@ dependencies { compile name: 'worldedit-core-6.1.7-SNAPSHOT-dist' } -sourceCompatibility = 1.8 -targetCompatibility = 1.8 - minecraft { version = "1.11" mappings = "snapshot_20161116" diff --git a/sponge/src/main/java/com/boydti/fawe/sponge/SpongePlayer.java b/sponge/src/main/java/com/boydti/fawe/sponge/SpongePlayer.java index fc292463..3c0a4036 100644 --- a/sponge/src/main/java/com/boydti/fawe/sponge/SpongePlayer.java +++ b/sponge/src/main/java/com/boydti/fawe/sponge/SpongePlayer.java @@ -73,7 +73,7 @@ public class SpongePlayer extends FawePlayer { } @Override - public com.sk89q.worldedit.entity.Player getPlayer() { + public com.sk89q.worldedit.entity.Player toWorldEditPlayer() { if (WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.USER_COMMANDS) != null) { for (Platform platform : WorldEdit.getInstance().getPlatformManager().getPlatforms()) { return platform.matchPlayer(new FakePlayer(getName(), getUUID(), null));