From 4d02548b04fbeb05a493814555b9e87ed57d5d9b Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Thu, 31 Aug 2017 16:03:43 +1000 Subject: [PATCH] (Experimental) Persistent brushes (config option) Brushes can be bound to the item instead of being stored in the player's LocalSession. - Brushes can be shared by dropping the item - Hasn't been fully tested, there may be bugs or performance issues --- .../com/boydti/fawe/bukkit/FaweBukkit.java | 20 ++++ .../bukkit/block/BrushBoundBaseBlock.java | 94 ++++++++++++++++++ .../bukkit/{ => listener}/BrushListener.java | 2 +- .../bukkit/{ => listener}/RenderListener.java | 2 +- .../fawe/bukkit/{ => util}/BukkitTaskMan.java | 2 +- .../com/boydti/fawe/bukkit/util/ItemUtil.java | 95 +++++++++++++++++++ .../fawe/bukkit/{ => util}/VaultUtil.java | 2 +- .../sk89q/worldedit/bukkit/BukkitPlayer.java | 13 ++- .../java/com/boydti/fawe/config/Settings.java | 4 + .../com/sk89q/worldedit/LocalSession.java | 53 +++++++---- .../command/BrushOptionsCommands.java | 16 +++- .../worldedit/command/BrushProcessor.java | 3 +- .../worldedit/command/tool/BrushHolder.java | 7 ++ .../worldedit/command/tool/BrushTool.java | 27 ++++++ 14 files changed, 308 insertions(+), 32 deletions(-) create mode 100644 bukkit/src/main/java/com/boydti/fawe/bukkit/block/BrushBoundBaseBlock.java rename bukkit/src/main/java/com/boydti/fawe/bukkit/{ => listener}/BrushListener.java (98%) rename bukkit/src/main/java/com/boydti/fawe/bukkit/{ => listener}/RenderListener.java (99%) rename bukkit/src/main/java/com/boydti/fawe/bukkit/{ => util}/BukkitTaskMan.java (97%) create mode 100644 bukkit/src/main/java/com/boydti/fawe/bukkit/util/ItemUtil.java rename bukkit/src/main/java/com/boydti/fawe/bukkit/{ => util}/VaultUtil.java (93%) create mode 100644 core/src/main/java/com/sk89q/worldedit/command/tool/BrushHolder.java 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 900d809d..a1017c4b 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java @@ -3,6 +3,8 @@ package com.boydti.fawe.bukkit; import com.boydti.fawe.Fawe; import com.boydti.fawe.IFawe; import com.boydti.fawe.bukkit.chat.BukkitChatManager; +import com.boydti.fawe.bukkit.listener.BrushListener; +import com.boydti.fawe.bukkit.listener.RenderListener; import com.boydti.fawe.bukkit.regions.FactionsFeature; import com.boydti.fawe.bukkit.regions.FactionsOneFeature; import com.boydti.fawe.bukkit.regions.FactionsUUIDFeature; @@ -12,6 +14,9 @@ import com.boydti.fawe.bukkit.regions.PreciousStonesFeature; import com.boydti.fawe.bukkit.regions.ResidenceFeature; import com.boydti.fawe.bukkit.regions.TownyFeature; import com.boydti.fawe.bukkit.regions.Worldguard; +import com.boydti.fawe.bukkit.util.BukkitTaskMan; +import com.boydti.fawe.bukkit.util.ItemUtil; +import com.boydti.fawe.bukkit.util.VaultUtil; import com.boydti.fawe.bukkit.v0.BukkitQueue_0; import com.boydti.fawe.bukkit.v0.BukkitQueue_All; import com.boydti.fawe.bukkit.v0.ChunkListener; @@ -62,6 +67,7 @@ public class FaweBukkit implements IFawe, Listener { private final BukkitMain plugin; private VaultUtil vault; private WorldEditPlugin worldedit; + private ItemUtil itemUtil; public VaultUtil getVault() { return this.vault; @@ -96,6 +102,16 @@ public class FaweBukkit implements IFawe, Listener { e.printStackTrace(); debug("==================================="); } + if (Settings.IMP.EXPERIMENTAL.PERSISTENT_BRUSHES) { + try { + this.itemUtil = new ItemUtil(); + } catch (Throwable e) { + Settings.IMP.EXPERIMENTAL.PERSISTENT_BRUSHES = false; + debug("===== PERSISTENT BRUSH FAILED ====="); + e.printStackTrace(); + debug("==================================="); + } + } if (Bukkit.getVersion().contains("git-Spigot")) { debug("====== USE PAPER ======"); debug("DOWNLOAD: https://ci.destroystokyo.com/job/PaperSpigot/"); @@ -235,6 +251,10 @@ public class FaweBukkit implements IFawe, Listener { }); } + public ItemUtil getItemUtil() { + return itemUtil; + } + /** * Vault isn't required, but used for setting player permissions (WorldEdit bypass) * @return diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/block/BrushBoundBaseBlock.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/block/BrushBoundBaseBlock.java new file mode 100644 index 00000000..3f488aec --- /dev/null +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/block/BrushBoundBaseBlock.java @@ -0,0 +1,94 @@ +package com.boydti.fawe.bukkit.block; + +import com.boydti.fawe.Fawe; +import com.boydti.fawe.bukkit.FaweBukkit; +import com.boydti.fawe.bukkit.util.ItemUtil; +import com.boydti.fawe.object.collection.SoftHashMap; +import com.boydti.fawe.util.ReflectionUtils; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.command.tool.BrushHolder; +import com.sk89q.worldedit.command.tool.BrushTool; +import com.sk89q.worldedit.entity.Player; +import java.util.HashMap; +import java.util.Map; +import org.bukkit.inventory.ItemStack; + +public class BrushBoundBaseBlock extends BaseBlock implements BrushHolder { + public static SoftHashMap brushCache = new SoftHashMap<>(); + private final LocalSession session; + private final Player player; + + private ItemStack item; + private BrushTool tool; + + private static CompoundTag getNBT(ItemStack item) { + ItemUtil util = Fawe.imp().getItemUtil(); + return util != null && item.hasItemMeta() ? util.getNBT(item) : null; + } + + private static Object getKey(ItemStack item) { + ItemUtil util = Fawe.imp().getItemUtil(); + return util != null ? util.getNMSItem(item) : item; + } + + public BrushBoundBaseBlock(Player player, LocalSession session, ItemStack item) { + super(item.getTypeId(), item.getType().getMaxDurability() != 0 ? 0 : Math.max(0, item.getDurability()), getNBT(item)); + this.item = item; + this.tool = brushCache.get(getKey(item)); + this.player = player; + this.session = session; + } + + @Override + public BrushTool getTool() { + if (tool == null && hasNbtData()) { + String json = getNbtData().getString("weBrushJson"); + if (json != null) { + try { + this.tool = BrushTool.fromString(player, session, json); + this.tool.setHolder(this); + } catch (Throwable ignore) { + ignore.printStackTrace(); + } + } + } + return this.tool; + } + + public ItemStack getItem() { + return item; + } + + @Override + public BrushTool setTool(BrushTool tool) { + this.tool = tool; + CompoundTag nbt = getNbtData(); + Map map; + if (nbt == null) { + if (tool == null) { + return tool; + } + setNbtData(nbt = new CompoundTag(map = new HashMap<>())); + } else { + map = ReflectionUtils.getMap(nbt.getValue()); + } + brushCache.remove(getKey(item)); + if (tool != null) { + String json = tool.toString(); + map.put("weBrushJson", new StringTag(json)); + } else if (map.containsKey("weBrushJson")) { + map.remove("weBrushJson"); + } else { + return tool; + } + item = Fawe.imp().getItemUtil().setNBT(item, nbt); + if (tool != null) { + brushCache.put(getKey(item), tool); + } + return tool; + } +} \ No newline at end of file diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/BrushListener.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/listener/BrushListener.java similarity index 98% rename from bukkit/src/main/java/com/boydti/fawe/bukkit/BrushListener.java rename to bukkit/src/main/java/com/boydti/fawe/bukkit/listener/BrushListener.java index 5b119a5a..ae709da6 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/BrushListener.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/listener/BrushListener.java @@ -1,4 +1,4 @@ -package com.boydti.fawe.bukkit; +package com.boydti.fawe.bukkit.listener; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.brush.MovableTool; diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/RenderListener.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/listener/RenderListener.java similarity index 99% rename from bukkit/src/main/java/com/boydti/fawe/bukkit/RenderListener.java rename to bukkit/src/main/java/com/boydti/fawe/bukkit/listener/RenderListener.java index 3a55a989..7de44adc 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/RenderListener.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/listener/RenderListener.java @@ -1,4 +1,4 @@ -package com.boydti.fawe.bukkit; +package com.boydti.fawe.bukkit.listener; import com.boydti.fawe.Fawe; import com.boydti.fawe.object.FawePlayer; diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitTaskMan.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/util/BukkitTaskMan.java similarity index 97% rename from bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitTaskMan.java rename to bukkit/src/main/java/com/boydti/fawe/bukkit/util/BukkitTaskMan.java index f3248a89..12de1f9e 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitTaskMan.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/util/BukkitTaskMan.java @@ -1,4 +1,4 @@ -package com.boydti.fawe.bukkit; +package com.boydti.fawe.bukkit.util; import com.boydti.fawe.util.TaskManager; import org.apache.commons.lang.mutable.MutableInt; diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/util/ItemUtil.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/util/ItemUtil.java new file mode 100644 index 00000000..e39150f9 --- /dev/null +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/util/ItemUtil.java @@ -0,0 +1,95 @@ +package com.boydti.fawe.bukkit.util; + +import com.boydti.fawe.bukkit.v0.BukkitQueue_0; +import com.boydti.fawe.util.ReflectionUtils; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.Tag; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import org.bukkit.inventory.ItemStack; + +public class ItemUtil { + + private final Class classCraftItemStack; + private final Method methodAsNMSCopy; + private final Class classNMSItem; + private final Method methodGetTag; + private final Method methodHasTag; + private final Method methodSetTag; + private final Method methodAsBukkitCopy; + private final Field fieldHandle; + + private SoftReference>> hashToNMSTag = new SoftReference(new Int2ObjectOpenHashMap<>()); + + public ItemUtil() throws Exception { + this.classCraftItemStack = ReflectionUtils.getCbClass("inventory.CraftItemStack"); + this.classNMSItem = ReflectionUtils.getNmsClass("ItemStack"); + this.methodAsNMSCopy = ReflectionUtils.setAccessible(classCraftItemStack.getDeclaredMethod("asNMSCopy", ItemStack.class)); + this.methodHasTag = ReflectionUtils.setAccessible(classNMSItem.getDeclaredMethod("hasTag")); + this.methodGetTag = ReflectionUtils.setAccessible(classNMSItem.getDeclaredMethod("getTag")); + this.fieldHandle = ReflectionUtils.setAccessible(classCraftItemStack.getDeclaredField("handle")); + Class classNBTTagCompound = ReflectionUtils.getNmsClass("NBTTagCompound"); + this.methodSetTag = ReflectionUtils.setAccessible(classNMSItem.getDeclaredMethod("setTag", classNBTTagCompound)); + this.methodAsBukkitCopy = ReflectionUtils.setAccessible(classCraftItemStack.getDeclaredMethod("asBukkitCopy", classNMSItem)); + } + + public Object getNMSItem(ItemStack item) { + try { + Object nmsItem = fieldHandle.get(item); + if (nmsItem == null) nmsItem = methodAsNMSCopy.invoke(null, item); + return item; + } catch (Throwable e) { + e.printStackTrace(); + } + return null; + } + + public CompoundTag getNBT(ItemStack item) { + try { + Object nmsItem = fieldHandle.get(item); + if (nmsItem == null) nmsItem = methodAsNMSCopy.invoke(null, item); + if (methodHasTag.invoke(nmsItem).equals(true)) { + Object nmsTag = methodGetTag.invoke(nmsItem); + if (nmsTag == null) return null; + + Int2ObjectOpenHashMap> map = hashToNMSTag.get(); + if (map == null) { + map = new Int2ObjectOpenHashMap<>(); + hashToNMSTag = new SoftReference(new Int2ObjectOpenHashMap<>(map)); + } + WeakReference nativeTagRef = map.get(nmsTag.hashCode()); + if (nativeTagRef != null) { + Tag nativeTag = nativeTagRef.get(); + if (nativeTag != null) return (CompoundTag) nativeTag; + } + Tag nativeTag = BukkitQueue_0.toNative(nmsTag); + map.put(nmsTag.hashCode(), new WeakReference(nativeTag)); + return null; + } + } catch (Throwable e) { + e.printStackTrace(); + } + return null; + } + + public ItemStack setNBT(ItemStack item, CompoundTag tag) { + try { + Object nmsItem = fieldHandle.get(item); + boolean copy = false; + if (nmsItem == null) { + copy = true; + nmsItem = methodAsNMSCopy.invoke(null, item); + } + Object nmsTag = BukkitQueue_0.fromNative(tag); + methodSetTag.invoke(nmsItem, nmsTag); + if (copy) return (ItemStack) methodAsBukkitCopy.invoke(null, nmsItem); + return item; + } catch (Throwable e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/VaultUtil.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/util/VaultUtil.java similarity index 93% rename from bukkit/src/main/java/com/boydti/fawe/bukkit/VaultUtil.java rename to bukkit/src/main/java/com/boydti/fawe/bukkit/util/VaultUtil.java index dff828e4..dfc2cde8 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/VaultUtil.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/util/VaultUtil.java @@ -1,4 +1,4 @@ -package com.boydti.fawe.bukkit; +package com.boydti.fawe.bukkit.util; import net.milkbowl.vault.permission.Permission; import org.bukkit.Bukkit; diff --git a/bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java index ad5a2ed1..628a322c 100644 --- a/bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java +++ b/bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java @@ -19,7 +19,11 @@ package com.sk89q.worldedit.bukkit; +import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; +import com.boydti.fawe.bukkit.FaweBukkit; +import com.boydti.fawe.bukkit.block.BrushBoundBaseBlock; +import com.boydti.fawe.config.Settings; import com.boydti.fawe.wrappers.WorldWrapper; import com.sk89q.util.StringUtil; import com.sk89q.worldedit.EditSession; @@ -80,13 +84,14 @@ public class BukkitPlayer extends LocalPlayer { } final int typeId = itemStack.getTypeId(); switch (typeId) { + case 0: + return EditSession.nullBlock; case ItemID.INK_SACK: final Dye materialData = (Dye) itemStack.getData(); if (materialData.getColor() == DyeColor.BROWN) { return FaweCache.getBlock(BlockID.COCOA_PLANT, 0); } break; - case ItemID.HEAD: return new SkullBlock(0, (byte) itemStack.getDurability()); @@ -97,7 +102,11 @@ public class BukkitPlayer extends LocalPlayer { } break; } - return FaweCache.getBlock(typeId, itemStack.getType().getMaxDurability() != 0 ? 0 : Math.max(0, itemStack.getDurability())); + BaseBlock block = FaweCache.getBlock(typeId, itemStack.getType().getMaxDurability() != 0 ? 0 : Math.max(0, itemStack.getDurability())); + if (Settings.IMP.EXPERIMENTAL.PERSISTENT_BRUSHES && Fawe.imp().getItemUtil() != null) { + return new BrushBoundBaseBlock(this, WorldEdit.getInstance().getSession(this), itemStack); + } + return block; } @Override 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 7e825f84..21263258 100644 --- a/core/src/main/java/com/boydti/fawe/config/Settings.java +++ b/core/src/main/java/com/boydti/fawe/config/Settings.java @@ -306,6 +306,10 @@ public class Settings extends Config { " - Please provide feedback", }) public boolean DYNAMIC_CHUNK_RENDERING = false; + @Comment({ + "Allows brushes to be persistent", + }) + public boolean PERSISTENT_BRUSHES = false; } public static class WEB { diff --git a/core/src/main/java/com/sk89q/worldedit/LocalSession.java b/core/src/main/java/com/sk89q/worldedit/LocalSession.java index 83d79cb1..328354f3 100644 --- a/core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -41,6 +41,7 @@ import com.sk89q.jchronic.utils.Span; import com.sk89q.jchronic.utils.Time; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.command.tool.BlockTool; +import com.sk89q.worldedit.command.tool.BrushHolder; import com.sk89q.worldedit.command.tool.BrushTool; import com.sk89q.worldedit.command.tool.InvalidToolBindException; import com.sk89q.worldedit.command.tool.SinglePickaxe; @@ -960,18 +961,26 @@ public class LocalSession { @Nullable public Tool getTool(Player player) { - if (tools.isEmpty()) { + if (!Settings.IMP.EXPERIMENTAL.PERSISTENT_BRUSHES && tools.isEmpty()) { return null; } try { BaseBlock block = player.getBlockInHand(); - return getTool(block.getId(), block.getData()); + return getTool(block, player); } catch (WorldEditException e) { e.printStackTrace(); return null; } } + public Tool getTool(BaseBlock block, Player player) { + if (block instanceof BrushHolder) { + BrushTool tool = ((BrushHolder) block).getTool(); + if (tool != null) return tool; + } + return getTool(block.getId(), block.getData()); + } + /** * 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 @@ -981,16 +990,15 @@ public class LocalSession { * @return the tool, or {@code null} * @throws InvalidToolBindException if the item can't be bound to that item */ + @Deprecated public BrushTool getBrushTool(int item) throws InvalidToolBindException { - return getBrushTool(item, 0, null, true); + return getBrushTool(FaweCache.getBlock(item, 0), null, true); } - @Deprecated public BrushTool getBrushTool(Player player) throws InvalidToolBindException { return getBrushTool(player, true); } - @Deprecated public BrushTool getBrushTool(Player player, boolean create) throws InvalidToolBindException { BaseBlock block; try { @@ -999,18 +1007,16 @@ public class LocalSession { e.printStackTrace(); block = EditSession.nullBlock; } - return getBrushTool(block.getId(), block.getData(), player, create); + return getBrushTool(block, player, create); } - @Deprecated - public BrushTool getBrushTool(int id, int data, Player player, boolean create) throws InvalidToolBindException { - Tool tool = getTool(id, data); - + public BrushTool getBrushTool(BaseBlock item, Player player, boolean create) throws InvalidToolBindException { + Tool tool = getTool(item, player); if ((tool == null || !(tool instanceof BrushTool))) { if (create) { tool = new BrushTool(); - setTool(id, data, tool, player); + setTool(item, tool, player); } else { return null; } @@ -1028,7 +1034,7 @@ public class LocalSession { */ @Deprecated public void setTool(int item, @Nullable Tool tool) throws InvalidToolBindException { - setTool(item, 0, tool, null); + setTool(FaweCache.getBlock(item, 0), tool, null); } public void setTool(@Nullable Tool tool, Player player) throws InvalidToolBindException { @@ -1039,10 +1045,12 @@ public class LocalSession { item = EditSession.nullBlock; e.printStackTrace(); } - setTool(item.getId(), item.getData(), tool, player); + setTool(item, tool, player); } - public void setTool(int id, int data, @Nullable Tool tool, Player player) throws InvalidToolBindException { + public void setTool(BaseBlock item, @Nullable Tool tool, Player player) throws InvalidToolBindException { + int id = item.getId(); + int data = item.getData(); if (id > 0 && id < 255) { throw new InvalidToolBindException(id, "Blocks can't be used"); } else if (id == config.wandItem) { @@ -1050,12 +1058,17 @@ public class LocalSession { } else if (id == config.navigationWand) { throw new InvalidToolBindException(id, "Already used for the navigation wand"); } - Tool previous = this.tools.put(FaweCache.getCombined(id, data), tool); - if (player != null) { - if (previous instanceof BrushTool) { - BrushTool brushTool = (BrushTool) previous; - brushTool.clear(player); - } + Tool previous; + if (player != null && (tool instanceof BrushTool || tool == null) && item instanceof BrushHolder) { + BrushHolder holder = (BrushHolder) item; + previous = holder.setTool((BrushTool) tool); + if (tool != null) ((BrushTool) tool).setHolder(holder); + } else { + previous = this.tools.put(FaweCache.getCombined(id, data), tool); + } + if (previous != null && player != null && previous instanceof BrushTool) { + BrushTool brushTool = (BrushTool) previous; + brushTool.clear(player); } } diff --git a/core/src/main/java/com/sk89q/worldedit/command/BrushOptionsCommands.java b/core/src/main/java/com/sk89q/worldedit/command/BrushOptionsCommands.java index c0b6536b..700dc7d1 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/BrushOptionsCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/BrushOptionsCommands.java @@ -118,7 +118,7 @@ public class BrushOptionsCommands extends MethodCommands { String json = in.readUTF(); BrushTool tool = BrushTool.fromString(player, session, json); BaseBlock item = player.getBlockInHand(); - session.setTool(item.getId(), item.getData(), tool, player); + session.setTool(item, tool, player); BBC.BRUSH_EQUIPPED.send(player, name); } catch (Throwable e) { e.printStackTrace(); @@ -194,11 +194,11 @@ public class BrushOptionsCommands extends MethodCommands { public void primary(Player player, LocalSession session, CommandContext args) throws WorldEditException { BaseBlock item = player.getBlockInHand(); BrushTool tool = session.getBrushTool(player, false); - session.setTool(item.getId(), item.getData(), null, player); + session.setTool(item, null, player); String cmd = "brush " + args.getJoinedStrings(0); CommandEvent event = new CommandEvent(player, cmd); CommandManager.getInstance().handleCommandOnCurrentThread(event); - BrushTool newTool = session.getBrushTool(item.getId(), item.getData(), player, false); + BrushTool newTool = session.getBrushTool(item, player, false); if (newTool != null && tool != null) { newTool.setSecondary(tool.getSecondary()); } @@ -214,11 +214,11 @@ public class BrushOptionsCommands extends MethodCommands { public void secondary(Player player, LocalSession session, CommandContext args) throws WorldEditException { BaseBlock item = player.getBlockInHand(); BrushTool tool = session.getBrushTool(player, false); - session.setTool(item.getId(), item.getData(), null, player); + session.setTool(item, null, player); String cmd = "brush " + args.getJoinedStrings(0); CommandEvent event = new CommandEvent(player, cmd); CommandManager.getInstance().handleCommandOnCurrentThread(event); - BrushTool newTool = session.getBrushTool(item.getId(), item.getData(), player, false); + BrushTool newTool = session.getBrushTool(item, player, false); if (newTool != null && tool != null) { newTool.setPrimary(tool.getPrimary()); } @@ -329,6 +329,7 @@ public class BrushOptionsCommands extends MethodCommands { settings.addSetting(BrushSettings.SettingType.SCROLL_ACTION, full); BBC.BRUSH_SCROLL_ACTION_SET.send(player, full); } + bt.update(); } @Command( @@ -359,6 +360,7 @@ public class BrushOptionsCommands extends MethodCommands { BrushSettings settings = offHand ? tool.getOffHand() : tool.getContext(); settings.addSetting(BrushSettings.SettingType.MASK, context.getString(context.argsLength() - 1)); settings.setMask(mask); + tool.update(); BBC.BRUSH_MASK.send(player); } @@ -391,6 +393,7 @@ public class BrushOptionsCommands extends MethodCommands { BrushSettings settings = offHand ? tool.getOffHand() : tool.getContext(); settings.addSetting(BrushSettings.SettingType.SOURCE_MASK, context.getString(context.argsLength() - 1)); settings.setSourceMask(mask); + tool.update(); BBC.BRUSH_SOURCE_MASK.send(player); } @@ -422,6 +425,7 @@ public class BrushOptionsCommands extends MethodCommands { BrushSettings settings = offHand ? tool.getOffHand() : tool.getContext(); settings.addSetting(BrushSettings.SettingType.TRANSFORM, context.getString(context.argsLength() - 1)); settings.setTransform(transform); + tool.update(); BBC.BRUSH_TRANSFORM.send(player); } @@ -447,6 +451,7 @@ public class BrushOptionsCommands extends MethodCommands { BrushSettings settings = offHand ? tool.getOffHand() : tool.getContext(); settings.setFill(pattern); settings.addSetting(BrushSettings.SettingType.FILL, context.getString(context.argsLength() - 1)); + tool.update(); BBC.BRUSH_MATERIAL.send(player); } @@ -487,6 +492,7 @@ public class BrushOptionsCommands extends MethodCommands { } BrushSettings settings = offHand ? tool.getOffHand() : tool.getContext(); settings.setSize(radius); + tool.update(); BBC.BRUSH_SIZE.send(player); } diff --git a/core/src/main/java/com/sk89q/worldedit/command/BrushProcessor.java b/core/src/main/java/com/sk89q/worldedit/command/BrushProcessor.java index 24702ce5..7e8791fa 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/BrushProcessor.java +++ b/core/src/main/java/com/sk89q/worldedit/command/BrushProcessor.java @@ -23,10 +23,11 @@ public class BrushProcessor implements CallableProcessor { public BrushSettings process(CommandLocals locals, BrushSettings settings) throws Command.CommandException, WorldEditException { Actor actor = locals.get(Actor.class); LocalSession session = worldEdit.getSessionManager().get(actor); + session.setTool(null, (Player) actor); BrushTool tool = session.getBrushTool((Player) actor); tool.setPrimary(settings); tool.setSecondary(settings); BBC.BRUSH_EQUIPPED.send(actor, ((String) locals.get("arguments")).split(" ")[1]); return null; } -} +} \ No newline at end of file diff --git a/core/src/main/java/com/sk89q/worldedit/command/tool/BrushHolder.java b/core/src/main/java/com/sk89q/worldedit/command/tool/BrushHolder.java new file mode 100644 index 00000000..254b61a5 --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/command/tool/BrushHolder.java @@ -0,0 +1,7 @@ +package com.sk89q.worldedit.command.tool; + +public interface BrushHolder { + BrushTool getTool(); + + BrushTool setTool(BrushTool tool); +} \ No newline at end of file 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 3df08352..6094b7db 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 @@ -81,6 +81,8 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool private transient VisualExtent visualExtent; private transient Lock lock = new ReentrantLock(); + private transient BrushHolder holder; + public BrushTool(String permission) { getContext().addPermission(permission); } @@ -117,6 +119,14 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool return tool; } + public void setHolder(BrushHolder holder) { + this.holder = holder; + } + + public boolean isSet() { + return primary.getBrush() != null || secondary.getBrush() != null; + } + @Override public String toString() { HashMap map = new HashMap<>(); @@ -139,6 +149,12 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool return new Gson().toJson(map); } + public void update() { + if (holder != null) { + holder.setTool(this); + } + } + private void writeObject(java.io.ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); stream.writeBoolean(primary == secondary); @@ -200,16 +216,19 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool checkNotNull(primary); this.primary = primary; this.context = primary; + update(); } public void setSecondary(BrushSettings secondary) { checkNotNull(secondary); this.secondary = secondary; this.context = secondary; + update(); } public void setTransform(ResettableExtent transform) { getContext().setTransform(transform); + update(); } /** @@ -246,6 +265,7 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool */ public void setMask(Mask filter) { this.getContext().setMask(filter); + update(); } /** @@ -255,6 +275,7 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool */ public void setSourceMask(Mask filter) { this.getContext().setSourceMask(filter); + update(); } /** @@ -266,6 +287,7 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool @Deprecated public void setBrush(Brush brush, String permission) { setBrush(brush, permission, null); + update(); } @Deprecated @@ -472,18 +494,22 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool public void setScrollAction(ScrollAction scrollAction) { this.getContext().setScrollAction(scrollAction); + update(); } public void setTargetOffset(int targetOffset) { this.targetOffset = targetOffset; + update(); } public void setTargetMode(TargetMode targetMode) { this.targetMode = targetMode != null ? targetMode : TargetMode.TARGET_BLOCK_RANGE; + update(); } public void setTargetMask(Mask mask) { this.targetMask = mask; + update(); } public void setVisualMode(Player player, VisualMode visualMode) { @@ -501,6 +527,7 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool } } } + update(); } public TargetMode getTargetMode() {