diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java index 7066da770..46a0564a6 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java @@ -22,6 +22,7 @@ package com.sk89q.worldedit.bukkit; import com.sk89q.util.StringUtil; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.entity.BaseEntity; @@ -31,6 +32,8 @@ import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.gamemode.GameMode; import com.sk89q.worldedit.world.gamemode.GameModes; import org.bukkit.Bukkit; @@ -239,4 +242,22 @@ public class BukkitPlayer extends AbstractPlayerActor { } + @Override + public void sendFakeBlock(Vector pos, BlockStateHolder block) { + Location loc = new Location(player.getWorld(), pos.getX(), pos.getY(), pos.getZ()); + if (block == null) { + player.sendBlockChange(loc, player.getWorld().getBlockAt(loc).getBlockData()); + } else { + player.sendBlockChange(loc, BukkitAdapter.adapt(block)); + if (block instanceof BaseBlock && ((BaseBlock) block).hasNbtData()) { + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + if (adapter != null) { + adapter.sendFakeNBT(player, pos, ((BaseBlock) block).getNbtData()); + if (block.getBlockType() == BlockTypes.STRUCTURE_BLOCK) { + adapter.sendFakeOP(player); + } + } + } + } + } } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java index 057742b92..ab0d08fba 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java @@ -150,7 +150,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { @Override public void onDisable() { WorldEdit worldEdit = WorldEdit.getInstance(); - worldEdit.getSessionManager().clear(); + worldEdit.getSessionManager().unload(); worldEdit.getPlatformManager().unregister(server); if (config != null) { config.unload(); diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java index 4a30a11c0..d075cac45 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java @@ -19,6 +19,8 @@ package com.sk89q.worldedit.bukkit.adapter; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.registry.state.Property; @@ -27,6 +29,7 @@ import com.sk89q.worldedit.world.block.BlockType; import org.bukkit.Location; import org.bukkit.block.Biome; import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; import java.util.Map; @@ -101,4 +104,21 @@ public interface BukkitImplAdapter { * @return The properties map */ Map getProperties(BlockType blockType); + + /** + * Send the given NBT data to the player. + * + * @param player The player + * @param pos The position + * @param nbtData The NBT Data + */ + void sendFakeNBT(Player player, Vector pos, CompoundTag nbtData); + + /** + * Make the client think it has operator status. + * This does not give them any operator capabilities. + * + * @param player The player + */ + void sendFakeOP(Player player); } diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1.class index 9655a35a6..80124e9d9 100644 Binary files a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1.class and b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1.class differ diff --git a/worldedit-bukkit/src/main/resources/defaults/config.yml b/worldedit-bukkit/src/main/resources/defaults/config.yml index fd931081f..a01430cfd 100644 --- a/worldedit-bukkit/src/main/resources/defaults/config.yml +++ b/worldedit-bukkit/src/main/resources/defaults/config.yml @@ -143,3 +143,4 @@ no-double-slash: false no-op-permissions: false debug: false show-help-on-first-use: true +server-side-cui: true \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java index 2d931f91f..81b4d892a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java @@ -134,6 +134,7 @@ public abstract class LocalConfiguration { public int butcherDefaultRadius = -1; public int butcherMaxRadius = -1; public boolean allowSymlinks = false; + public boolean serverSideCUI = true; /** * Load the configuration. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index c42be0914..c0f3a5b54 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -25,6 +25,8 @@ import com.sk89q.jchronic.Chronic; import com.sk89q.jchronic.Options; import com.sk89q.jchronic.utils.Span; import com.sk89q.jchronic.utils.Time; +import com.sk89q.jnbt.IntTag; +import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.command.tool.BlockTool; import com.sk89q.worldedit.command.tool.BrushTool; import com.sk89q.worldedit.command.tool.InvalidToolBindException; @@ -37,6 +39,7 @@ import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.internal.cui.CUIRegion; import com.sk89q.worldedit.internal.cui.SelectionShapeEvent; +import com.sk89q.worldedit.internal.cui.ServerCUIHandler; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; @@ -44,6 +47,7 @@ import com.sk89q.worldedit.regions.selector.RegionSelectorType; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.snapshot.Snapshot; @@ -87,10 +91,12 @@ public class LocalSession { private transient boolean fastMode = false; private transient Mask mask; private transient TimeZone timezone = TimeZone.getDefault(); + private transient Vector cuiTemporaryBlock; // Saved properties private String lastScript; private RegionSelectorType defaultSelector; + private boolean useServerCUI = false; // Save this to not annoy players. /** * Construct the object. @@ -612,6 +618,59 @@ public class LocalSession { public void tellVersion(Actor player) { } + public boolean shouldUseServerCUI() { + return this.useServerCUI; + } + + public void setUseServerCUI(boolean useServerCUI) { + this.useServerCUI = useServerCUI; + setDirty(); + } + + /** + * Update server-side WorldEdit CUI. + * + * @param actor The player + */ + public void updateServerCUI(Actor actor) { + if (!actor.isPlayer()) { + return; // This is for players only. + } + + if (!config.serverSideCUI) { + return; // Disabled in config. + } + + Player player = (Player) actor; + + if (!useServerCUI || hasCUISupport) { + if (cuiTemporaryBlock != null) { + player.sendFakeBlock(cuiTemporaryBlock, null); + cuiTemporaryBlock = null; + } + return; // If it's not enabled, ignore this. + } + + // Remove the old block. + if (cuiTemporaryBlock != null) { + player.sendFakeBlock(cuiTemporaryBlock, null); + cuiTemporaryBlock = null; + } + + BaseBlock block = ServerCUIHandler.createStructureBlock(player); + if (block != null) { + // If it's null, we don't need to do anything. The old was already removed. + Map tags = block.getNbtData().getValue(); + cuiTemporaryBlock = new Vector( + ((IntTag) tags.get("x")).getValue(), + ((IntTag) tags.get("y")).getValue(), + ((IntTag) tags.get("z")).getValue() + ); + + player.sendFakeBlock(cuiTemporaryBlock, block); + } + } + /** * Dispatch a CUI event but only if the actor has CUI support. * @@ -624,6 +683,8 @@ public class LocalSession { if (hasCUISupport) { actor.dispatchCUIEvent(event); + } else if (useServerCUI) { + updateServerCUI(actor); } } @@ -647,6 +708,9 @@ public class LocalSession { checkNotNull(actor); if (!hasCUISupport) { + if (useServerCUI) { + updateServerCUI(actor); + } return; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java index 3e1ecec7b..862b4398d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java @@ -31,6 +31,7 @@ import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.input.DisallowedUsageException; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.util.command.parametric.Optional; @@ -114,6 +115,41 @@ public class GeneralCommands { } } + @Command( + aliases = { "/drawsel" }, + usage = "[on|off]", + desc = "Toggle drawing the current selection", + min = 0, + max = 1 + ) + @CommandPermissions("worldedit.drawsel") + public void drawSelection(Player player, LocalSession session, CommandContext args) throws WorldEditException { + + if (!WorldEdit.getInstance().getConfiguration().serverSideCUI) { + throw new DisallowedUsageException("This functionality is disabled in the configuration!"); + } + String newState = args.getString(0, null); + if (session.shouldUseServerCUI()) { + if ("on".equals(newState)) { + player.printError("Server CUI already enabled."); + return; + } + + session.setUseServerCUI(false); + session.updateServerCUI(player); + player.print("Server CUI disabled."); + } else { + if ("off".equals(newState)) { + player.printError("Server CUI already disabled."); + return; + } + + session.setUseServerCUI(true); + session.updateServerCUI(player); + player.print("Server CUI enabled. This only supports cuboid regions, with a maximum size of 32x32x32."); + } + } + @Command( aliases = { "/gmask", "gmask" }, usage = "[mask]", diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java index b803e93f5..ac2fc81ed 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java @@ -29,8 +29,11 @@ import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.gamemode.GameMode; +import javax.annotation.Nullable; + /** * Represents a player */ @@ -262,4 +265,15 @@ public interface Player extends Entity, Actor { */ void setPosition(Vector pos); + /** + * Sends a fake block to the client. + * + *

+ * This block isn't real. + *

+ * + * @param pos The position of the block + * @param block The block to send, null to reset + */ + void sendFakeBlock(Vector pos, @Nullable BlockStateHolder block); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java index e738f8004..d08b2bf18 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java @@ -498,4 +498,8 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { return false; } + @Override + public void sendFakeBlock(Vector pos, BlockStateHolder block) { + + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java index 27da6be8a..adb5e2e83 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java @@ -31,6 +31,7 @@ import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.gamemode.GameMode; import java.util.UUID; @@ -155,4 +156,9 @@ class PlayerProxy extends AbstractPlayerActor { public void setGameMode(GameMode gameMode) { basePlayer.setGameMode(gameMode); } + + @Override + public void sendFakeBlock(Vector pos, BlockStateHolder block) { + basePlayer.sendFakeBlock(pos, block); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java new file mode 100644 index 000000000..af63bebe0 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java @@ -0,0 +1,156 @@ +/* + * 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.internal.cui; + +import com.sk89q.jnbt.ByteTag; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.IntTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.Nullable; + +/** + * Handles creation of server-side CUI systems. + */ +public class ServerCUIHandler { + + private ServerCUIHandler() { + } + + /** + * Creates a structure block that shows the region. + * + *

+ * Null symbolises removal of the CUI. + *

+ * + * @param player The player to create the structure block for. + * @return The structure block, or null + */ + @Nullable + public static BaseBlock createStructureBlock(Player player) { + LocalSession session = WorldEdit.getInstance().getSessionManager().get(player); + RegionSelector regionSelector = session.getRegionSelector(player.getWorld()); + + int posX, posY, posZ; + int width, height, length; + + if (regionSelector instanceof CuboidRegionSelector) { + if (regionSelector.isDefined()) { + try { + CuboidRegion region = ((CuboidRegionSelector) regionSelector).getRegion(); + + posX = region.getMinimumPoint().getBlockX(); + posY = region.getMinimumPoint().getBlockY(); + posZ = region.getMinimumPoint().getBlockZ(); + + width = region.getWidth(); + height = region.getHeight(); + length = region.getLength(); + } catch (IncompleteRegionException e) { + // This will never happen. + e.printStackTrace(); + return null; + } + } else { + CuboidRegion region = ((CuboidRegionSelector) regionSelector).getIncompleteRegion(); + Vector point; + if (region.getPos1() != null) { + point = region.getPos1(); + } else if (region.getPos2() != null) { + point = region.getPos2(); + } else { + // No more selection + return null; + } + + // Just select the point. + posX = point.getBlockX(); + posY = point.getBlockY(); + posZ = point.getBlockZ(); + width = 1; + height = 1; + length = 1; + } + } else { + // We only support cuboid regions right now. + return null; + } + + if (width > 32 || length > 32 || height > 32) { + // Structure blocks have a limit of 32x32x32 + return null; + } + + // Borrowed this math from FAWE + double rotX = player.getLocation().getYaw(); + double rotY = player.getLocation().getPitch(); + double xz = Math.cos(Math.toRadians(rotY)); + int x = (int) (player.getLocation().getX() - (-xz * Math.sin(Math.toRadians(rotX))) * 12); + int z = (int) (player.getLocation().getZ() - (xz * Math.cos(Math.toRadians(rotX))) * 12); + int y = Math.max(0, Math.min(Math.min(255, posY + 32), posY + 3)); + + Map structureTag = new HashMap<>(); + + posX -= x; + posY -= y; + posZ -= z; + + if (Math.abs(posX) > 32 || Math.abs(posY) > 32 || Math.abs(posZ) > 32) { + // Structure blocks have a limit + return null; + } + + structureTag.put("name", new StringTag("worldedit:" + player.getName())); + structureTag.put("author", new StringTag(player.getName())); + structureTag.put("metadata", new StringTag("")); + structureTag.put("x", new IntTag(x)); + structureTag.put("y", new IntTag(y)); + structureTag.put("z", new IntTag(z)); + structureTag.put("posX", new IntTag(posX)); + structureTag.put("posY", new IntTag(posY)); + structureTag.put("posZ", new IntTag(posZ)); + structureTag.put("sizeX", new IntTag(width)); + structureTag.put("sizeY", new IntTag(height)); + structureTag.put("sizeZ", new IntTag(length)); + structureTag.put("rotation", new StringTag("NONE")); + structureTag.put("mirror", new StringTag("NONE")); + structureTag.put("mode", new StringTag("SAVE")); + structureTag.put("ignoreEntities", new ByteTag((byte) 1)); + structureTag.put("showboundingbox", new ByteTag((byte) 1)); + structureTag.put("id", new StringTag(BlockTypes.STRUCTURE_BLOCK.getId())); + + return BlockTypes.STRUCTURE_BLOCK.getDefaultState().toBaseBlock(new CompoundTag(structureTag)); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java index aa9b9e5df..929085bd5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java @@ -266,13 +266,50 @@ public class SessionManager { sessions.remove(getKey(owner)); } + /** + * Called to unload this session manager. + */ + public synchronized void unload() { + clear(); + } + /** * Remove all sessions. */ public synchronized void clear() { + saveChangedSessions(); sessions.clear(); } + private synchronized void saveChangedSessions() { + long now = System.currentTimeMillis(); + Iterator it = sessions.values().iterator(); + Map saveQueue = new HashMap<>(); + + while (it.hasNext()) { + SessionHolder stored = it.next(); + if (stored.key.isActive()) { + stored.lastActive = now; + + if (stored.session.compareAndResetDirty()) { + saveQueue.put(stored.key, stored.session); + } + } else { + if (now - stored.lastActive > EXPIRATION_GRACE) { + if (stored.session.compareAndResetDirty()) { + saveQueue.put(stored.key, stored.session); + } + + it.remove(); + } + } + } + + if (!saveQueue.isEmpty()) { + commit(saveQueue); + } + } + @Subscribe public void onConfigurationLoad(ConfigurationLoadEvent event) { LocalConfiguration config = event.getConfiguration(); @@ -302,32 +339,7 @@ public class SessionManager { @Override public void run() { synchronized (SessionManager.this) { - long now = System.currentTimeMillis(); - Iterator it = sessions.values().iterator(); - Map saveQueue = new HashMap<>(); - - while (it.hasNext()) { - SessionHolder stored = it.next(); - if (stored.key.isActive()) { - stored.lastActive = now; - - if (stored.session.compareAndResetDirty()) { - saveQueue.put(stored.key, stored.session); - } - } else { - if (now - stored.lastActive > EXPIRATION_GRACE) { - if (stored.session.compareAndResetDirty()) { - saveQueue.put(stored.key, stored.session); - } - - it.remove(); - } - } - } - - if (!saveQueue.isEmpty()) { - commit(saveQueue); - } + saveChangedSessions(); } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java index 472796c4a..65f44c691 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java @@ -114,6 +114,7 @@ public class PropertiesConfiguration extends LocalConfiguration { butcherDefaultRadius = getInt("butcher-default-radius", butcherDefaultRadius); butcherMaxRadius = getInt("butcher-max-radius", butcherMaxRadius); allowSymlinks = getBool("allow-symbolic-links", allowSymlinks); + serverSideCUI = getBool("server-side-cui", serverSideCUI); LocalSession.MAX_HISTORY_SIZE = Math.max(15, getInt("history-size", 15)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java index c6ab2b7db..84e0fc34e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java @@ -112,6 +112,7 @@ public class YAMLConfiguration extends LocalConfiguration { SessionManager.EXPIRATION_GRACE = config.getInt("history.expiration", 10) * 60 * 1000; showHelpInfo = config.getBoolean("show-help-on-first-use", true); + serverSideCUI = config.getBoolean("server-side-cui", true); String snapshotsDir = config.getString("snapshots.directory", ""); if (!snapshotsDir.isEmpty()) { diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java index d4b906fc4..817315e92 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java @@ -29,6 +29,8 @@ import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.item.ItemTypes; import io.netty.buffer.Unpooled; import net.minecraft.entity.player.EntityPlayerMP; @@ -36,7 +38,9 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.network.PacketBuffer; import net.minecraft.network.play.server.SPacketCustomPayload; +import net.minecraft.network.play.server.SPacketUpdateTileEntity; import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextFormatting; import net.minecraftforge.fml.common.registry.ForgeRegistries; @@ -164,6 +168,24 @@ public class ForgePlayer extends AbstractPlayerActor { return null; } + @Override + public void sendFakeBlock(Vector pos, BlockStateHolder block) { + BlockPos loc = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); + if (block == null) { + // TODO +// player.sendBlockChange(loc, player.getWorld().getBlockAt(loc).getBlockData()); + } else { + // TODO +// player.sendBlockChange(loc, BukkitAdapter.adapt(block)); + if (block instanceof BaseBlock && ((BaseBlock) block).hasNbtData()) { + player.connection.sendPacket(new SPacketUpdateTileEntity( + new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()), 7, + NBTConverter.toNative(((BaseBlock) block).getNbtData())) + ); + } + } + } + @Override public SessionKey getSessionKey() { return new SessionKeyImpl(player.getUniqueID(), player.getName()); diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java index bf17292cd..963f2f748 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -136,7 +136,9 @@ public class ForgeWorldEdit { @EventHandler public void serverStopping(FMLServerStoppingEvent event) { - WorldEdit.getInstance().getPlatformManager().unregister(platform); + WorldEdit worldEdit = WorldEdit.getInstance(); + worldEdit.getSessionManager().unload(); + worldEdit.getPlatformManager().unregister(platform); } @EventHandler diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java index 37774dbc8..662d65e55 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java @@ -30,6 +30,7 @@ import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.gamemode.GameMode; import com.sk89q.worldedit.world.gamemode.GameModes; import com.sk89q.worldedit.world.item.ItemTypes; @@ -183,6 +184,23 @@ public class SpongePlayer extends AbstractPlayerActor { gameMode.getId()).get()); } + @Override + public void sendFakeBlock(Vector pos, BlockStateHolder block) { + org.spongepowered.api.world.Location loc = player.getWorld().getLocation(pos.getX(), pos.getY(), pos.getZ()); + if (block == null) { + player.sendBlockChange(loc.getBlockPosition(), loc.getBlock()); + } else { + // TODO +// player.sendBlockChange(loc, BukkitAdapter.adapt(block)); +// if (block instanceof BaseBlock && ((BaseBlock) block).hasNbtData()) { +// BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); +// if (adapter != null) { +// adapter.sendFakeNBT(player, pos, ((BaseBlock) block).getNbtData()); +// } +// } + } + } + @Override public SessionKey getSessionKey() { return new SessionKeyImpl(player.getUniqueId(), player.getName()); diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java index f2ba77982..d86e77c7c 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java @@ -147,7 +147,9 @@ public class SpongeWorldEdit { @Listener public void serverStopping(GameStoppingServerEvent event) { - WorldEdit.getInstance().getPlatformManager().unregister(platform); + WorldEdit worldEdit = WorldEdit.getInstance(); + worldEdit.getSessionManager().unload(); + worldEdit.getPlatformManager().unregister(platform); } @Listener diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java index e38140bb4..d824e0a8f 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java @@ -120,6 +120,7 @@ public class ConfigurateConfiguration extends LocalConfiguration { SessionManager.EXPIRATION_GRACE = node.getNode("history", "expiration").getInt(10) * 60 * 1000; showHelpInfo = node.getNode("show-help-on-first-use").getBoolean(true); + serverSideCUI = node.getNode("server-side-cui").getBoolean(true); String snapshotsDir = node.getNode("snapshots", "directory").getString(""); if (!snapshotsDir.isEmpty()) {