From 72951cdf23df9f81cba2783b998a54cf24a7a77a Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Wed, 30 Oct 2019 12:26:52 +0100 Subject: [PATCH] Various fake chunk packet aliases cfi wip --- .../com/boydti/fawe/bukkit/FaweBukkit.java | 4 +- .../adapter/mc1_14/BukkitAdapter_1_14.java | 4 +- .../adapter/mc1_14/MapChunkUtil_1_14.java | 81 +++++++++ .../adapter/mc1_14/Spigot_v1_14_R4.java | 30 +++- .../mc1_14/test/TestChunkPacketSend.java | 39 +++++ .../sk89q/worldedit/bukkit/BukkitAdapter.java | 2 +- .../sk89q/worldedit/bukkit/BukkitPlayer.java | 125 +++++++------- .../sk89q/worldedit/bukkit/BukkitWorld.java | 9 + .../worldedit/bukkit/WorldEditPlugin.java | 17 +- .../bukkit/adapter/BukkitImplAdapter.java | 8 + .../main/java/com/boydti/fawe/FaweCache.java | 33 +++- .../java/com/boydti/fawe/beta/IBlocks.java | 109 +++++++++++- .../implementation/BatchProcessorHolder.java | 10 ++ .../fawe/beta/implementation/ChunkPacket.java | 159 +++++++++--------- .../implementation/ChunkSendProcessor.java | 22 ++- .../implementation/IBatchProcessorHolder.java | 1 + .../implementation/MultiBatchProcessor.java | 18 +- .../beta/implementation/NullProcessor.java | 22 +++ .../SingleThreadQueueExtent.java | 18 +- .../cfi/HeightMapMCAGenerator.java | 87 +++++----- .../fawe/object/collection/BitArray4096.java | 4 + .../java/com/boydti/fawe/util/StringMan.java | 4 +- .../boydti/fawe/wrappers/WorldWrapper.java | 7 + .../java/com/sk89q/jnbt/NBTOutputStream.java | 89 +++++----- .../worldedit/command/ClipboardCommands.java | 1 + .../worldedit/command/HistoryCommands.java | 8 +- .../worldedit/command/RegionCommands.java | 50 +++++- .../worldedit/command/ToolUtilCommands.java | 4 +- .../worldedit/command/UtilityCommands.java | 2 +- .../com/sk89q/worldedit/entity/Player.java | 3 +- .../extension/platform/PlayerProxy.java | 5 - .../com/sk89q/worldedit/world/NullWorld.java | 6 + .../java/com/sk89q/worldedit/world/World.java | 9 + 33 files changed, 704 insertions(+), 286 deletions(-) create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/MapChunkUtil_1_14.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/test/TestChunkPacketSend.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/NullProcessor.java diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java index d33ed175f..c9aac5c8e 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java @@ -6,6 +6,7 @@ import com.boydti.fawe.beta.implementation.QueueHandler; import com.boydti.fawe.beta.preloader.AsyncPreloader; import com.boydti.fawe.beta.preloader.Preloader; import com.boydti.fawe.bukkit.adapter.BukkitQueueHandler; +import com.boydti.fawe.bukkit.adapter.mc1_14.test.TestChunkPacketSend; import com.boydti.fawe.bukkit.listener.BrushListener; import com.boydti.fawe.bukkit.listener.BukkitImageListener; import com.boydti.fawe.bukkit.listener.ChunkListener_8; @@ -29,7 +30,6 @@ import com.boydti.fawe.object.FaweCommand; import com.boydti.fawe.regions.FaweMaskManager; import com.boydti.fawe.util.Jars; import com.boydti.fawe.util.TaskManager; -import com.boydti.fawe.util.WEManager; import com.boydti.fawe.util.image.ImageViewer; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitPlayer; @@ -114,6 +114,8 @@ public class FaweBukkit implements IFawe, Listener { new ChunkListener_9(); } + new TestChunkPacketSend(plugin); + }); } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitAdapter_1_14.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitAdapter_1_14.java index d7682364e..bf54b126e 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitAdapter_1_14.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitAdapter_1_14.java @@ -80,7 +80,7 @@ public class BukkitAdapter_1_14 { fieldDirtyBits.setAccessible(true); { - Field tmp = null; + Field tmp; try { tmp = DataPaletteBlock.class.getDeclaredField("writeLock"); } catch (NoSuchFieldException paper) { @@ -161,7 +161,7 @@ public class BukkitAdapter_1_14 { return TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(X, Z)); } - private static PlayerChunk getPlayerChunk(net.minecraft.server.v1_14_R1.WorldServer nmsWorld, final int cx, final int cz) { + public static PlayerChunk getPlayerChunk(net.minecraft.server.v1_14_R1.WorldServer nmsWorld, final int cx, final int cz) { PlayerChunkMap chunkMap = nmsWorld.getChunkProvider().playerChunkMap; PlayerChunk playerChunk = chunkMap.visibleChunks.get(ChunkCoordIntPair.pair(cx, cz)); if (playerChunk == null) { diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/MapChunkUtil_1_14.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/MapChunkUtil_1_14.java new file mode 100644 index 000000000..3448c0c76 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/MapChunkUtil_1_14.java @@ -0,0 +1,81 @@ +package com.boydti.fawe.bukkit.adapter.mc1_14; + +import com.boydti.fawe.beta.implementation.ChunkPacket; +import com.boydti.fawe.util.ReflectionUtils; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.math.BlockVector3; +import net.minecraft.server.v1_14_R1.NBTBase; +import net.minecraft.server.v1_14_R1.NBTTagCompound; +import net.minecraft.server.v1_14_R1.PacketPlayOutMapChunk; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Map; + +public class MapChunkUtil_1_14 { + private static final Field fieldX; + + private static final Field fieldZ; + + private static final Field fieldHeightMap; + + private static final Field fieldBitMask; + + private static final Field fieldChunkData; + + private static final Field fieldBlockEntities; + + private static final Field fieldFull; + + + static { + try { + fieldX = PacketPlayOutMapChunk.class.getDeclaredField("a"); + fieldZ = PacketPlayOutMapChunk.class.getDeclaredField("b"); + fieldBitMask = PacketPlayOutMapChunk.class.getDeclaredField("c"); + fieldHeightMap = PacketPlayOutMapChunk.class.getDeclaredField("d"); + fieldChunkData = PacketPlayOutMapChunk.class.getDeclaredField("e"); + fieldBlockEntities = PacketPlayOutMapChunk.class.getDeclaredField("f"); + fieldFull = PacketPlayOutMapChunk.class.getDeclaredField("g"); + + fieldX.setAccessible(true); + fieldZ.setAccessible(true); + fieldBitMask.setAccessible(true); + fieldHeightMap.setAccessible(true); + fieldBlockEntities.setAccessible(true); + fieldFull.setAccessible(true); + } catch (Throwable e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + public static PacketPlayOutMapChunk create(BukkitImplAdapter adapter, ChunkPacket packet) { + PacketPlayOutMapChunk nmsPacket = new PacketPlayOutMapChunk(); + + try { + fieldX.setInt(nmsPacket, packet.getChunkX()); + fieldZ.setInt(nmsPacket, packet.getChunkZ()); + + fieldBitMask.set(nmsPacket, packet.getChunk().getBitMask()); + NBTBase heightMap = adapter.fromNative(packet.getHeightMap()); + fieldHeightMap.set(nmsPacket, heightMap); + fieldChunkData.set(nmsPacket, packet.get()); + + Map tiles = packet.getChunk().getTiles(); + ArrayList nmsTiles = new ArrayList<>(tiles.size()); + for (Map.Entry entry : tiles.entrySet()) { + NBTBase nmsTag = adapter.fromNative(entry.getValue()); + nmsTiles.add((NBTTagCompound) nmsTag); + } + fieldBlockEntities.set(nmsPacket, nmsTiles); + fieldFull.set(nmsPacket, packet.isFull()); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + return nmsPacket; + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/Spigot_v1_14_R4.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/Spigot_v1_14_R4.java index 812689158..5efdd8b86 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/Spigot_v1_14_R4.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/Spigot_v1_14_R4.java @@ -19,8 +19,8 @@ package com.boydti.fawe.bukkit.adapter.mc1_14; -import com.bekvon.bukkit.residence.commands.material; import com.boydti.fawe.Fawe; +import com.boydti.fawe.beta.implementation.ChunkPacket; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; @@ -76,6 +76,7 @@ import net.minecraft.server.v1_14_R1.Chunk; import net.minecraft.server.v1_14_R1.ChunkCoordIntPair; import net.minecraft.server.v1_14_R1.ChunkSection; import net.minecraft.server.v1_14_R1.Entity; +import net.minecraft.server.v1_14_R1.EntityPlayer; import net.minecraft.server.v1_14_R1.EntityTypes; import net.minecraft.server.v1_14_R1.EnumDirection; import net.minecraft.server.v1_14_R1.EnumHand; @@ -103,7 +104,9 @@ import net.minecraft.server.v1_14_R1.NBTTagLongArray; import net.minecraft.server.v1_14_R1.NBTTagShort; import net.minecraft.server.v1_14_R1.NBTTagString; import net.minecraft.server.v1_14_R1.PacketPlayOutEntityStatus; +import net.minecraft.server.v1_14_R1.PacketPlayOutMapChunk; import net.minecraft.server.v1_14_R1.PacketPlayOutTileEntityData; +import net.minecraft.server.v1_14_R1.PlayerChunk; import net.minecraft.server.v1_14_R1.PlayerChunkMap; import net.minecraft.server.v1_14_R1.TileEntity; import net.minecraft.server.v1_14_R1.Vec3D; @@ -138,6 +141,7 @@ import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.function.Supplier; import java.util.stream.Collectors; +import java.util.stream.Stream; import static com.google.common.base.Preconditions.checkNotNull; @@ -657,6 +661,30 @@ public final class Spigot_v1_14_R4 extends CachedBukkitAdapter implements Bukkit )); } + @Override + public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket packet) { + WorldServer nmsWorld = ((CraftWorld) world).getHandle(); + PlayerChunk map = BukkitAdapter_1_14.getPlayerChunk(nmsWorld, packet.getChunkX(), packet.getChunkZ()); + if (map != null && map.hasBeenLoaded()) { + boolean flag = false; + PlayerChunk.d players = map.players; + Stream stream = players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag); + + EntityPlayer checkPlayer = player == null ? null : ((CraftPlayer) player).getHandle(); + stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer) + .forEach(entityPlayer -> { + synchronized (packet) { + PacketPlayOutMapChunk nmsPacket = (PacketPlayOutMapChunk) packet.getNativePacket(); + if (nmsPacket == null) { + nmsPacket = MapChunkUtil_1_14.create(this, packet); + packet.setNativePacket(nmsPacket); + } + entityPlayer.playerConnection.sendPacket(nmsPacket); + } + }); + } + } + private static EnumDirection adapt(Direction face) { switch (face) { case NORTH: return EnumDirection.NORTH; diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/test/TestChunkPacketSend.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/test/TestChunkPacketSend.java new file mode 100644 index 000000000..d3dde69be --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/test/TestChunkPacketSend.java @@ -0,0 +1,39 @@ +package com.boydti.fawe.bukkit.adapter.mc1_14.test; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.ProtocolManager; +import com.comphenix.protocol.events.ListenerPriority; +import com.comphenix.protocol.events.PacketAdapter; +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.events.PacketEvent; +import com.comphenix.protocol.reflect.StructureModifier; +import com.comphenix.protocol.wrappers.WrappedBlockData; +import org.bukkit.plugin.Plugin; + +import java.util.List; + +public class TestChunkPacketSend { + public TestChunkPacketSend(Plugin plugin) { + // Disable all sound effects + ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager(); + protocolManager.addPacketListener( + new PacketAdapter(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.MAP_CHUNK) { + @Override + public void onPacketSending(PacketEvent event) { + if (event.getPacketType() != PacketType.Play.Server.MAP_CHUNK) { + System.out.println("Wrong packet"); + return; + } + PacketContainer packet = event.getPacket(); + StructureModifier bytes = packet.getBytes(); + StructureModifier blockData = packet.getBlockData(); + List values = blockData.getValues(); + System.out.println("Packet " + values.size() + " | " + blockData.size()); + System.out.println(bytes.size()); + System.out.println(packet.getByteArrays().size()); + System.out.println(packet.getBlocks().size()); + } + }); + } +} diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java index 28dd35557..96cbf1e33 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java @@ -139,7 +139,7 @@ public enum BukkitAdapter { */ public static Player adapt(com.sk89q.worldedit.entity.Player player) { player = PlayerProxy.unwrap(player); - return ((BukkitPlayer) player).getPlayer(); + return player == null ? null : ((BukkitPlayer) player).getPlayer(); } /** 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 091b3242d..bb474f380 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 @@ -24,10 +24,6 @@ import com.boydti.fawe.bukkit.FaweBukkit; import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.RunnableVal; import com.boydti.fawe.util.TaskManager; -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.ProtocolManager; -import com.comphenix.protocol.injector.netty.WirePacket; import com.sk89q.util.StringUtil; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; @@ -51,14 +47,6 @@ 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 java.lang.reflect.InvocationTargetException; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.UUID; -import java.util.function.Supplier; -import javax.annotation.Nullable; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; @@ -69,6 +57,12 @@ import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; + public class BukkitPlayer extends AbstractPlayerActor { private Player player; @@ -76,6 +70,7 @@ public class BukkitPlayer extends AbstractPlayerActor { public BukkitPlayer(Player player) { this(WorldEditPlugin.getInstance(), player); + Fawe.debug("Should not construct BukkitPlayer. Instead use BukkitAdapter.adapt(player)"); } public BukkitPlayer(WorldEditPlugin plugin, Player player) { @@ -94,16 +89,16 @@ public class BukkitPlayer extends AbstractPlayerActor { @Override public BaseItemStack getItemInHand(HandSide handSide) { ItemStack itemStack = handSide == HandSide.MAIN_HAND - ? player.getInventory().getItemInMainHand() - : player.getInventory().getItemInOffHand(); + ? getPlayer().getInventory().getItemInMainHand() + : getPlayer().getInventory().getItemInOffHand(); return BukkitAdapter.adapt(itemStack); } @Override public BaseBlock getBlockInHand(HandSide handSide) throws WorldEditException { ItemStack itemStack = handSide == HandSide.MAIN_HAND - ? player.getInventory().getItemInMainHand() - : player.getInventory().getItemInOffHand(); + ? getPlayer().getInventory().getItemInMainHand() + : getPlayer().getInventory().getItemInOffHand(); return BukkitAdapter.asBlockState(itemStack).toBaseBlock(); } @@ -114,18 +109,18 @@ public class BukkitPlayer extends AbstractPlayerActor { @Override public String getDisplayName() { - return player.getDisplayName(); + return getPlayer().getDisplayName(); } @Override public void giveItem(BaseItemStack itemStack) { - final PlayerInventory inv = player.getInventory(); + final PlayerInventory inv = getPlayer().getInventory(); ItemStack newItem = BukkitAdapter.adapt(itemStack); if (itemStack.getType().getId().equalsIgnoreCase(WorldEdit.getInstance().getConfiguration().wandItem)) { inv.remove(newItem); } - final ItemStack item = player.getInventory().getItemInMainHand(); - player.getInventory().setItemInMainHand(newItem); + final ItemStack item = getPlayer().getInventory().getItemInMainHand(); + getPlayer().getInventory().setItemInMainHand(newItem); HashMap overflow = inv.addItem(item); if (!overflow.isEmpty()) { TaskManager.IMP.sync(new RunnableVal() { @@ -135,7 +130,7 @@ public class BukkitPlayer extends AbstractPlayerActor { ItemStack stack = entry.getValue(); if (stack.getType() != Material.AIR && stack.getAmount() > 0) { Item - dropped = player.getWorld().dropItem(player.getLocation(), stack); + dropped = getPlayer().getWorld().dropItem(getPlayer().getLocation(), stack); PlayerDropItemEvent event = new PlayerDropItemEvent(player, dropped); if (event.isCancelled()) { dropped.remove(); @@ -145,45 +140,45 @@ public class BukkitPlayer extends AbstractPlayerActor { } }); } - player.updateInventory(); + getPlayer().updateInventory(); } @Override public void printRaw(String msg) { for (String part : msg.split("\n")) { - player.sendMessage(part); + getPlayer().sendMessage(part); } } @Override public void print(String msg) { for (String part : msg.split("\n")) { - player.sendMessage("\u00A7d" + part); + getPlayer().sendMessage("\u00A7d" + part); } } @Override public void printDebug(String msg) { for (String part : msg.split("\n")) { - player.sendMessage("\u00A77" + part); + getPlayer().sendMessage("\u00A77" + part); } } @Override public void printError(String msg) { for (String part : msg.split("\n")) { - player.sendMessage("\u00A7c" + part); + getPlayer().sendMessage("\u00A7c" + part); } } @Override public void print(Component component) { - TextAdapter.sendComponent(player, WorldEditText.format(component)); + TextAdapter.sendComponent(getPlayer(), WorldEditText.format(component)); } @Override public void setPosition(Vector3 pos, float pitch, float yaw) { - org.bukkit.World world = player.getWorld(); + org.bukkit.World world = getPlayer().getWorld(); if (pos instanceof com.sk89q.worldedit.util.Location) { com.sk89q.worldedit.util.Location loc = (com.sk89q.worldedit.util.Location) pos; Extent extent = loc.getExtent(); @@ -191,42 +186,41 @@ public class BukkitPlayer extends AbstractPlayerActor { world = Bukkit.getWorld(((World) extent).getName()); } } - player.teleport(new Location(world, pos.getX(), pos.getY(), pos.getZ(), yaw, pitch)); + getPlayer().teleport(new Location(world, pos.getX(), pos.getY(), pos.getZ(), yaw, pitch)); } @Override public String[] getGroups() { - return plugin.getPermissionsResolver().getGroups(player); + return plugin.getPermissionsResolver().getGroups(getPlayer()); } @Override public BlockBag getInventoryBlockBag() { - return new BukkitPlayerBlockBag(player); + return new BukkitPlayerBlockBag(getPlayer()); } @Override public GameMode getGameMode() { - return GameModes.get(player.getGameMode().name().toLowerCase(Locale.ROOT)); + return GameModes.get(getPlayer().getGameMode().name().toLowerCase(Locale.ROOT)); } @Override public void setGameMode(GameMode gameMode) { - player.setGameMode(org.bukkit.GameMode.valueOf(gameMode.getId().toUpperCase(Locale.ROOT))); + getPlayer().setGameMode(org.bukkit.GameMode.valueOf(gameMode.getId().toUpperCase(Locale.ROOT))); } @Override public boolean hasPermission(String perm) { return (!plugin.getLocalConfiguration().noOpPermissions && player.isOp()) - || plugin.getPermissionsResolver().hasPermission( - player.getWorld().getName(), player, perm); + || plugin.getPermissionsResolver().hasPermission(player.getWorld().getName(), player, perm); } @Override public boolean togglePermission(String permission) { if (this.hasPermission(permission)) { - player.addAttachment(plugin).setPermission(permission, false); + getPlayer().addAttachment(plugin).setPermission(permission, false); return false; } else { - player.addAttachment(plugin).setPermission(permission, true); + getPlayer().addAttachment(plugin).setPermission(permission, true); return true; } } @@ -238,19 +232,19 @@ public class BukkitPlayer extends AbstractPlayerActor { * - The `/wea` command will give/remove the required bypass permission */ if (Fawe.imp().getVault() == null || Fawe. imp().getVault().permission == null) { - player.addAttachment(Fawe. imp().getPlugin()).setPermission(permission, value); + getPlayer().addAttachment(Fawe. imp().getPlugin()).setPermission(permission, value); } else if (value) { if (!Fawe. imp().getVault().permission.playerAdd(player, permission)) { - player.addAttachment(Fawe. imp().getPlugin()).setPermission(permission, value); + getPlayer().addAttachment(Fawe. imp().getPlugin()).setPermission(permission, value); } } else if (!Fawe.imp().getVault().permission.playerRemove(player, permission)) { - player.addAttachment(Fawe.imp().getPlugin()).setPermission(permission, value); + getPlayer().addAttachment(Fawe.imp().getPlugin()).setPermission(permission, value); } } @Override public World getWorld() { - return BukkitAdapter.adapt(player.getWorld()); + return BukkitAdapter.adapt(getPlayer().getWorld()); } @Override @@ -260,21 +254,30 @@ public class BukkitPlayer extends AbstractPlayerActor { if (params.length > 0) { send = send + "|" + StringUtil.joinString(params, "|"); } - player.sendPluginMessage(plugin, WorldEditPlugin.CUI_PLUGIN_CHANNEL, send.getBytes(CUIChannelListener.UTF_8_CHARSET)); + getPlayer().sendPluginMessage(plugin, WorldEditPlugin.CUI_PLUGIN_CHANNEL, send.getBytes(CUIChannelListener.UTF_8_CHARSET)); } public Player getPlayer() { + if (!player.isValid()) { + Player tmp = Bukkit.getPlayer(getUniqueId()); + if (tmp != null) { + player = tmp; + } else { + System.out.println("Invalid player " + player.getName()); + new Exception().printStackTrace(); + } + } return player; } @Override public boolean isAllowedToFly() { - return player.getAllowFlight(); + return getPlayer().getAllowFlight(); } @Override public void setFlying(boolean flying) { - player.setFlying(flying); + getPlayer().setFlying(flying); } @Override @@ -284,7 +287,7 @@ public class BukkitPlayer extends AbstractPlayerActor { @Override public com.sk89q.worldedit.util.Location getLocation() { - Location nativeLocation = player.getLocation(); + Location nativeLocation = getPlayer().getLocation(); Vector3 position = BukkitAdapter.asVector(nativeLocation); return new com.sk89q.worldedit.util.Location( getWorld(), @@ -295,7 +298,7 @@ public class BukkitPlayer extends AbstractPlayerActor { @Override public boolean setLocation(com.sk89q.worldedit.util.Location location) { - return player.teleport(BukkitAdapter.adapt(location)); + return getPlayer().teleport(BukkitAdapter.adapt(location)); } @Nullable @@ -306,7 +309,7 @@ public class BukkitPlayer extends AbstractPlayerActor { @Override public SessionKey getSessionKey() { - return new SessionKeyImpl(this.player.getUniqueId(), player.getName()); + return new SessionKeyImpl(getUniqueId(), getName()); } private static class SessionKeyImpl implements SessionKey { @@ -349,11 +352,11 @@ public class BukkitPlayer extends AbstractPlayerActor { @Override public > void sendFakeBlock(BlockVector3 pos, B block) { - Location loc = new Location(player.getWorld(), pos.getX(), pos.getY(), pos.getZ()); + Location loc = new Location(getPlayer().getWorld(), pos.getX(), pos.getY(), pos.getZ()); if (block == null) { - player.sendBlockChange(loc, player.getWorld().getBlockAt(loc).getBlockData()); + getPlayer().sendBlockChange(loc, getPlayer().getWorld().getBlockAt(loc).getBlockData()); } else { - player.sendBlockChange(loc, BukkitAdapter.adapt(block)); + getPlayer().sendBlockChange(loc, BukkitAdapter.adapt(block)); if (block instanceof BaseBlock && ((BaseBlock) block).hasNbtData()) { BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); if (adapter != null) { @@ -366,25 +369,15 @@ public class BukkitPlayer extends AbstractPlayerActor { } } - @Override - public void sendFakeChunk(int chunkX, int chunkZ, Supplier data) { - ProtocolManager manager = ProtocolLibrary.getProtocolManager(); - // check if the chunk is in range - if (true) { - try { - byte[] raw = data.get(); - WirePacket packet = new WirePacket(PacketType.Play.Server.MAP_CHUNK, raw); - manager.sendWirePacket(getPlayer(), packet); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - } - } - @Override public void sendTitle(String title, String sub) { - player.sendTitle(ChatColor.GOLD + title, ChatColor.GOLD + sub, 0, 70, 20); + getPlayer().sendTitle(ChatColor.GOLD + title, ChatColor.GOLD + sub, 0, 70, 20); Bukkit.getServer().dispatchCommand(player, "title " + getName() + " subtitle [{\"text\":\"" + sub + "\",\"color\":\"gold\"}]"); Bukkit.getServer().dispatchCommand(player, "title " + getName() + " title [{\"text\":\"" + title + "\",\"color\":\"gold\"}]"); } + + @Override + public void unregister() { + getPlayer().removeMetadata("WE", WorldEditPlugin.getInstance()); + } } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index 412e8cc42..e44f0a155 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -23,6 +23,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.boydti.fawe.Fawe; import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.implementation.ChunkPacket; import com.boydti.fawe.bukkit.FaweBukkit; import com.boydti.fawe.bukkit.adapter.mc1_14.BukkitGetBlocks_1_14; import com.boydti.fawe.config.Settings; @@ -33,6 +34,8 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.PlayerProxy; import com.sk89q.worldedit.history.change.BlockChange; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; @@ -537,4 +540,10 @@ public class BukkitWorld extends AbstractWorld { public IChunkGet get(int chunkX, int chunkZ) { return new BukkitGetBlocks_1_14(getWorldChecked(), chunkX, chunkZ, Settings.IMP.QUEUE.POOL); } + + @Override + public void sendFakeChunk(Player player, ChunkPacket packet) { + org.bukkit.entity.Player bukkitPlayer = BukkitAdapter.adapt(player); + WorldEditPlugin.getInstance().getBukkitImplAdapter().sendFakeChunk(getWorld(), bukkitPlayer, packet); + } } 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 74b06d1f3..efdce1069 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 @@ -560,15 +560,18 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter * @return a wrapped player */ public BukkitPlayer wrapPlayer(Player player) { - synchronized (player) { - BukkitPlayer wePlayer = getCachedPlayer(player); - if (wePlayer == null) { - wePlayer = new BukkitPlayer(this, player); - player.setMetadata("WE", new FixedMetadataValue(this, wePlayer)); - return wePlayer; + BukkitPlayer wePlayer = getCachedPlayer(player); + if (wePlayer == null) { + synchronized (player) { + wePlayer = getCachedPlayer(player); + if (wePlayer == null) { + wePlayer = new BukkitPlayer(this, player); + player.setMetadata("WE", new FixedMetadataValue(this, wePlayer)); + return wePlayer; + } } - return wePlayer; } + return wePlayer; } public BukkitPlayer getCachedPlayer(Player player) { 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 26423c18b..62c78a64d 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 @@ -20,6 +20,7 @@ package com.sk89q.worldedit.bukkit.adapter; import com.boydti.fawe.Fawe; +import com.boydti.fawe.beta.implementation.ChunkPacket; import com.boydti.fawe.bukkit.FaweBukkit; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.Tag; @@ -141,6 +142,13 @@ public interface BukkitImplAdapter extends IBukkitAdapter { */ void sendFakeOP(Player player); + /** + * Send a fake chunk packet to a player + * @param player + * @param packet + */ + void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket packet); + /** * Simulates a player using an item. * diff --git a/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java b/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java index 5dd9dd93f..3cd039f48 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java @@ -38,8 +38,11 @@ import java.util.IdentityHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.CancellationException; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; @@ -101,6 +104,7 @@ public enum FaweCache implements Trimable { @Override public synchronized boolean trim(boolean aggressive) { + BYTE_BUFFER_8192.clean(); BLOCK_TO_PALETTE.clean(); PALETTE_TO_BLOCK.clean(); BLOCK_STATES.clean(); @@ -202,6 +206,8 @@ public enum FaweCache implements Trimable { thread cache */ + public final CleanableThreadLocal BYTE_BUFFER_8192 = new CleanableThreadLocal<>(() -> new byte[8192]); + public final CleanableThreadLocal BLOCK_TO_PALETTE = new CleanableThreadLocal<>(() -> { int[] result = new int[BlockTypes.states.length]; Arrays.fill(result, Integer.MAX_VALUE); @@ -502,6 +508,31 @@ public enum FaweCache implements Trimable { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, queue , Executors.defaultThreadFactory(), - new ThreadPoolExecutor.CallerRunsPolicy()); + new ThreadPoolExecutor.CallerRunsPolicy()) { + protected void afterExecute(Runnable r, Throwable t) { + try { + super.afterExecute(r, t); + if (t == null && r instanceof Future) { + try { + Future future = (Future) r; + if (future.isDone()) { + future.get(); + } + } catch (CancellationException ce) { + t = ce; + } catch (ExecutionException ee) { + t = ee.getCause(); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + } + if (t != null) { + t.printStackTrace(); + } + } catch (Throwable e) { + e.printStackTrace(); + } + } + }; } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IBlocks.java index b52e19ece..974c01b62 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IBlocks.java @@ -1,11 +1,20 @@ package com.boydti.fawe.beta; import com.boydti.fawe.FaweCache; +import com.boydti.fawe.object.FaweOutputStream; +import com.boydti.fawe.object.collection.BitArray4096; +import com.boydti.fawe.object.io.FastByteArrayOutputStream; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BlockID; import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.registry.BlockRegistry; +import java.io.IOException; import java.util.Map; import java.util.Set; @@ -29,11 +38,107 @@ public interface IBlocks extends Trimable { default int getBitMask() { int mask = 0; for (int layer = 0; layer < FaweCache.IMP.CHUNK_LAYERS; layer++) { - if (hasSection(layer)); - mask |= (1 << layer); + if (hasSection(layer)) { + System.out.println("Has layer 0 " + layer); + mask += (1 << layer); + } } return mask; } IBlocks reset(); + + default byte[] toByteArray(boolean writeBiomes) { + return toByteArray(null, writeBiomes); + } + + default byte[] toByteArray(byte[] buffer, boolean writeBiomes) { + if (buffer == null) { + buffer = new byte[1024]; + } + + BlockRegistry registry = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry(); + FastByteArrayOutputStream sectionByteArray = new FastByteArrayOutputStream(buffer); + FaweOutputStream sectionWriter = new FaweOutputStream(sectionByteArray); + try { + for (int layer = 0; layer < FaweCache.IMP.CHUNK_LAYERS; layer++) { + if (!this.hasSection(layer)) continue; + + char[] ids = this.getArray(layer); + + int nonEmpty = 0; // TODO optimize into same loop as toPalette + for (char id : ids) { + if (id != 0) nonEmpty++; + } + + sectionWriter.writeShort(nonEmpty); // non empty + + sectionWriter.writeByte(14); // globalPaletteBitsPerBlock + + if (true) { + BitArray4096 bits = new BitArray4096(14); // globalPaletteBitsPerBlock + bits.setAt(0, 0); + for (int i = 0; i < 4096; i++) { + int ordinal = ids[i]; + BlockState state = BlockState.getFromOrdinal(ordinal); + if (!state.getMaterial().isAir()) { + int mcId = registry.getInternalBlockStateId(state).getAsInt(); + bits.setAt(i, mcId); + } + } + sectionWriter.write(bits.getData()); + } else { + + FaweCache.Palette palette = FaweCache.IMP.toPalette(0, ids); + + sectionWriter.writeByte(palette.bitsPerEntry); // bits per block + sectionWriter.writeVarInt(palette.paletteToBlockLength); + for (int i = 0; i < palette.paletteToBlockLength; i++) { + int ordinal = palette.paletteToBlock[i]; + switch (ordinal) { + case BlockID.CAVE_AIR: + case BlockID.VOID_AIR: + case BlockID.AIR: + case BlockID.__RESERVED__: + sectionWriter.writeVarInt(0); + break; + default: + BlockState state = BlockState.getFromOrdinal(ordinal); + int mcId = registry.getInternalBlockStateId(state).getAsInt(); + sectionWriter.writeVarInt(mcId); + break; + } + } + sectionWriter.writeVarInt(palette.blockStatesLength); + for (int i = 0; i < palette.blockStatesLength; i++) { + sectionWriter.writeLong(palette.blockStates[i]); + } + } + } + +// if (writeBiomes) { +// for (int x = 0; x < 16; x++) { +// for (int z = 0; z < 16; z++) { +// BiomeType biome = this.getBiomeType(x, z); +// if (biome == null) { +// if (writeBiomes) { +// break; +// } else { +// biome = BiomeTypes.FOREST; +// } +// } +// } +// } +// } + if (writeBiomes) { + for (int i = 0; i < 256; i++) { + // TODO biomes + sectionWriter.writeInt(0); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + return sectionByteArray.toByteArray(); + } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/BatchProcessorHolder.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/BatchProcessorHolder.java index 7d0089be9..c958385b3 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/BatchProcessorHolder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/BatchProcessorHolder.java @@ -1,6 +1,9 @@ package com.boydti.fawe.beta.implementation; import com.boydti.fawe.beta.IBatchProcessor; +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IChunkSet; public class BatchProcessorHolder implements IBatchProcessorHolder { private IBatchProcessor processor = EmptyBatchProcessor.INSTANCE; @@ -10,6 +13,13 @@ public class BatchProcessorHolder implements IBatchProcessorHolder { return processor; } + @Override + public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) { + System.out.println("Process set"); + System.out.println(getProcessor()); + return getProcessor().processSet(chunk, get, set); + } + @Override public void setProcessor(IBatchProcessor set) { this.processor = set; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/ChunkPacket.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/ChunkPacket.java index d0499694d..7da7f129b 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/ChunkPacket.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/ChunkPacket.java @@ -4,42 +4,100 @@ import com.boydti.fawe.FaweCache; import com.boydti.fawe.beta.IBlocks; import com.boydti.fawe.object.FaweOutputStream; import com.boydti.fawe.object.io.FastByteArrayOutputStream; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.extension.platform.Capability; -import com.sk89q.worldedit.world.block.BlockID; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.registry.BlockRegistry; +import com.sk89q.jnbt.CompoundTag; +import java.util.HashMap; import java.util.function.Function; import java.util.function.Supplier; public class ChunkPacket implements Function, Supplier { private final boolean full; - private final boolean biomes; - private final IBlocks chunk; - private final int chunkX; - private final int chunkZ; + private final Supplier chunkSupplier; + private IBlocks chunk; - public ChunkPacket(int chunkX, int chunkZ, IBlocks chunk, boolean replaceAllSections, boolean sendBiomeData) { + private int chunkX; + private int chunkZ; + private byte[] sectionBytes; + private Object nativePacket; + + public ChunkPacket(int chunkX, int chunkZ, Supplier chunkSupplier, boolean replaceAllSections) { this.chunkX = chunkX; this.chunkZ = chunkZ; - this.chunk = chunk; + this.chunkSupplier = chunkSupplier; this.full = replaceAllSections; - this.biomes = sendBiomeData; + } + + public int getChunkX() { + return chunkX; + } + + public int getChunkZ() { + return chunkZ; + } + + public synchronized void setPosition(int chunkX, int chunkZ) { + this.chunkX = chunkX; + this.chunkZ = chunkZ; + nativePacket = null; + } + + public boolean isFull() { + return full; + } + + public IBlocks getChunk() { + if (this.chunk == null) { + synchronized (this) { + if (this.chunk == null) { + this.chunk = chunkSupplier.get(); + } + } + } + return chunk; + } + + private byte[] getSectionBytes() { + byte[] tmp = this.sectionBytes; + if (tmp == null) { + synchronized (this) { + if (sectionBytes == null) { + sectionBytes = getChunk().toByteArray(FaweCache.IMP.BYTE_BUFFER_8192.get(), this.full); + } + tmp = sectionBytes; + } + } + return tmp; + } + + public Object getNativePacket() { + return nativePacket; + } + + public void setNativePacket(Object nativePacket) { + this.nativePacket = nativePacket; } @Override @Deprecated public byte[] get() { - System.out.println("TODO deprecated, use buffer"); - return apply(new byte[8192]); + return apply(FaweCache.IMP.BYTE_BUFFER_8192.get()); + } + + public CompoundTag getHeightMap() { + HashMap map = new HashMap<>(); + map.put("MOTION_BLOCKING", new long[36]); + CompoundTag tag = FaweCache.IMP.asTag(map); + // TODO + return tag; } @Override public byte[] apply(byte[] buffer) { try { - FastByteArrayOutputStream baos = new FastByteArrayOutputStream(); + byte[] sectionBytes = getSectionBytes(); + + FastByteArrayOutputStream baos = new FastByteArrayOutputStream(buffer); FaweOutputStream fos = new FaweOutputStream(baos); fos.writeInt(this.chunkX); @@ -47,75 +105,16 @@ public class ChunkPacket implements Function, Supplier { fos.writeBoolean(this.full); - fos.writeVarInt(this.chunk.getBitMask()); // writeVarInt + fos.writeVarInt(getChunk().getBitMask()); - // TODO write NBTTagCompound of HeightMaps - fos.writeVarInt(0); // (Entities / NBT) - // TODO write chunk data to byte[] - { - BlockRegistry registry = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry(); - try (FastByteArrayOutputStream sectionByteArray = new FastByteArrayOutputStream(buffer); FaweOutputStream sectionWriter = new FaweOutputStream(sectionByteArray)) { - for (int layer = 0; layer < FaweCache.IMP.CHUNK_LAYERS; layer++) { - if (!this.chunk.hasSection(layer)) continue; - char[] ids = this.chunk.getArray(layer); - FaweCache.Palette palette = FaweCache.IMP.toPalette(0, ids); + fos.writeNBT("", getHeightMap()); - int nonEmpty = 0; // TODO optimize into same loop as toPalette - for (char id :ids) { - if (id != 0) nonEmpty++; - } - sectionWriter.writeShort(nonEmpty); // non empty - sectionWriter.writeByte(palette.bitsPerEntry); // bits per block - sectionWriter.writeVarInt(palette.paletteToBlockLength); - for (int i = 0; i < palette.paletteToBlockLength; i++) { - int ordinal = palette.paletteToBlock[i]; - switch (ordinal) { - case BlockID.CAVE_AIR: - case BlockID.VOID_AIR: - case BlockID.AIR: - case BlockID.__RESERVED__: - sectionWriter.writeByte(0); - break; - default: - BlockState state = BlockState.getFromOrdinal(ordinal); - int mcId = registry.getInternalBlockStateId(state).getAsInt(); - sectionWriter.writeVarInt(mcId); - } - } - sectionWriter.writeVarInt(palette.blockStatesLength); - for (int i = 0; i < palette.blockStatesLength; i++) { - sectionWriter.writeLong(palette.blockStates[i]); - } - } - - // TODO write biomes -// boolean writeBiomes = true; -// for (int x = 0; x < 16; x++) { -// for (int z = 0; z < 16; z++) { -// BiomeType biome = this.chunk.getBiomeType(x, z); -// if (biome == null) { -// if (writeBiomes) { -// break; -// } else { -// biome = BiomeTypes.FOREST; -// } -// } -// } -// } - if (this.full) { - for (int i = 0; i < 256; i++) { - sectionWriter.writeInt(0); - } - } - - fos.writeVarInt(sectionByteArray.getSize()); - for (byte[] arr : sectionByteArray.toByteArrays()) { - fos.write(arr); - } - } - } + fos.writeVarInt(sectionBytes.length); + fos.write(sectionBytes); // TODO entities / NBT +// Set entities = chunk.getEntities(); +// Map tiles = chunk.getTiles(); fos.writeVarInt(0); // (Entities / NBT) return baos.toByteArray(); } catch (Throwable e) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/ChunkSendProcessor.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/ChunkSendProcessor.java index 53635ba07..aaf87a179 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/ChunkSendProcessor.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/ChunkSendProcessor.java @@ -4,21 +4,21 @@ import com.boydti.fawe.beta.IBatchProcessor; import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.IChunkGet; import com.boydti.fawe.beta.IChunkSet; -import com.boydti.fawe.object.extent.NullExtent; import com.google.common.base.Suppliers; import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.world.World; import java.util.function.Supplier; import java.util.stream.Stream; -public class ChunkSendProcessor extends AbstractDelegateExtent implements IBatchProcessor { +public class ChunkSendProcessor implements IBatchProcessor { private final Supplier> players; + private final World world; - public ChunkSendProcessor(Supplier> players) { - super(new NullExtent()); + public ChunkSendProcessor(World world, Supplier> players) { this.players = players; + this.world = world; } @Override @@ -26,10 +26,14 @@ public class ChunkSendProcessor extends AbstractDelegateExtent implements IBatch int chunkX = chunk.getX(); int chunkZ = chunk.getZ(); boolean replaceAll = true; - boolean sendBiome = set.getBiomes() != null; - ChunkPacket packet = new ChunkPacket(chunkX, chunkZ, set, replaceAll, sendBiome); - Supplier packetData = Suppliers.memoize(packet::get); - players.get().forEach(plr -> plr.sendFakeChunk(chunkX, chunkZ, packetData)); + ChunkPacket packet = new ChunkPacket(chunkX, chunkZ, () -> set, replaceAll); + Stream stream = this.players.get(); + if (stream == null) { + world.sendFakeChunk(null, packet); + } else { + stream.filter(player -> player.getWorld().equals(world)) + .forEach(player -> world.sendFakeChunk(player, packet)); + } return set; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/IBatchProcessorHolder.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/IBatchProcessorHolder.java index 6712c5ec4..62226e18a 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/IBatchProcessorHolder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/IBatchProcessorHolder.java @@ -37,6 +37,7 @@ public interface IBatchProcessorHolder extends IBatchProcessor { @Override default IBatchProcessor join(IBatchProcessor other) { setProcessor(getProcessor().join(other)); + System.out.println("Join " + other + " | " + getProcessor()); return this; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/MultiBatchProcessor.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/MultiBatchProcessor.java index 6cd975d30..a4b5de86a 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/MultiBatchProcessor.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/MultiBatchProcessor.java @@ -55,13 +55,21 @@ public class MultiBatchProcessor implements IBatchProcessor { @Override public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) { - for (IBatchProcessor processor : this.processors) { - set = processor.processSet(chunk, get, set); - if (set == null) { - return null; + try { + System.out.println("Processes len " + this.processors.length); + for (IBatchProcessor processor : this.processors) { + set = processor.processSet(chunk, get, set); + if (set == null) { + System.out.println("Return null " + processor.getClass()); + return null; + } + System.out.println("Process " + processor.getClass()); } + return set; + } catch (Throwable e) { + e.printStackTrace(); + throw e; } - return set; } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/NullProcessor.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/NullProcessor.java new file mode 100644 index 000000000..2c3647e6c --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/NullProcessor.java @@ -0,0 +1,22 @@ +package com.boydti.fawe.beta.implementation; + +import com.boydti.fawe.beta.IBatchProcessor; +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IChunkSet; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.NullExtent; + +public enum NullProcessor implements IBatchProcessor { + INSTANCE; + @Override + public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) { + System.out.println("Null process " + chunk.getX() + "," + chunk.getZ()); + return null; + } + + @Override + public Extent construct(Extent child) { + return new NullExtent(); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SingleThreadQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SingleThreadQueueExtent.java index b22dc5694..f841bc969 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SingleThreadQueueExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SingleThreadQueueExtent.java @@ -89,6 +89,8 @@ public class SingleThreadQueueExtent extends BatchProcessorHolder implements IQu */ protected synchronized void reset() { if (!this.initialized) return; + System.out.println("Reset"); + new Exception().printStackTrace(); checkThread(); if (!this.chunks.isEmpty()) { for (IChunk chunk : this.chunks.values()) { @@ -128,6 +130,7 @@ public class SingleThreadQueueExtent extends BatchProcessorHolder implements IQu @Override public Extent addProcessor(IBatchProcessor processor) { join(processor); + System.out.println("Add processor " + this.getClass()); return this; } @@ -276,11 +279,20 @@ public class SingleThreadQueueExtent extends BatchProcessorHolder implements IQu private void pollSubmissions(int targetSize, boolean aggressive) { final int overflow = submissions.size() - targetSize; if (aggressive) { + if (targetSize == 0) { + while (!submissions.isEmpty()) { + Future future = submissions.poll(); + try { + while (future != null) future = (Future) future.get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + } + } for (int i = 0; i < overflow; i++) { Future first = submissions.poll(); try { - while ((first = (Future) first.get()) != null) { - } + while ((first = (Future) first.get()) != null); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } @@ -327,7 +339,7 @@ public class SingleThreadQueueExtent extends BatchProcessorHolder implements IQu chunks.clear(); } pollSubmissions(0, true); - reset(); + System.out.println(submissions.size()); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/cfi/HeightMapMCAGenerator.java b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/cfi/HeightMapMCAGenerator.java index b5e8aa4ab..4f2a0e81f 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/cfi/HeightMapMCAGenerator.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/cfi/HeightMapMCAGenerator.java @@ -2,6 +2,7 @@ package com.boydti.fawe.object.brush.visualization.cfi; import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.IBlocks; import com.boydti.fawe.beta.IChunkGet; import com.boydti.fawe.beta.IChunkSet; import com.boydti.fawe.beta.implementation.ChunkPacket; @@ -21,6 +22,7 @@ import com.boydti.fawe.object.schematic.Schematic; import com.boydti.fawe.util.CachedTextureUtil; import com.boydti.fawe.util.RandomTextureUtil; import com.boydti.fawe.util.ReflectionUtils; +import com.boydti.fawe.util.TaskManager; import com.boydti.fawe.util.TextureUtil; import com.boydti.fawe.util.image.Drawable; import com.boydti.fawe.util.image.ImageViewer; @@ -69,7 +71,6 @@ import java.util.concurrent.ThreadLocalRandom; import java.util.function.Supplier; import javax.annotation.Nullable; -// TODO FIXME public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Drawable, VirtualWorld { private final MutableBlockVector3 mutable = new MutableBlockVector3(); @@ -282,51 +283,53 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr if (viewer != null) { viewer.view(this); } -// if (chunkOffset != null && player != null) { TODO NOT IMPLEMENTED -// IQueueExtent packetQueue = SetQueue.IMP.getNewQueue(player.getWorld(), true, false); -// -// if (!packetQueue.supports(Capability.CHUNK_PACKETS)) { -// return; -// } -// -// int lenCX = (getWidth() + 15) >> 4; -// int lenCZ = (getLength() + 15) >> 4; -// -// int OX = chunkOffset.getBlockX(); -// int OZ = chunkOffset.getBlockZ(); -// -// Location position = player.getLocation(); -// int pcx = (position.getBlockX() >> 4) - OX; -// int pcz = (position.getBlockZ() >> 4) - OZ; -// -// int scx = Math.max(0, pcx - 15); -// int scz = Math.max(0, pcz - 15); -// int ecx = Math.min(lenCX - 1, pcx + 15); -// int ecz = Math.min(lenCZ - 1, pcz + 15); -// -// for (int cz = scz; cz <= ecz; cz++) { -// for (int cx = scx; cx <= ecx; cx++) { -// final int finalCX = cx; -// final int finalCZ = cz; -// TaskManager.IMP.getPublicForkJoinPool().submit(() -> { -// try { -// FaweChunk toSend = getSnapshot(finalCX, finalCZ); -// toSend.setLoc(HeightMapMCAGenerator.this, finalCX + OX, finalCZ + OZ); -// packetQueue.sendChunkUpdate(toSend, player); -// } catch (Throwable e) { -// e.printStackTrace(); -// } -// }); -// } -// } -// } + if (chunkOffset != null && player != null) { + World world = player.getWorld(); + + int lenCX = (getWidth() + 15) >> 4; + int lenCZ = (getLength() + 15) >> 4; + + int OX = chunkOffset.getBlockX(); + int OZ = chunkOffset.getBlockZ(); + + Location position = player.getLocation(); + int pcx = (position.getBlockX() >> 4) - OX; + int pcz = (position.getBlockZ() >> 4) - OZ; + + int scx = Math.max(0, pcx - 15); + int scz = Math.max(0, pcz - 15); + int ecx = Math.min(lenCX - 1, pcx + 15); + int ecz = Math.min(lenCZ - 1, pcz + 15); + + for (int chunkZ = scz; chunkZ <= ecz; chunkZ++) { + for (int chunkX = scx; chunkX <= ecx; chunkX++) { + int finalChunkX = chunkX; + int finalChunkZ = chunkZ; + + int realWorldX = chunkX + OX; + int realWorldZ = chunkZ + OZ; + + Supplier blocksSupplier = () -> getChunk(finalChunkX, finalChunkZ); + + ChunkPacket packet = new ChunkPacket(realWorldX, realWorldZ, blocksSupplier, true); + world.sendFakeChunk(player, packet); + } + } + } + } + + @Override + public void sendFakeChunk(@Nullable Player player, ChunkPacket packet) { + if (this.player != null) { + player.getWorld().sendFakeChunk(player, packet); + } } @Override public void refreshChunk(int chunkX, int chunkZ) { - IChunkSet chunk = getChunk(chunkX, chunkZ); - ChunkPacket packet = new ChunkPacket(chunkX, chunkZ, chunk, true, true); - player.sendFakeChunk(chunkX, chunkZ, packet::get); + if (chunkOffset != null && player != null) { + player.getWorld().refreshChunk(chunkX, chunkZ); + } } public IChunkSet getChunk(int chunkX, int chunkZ) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BitArray4096.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BitArray4096.java index 6dc10cd77..f9e434db3 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BitArray4096.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BitArray4096.java @@ -28,6 +28,10 @@ public final class BitArray4096 { this.data = new long[longLen]; } + public long[] getData() { + return data; + } + public final void setAt(int index, int value) { if (longLen == 0) return; int bitIndexStart = index * bitsPerEntry; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/StringMan.java b/worldedit-core/src/main/java/com/boydti/fawe/util/StringMan.java index 1cf6e56ba..cf34d9b85 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/StringMan.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/StringMan.java @@ -59,8 +59,8 @@ public class StringMan { } public static String prettyFormat(double d) { - if (d == Double.MIN_VALUE) return "-∞"; - if (d == Double.MAX_VALUE) return "∞"; + if (d == Double.MIN_VALUE || d == Double.NEGATIVE_INFINITY) return "-∞"; + if (d == Double.MAX_VALUE || d == Double.POSITIVE_INFINITY) return "∞"; if(d == (long) d) return String.format("%d",(long)d); else return String.format("%s",d); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java b/worldedit-core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java index 4d8b99fc5..e02b08b0b 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java @@ -1,6 +1,7 @@ package com.boydti.fawe.wrappers; import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.implementation.ChunkPacket; import com.boydti.fawe.object.RunnableVal; import com.boydti.fawe.util.ExtentTraverser; import com.boydti.fawe.util.TaskManager; @@ -13,6 +14,7 @@ import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.Extent; @@ -304,4 +306,9 @@ public class WorldWrapper extends AbstractWorld { public IChunkGet get(int x, int z) { return parent.get(x, z); } + + @Override + public void sendFakeChunk(@Nullable Player player, ChunkPacket packet) { + parent.sendFakeChunk(player, packet); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTOutputStream.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTOutputStream.java index 6aa559a9e..107cbaae6 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTOutputStream.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTOutputStream.java @@ -167,11 +167,12 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da } public void writeNamedTagName(String name, int type) throws IOException { - byte[] nameBytes = name.getBytes(NBTConstants.CHARSET); +// byte[] nameBytes = name.getBytes(NBTConstants.CHARSET); os.writeByte(type); - os.writeShort(nameBytes.length); - os.write(nameBytes); + os.writeUTF(name); +// os.writeShort(nameBytes.length); +// os.write(nameBytes); } public void writeLazyCompoundTag(String name, LazyWrite next) throws IOException { @@ -208,47 +209,47 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da public void writeTagPayload(Tag tag) throws IOException { int type = NBTUtils.getTypeCode(tag.getClass()); switch (type) { - case NBTConstants.TYPE_END: - writeEndTagPayload((EndTag) tag); - break; - case NBTConstants.TYPE_BYTE: - writeByteTagPayload((ByteTag) tag); - break; - case NBTConstants.TYPE_SHORT: - writeShortTagPayload((ShortTag) tag); - break; - case NBTConstants.TYPE_INT: - writeIntTagPayload((IntTag) tag); - break; - case NBTConstants.TYPE_LONG: - writeLongTagPayload((LongTag) tag); - break; - case NBTConstants.TYPE_FLOAT: - writeFloatTagPayload((FloatTag) tag); - break; - case NBTConstants.TYPE_DOUBLE: - writeDoubleTagPayload((DoubleTag) tag); - break; - case NBTConstants.TYPE_BYTE_ARRAY: - writeByteArrayTagPayload((ByteArrayTag) tag); - break; - case NBTConstants.TYPE_STRING: - writeStringTagPayload((StringTag) tag); - break; - case NBTConstants.TYPE_LIST: - writeListTagPayload((ListTag) tag); - break; - case NBTConstants.TYPE_COMPOUND: - writeCompoundTagPayload((CompoundTag) tag); - break; - case NBTConstants.TYPE_INT_ARRAY: - writeIntArrayTagPayload((IntArrayTag) tag); - break; - case NBTConstants.TYPE_LONG_ARRAY: - writeLongArrayTagPayload((LongArrayTag) tag); - break; - default: - throw new IOException("Invalid tag type: " + type + "."); + case NBTConstants.TYPE_END: + writeEndTagPayload((EndTag) tag); + break; + case NBTConstants.TYPE_BYTE: + writeByteTagPayload((ByteTag) tag); + break; + case NBTConstants.TYPE_SHORT: + writeShortTagPayload((ShortTag) tag); + break; + case NBTConstants.TYPE_INT: + writeIntTagPayload((IntTag) tag); + break; + case NBTConstants.TYPE_LONG: + writeLongTagPayload((LongTag) tag); + break; + case NBTConstants.TYPE_FLOAT: + writeFloatTagPayload((FloatTag) tag); + break; + case NBTConstants.TYPE_DOUBLE: + writeDoubleTagPayload((DoubleTag) tag); + break; + case NBTConstants.TYPE_BYTE_ARRAY: + writeByteArrayTagPayload((ByteArrayTag) tag); + break; + case NBTConstants.TYPE_STRING: + writeStringTagPayload((StringTag) tag); + break; + case NBTConstants.TYPE_LIST: + writeListTagPayload((ListTag) tag); + break; + case NBTConstants.TYPE_COMPOUND: + writeCompoundTagPayload((CompoundTag) tag); + break; + case NBTConstants.TYPE_INT_ARRAY: + writeIntArrayTagPayload((IntArrayTag) tag); + break; + case NBTConstants.TYPE_LONG_ARRAY: + writeLongArrayTagPayload((LongArrayTag) tag); + break; + default: + throw new IOException("Invalid tag type: " + type + "."); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java index 7f8928a00..f768082ee 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -540,6 +540,7 @@ public class ClipboardCommands { @Command( name = "/rotate", + aliases = {"/rt"}, desc = "Rotate the contents of the clipboard", descFooter = "Non-destructively rotate the contents of the clipboard.\n" + "Angles are provided in degrees and a positive angle will result in a clockwise rotation. " + diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java index 065f09e2a..d2de57e6c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java @@ -219,8 +219,8 @@ public class HistoryCommands { } @Command( - name = "undo", - aliases = { "/undo" }, + name = "/undo", + aliases = { "/un", "/ud", "undo" }, desc = "Undoes the last action (from history)" ) @CommandPermissions({"worldedit.history.undo", "worldedit.history.undo.self"}) @@ -266,8 +266,8 @@ public class HistoryCommands { } @Command( - name = "redo", - aliases = { "/redo" }, + name = "/redo", + aliases = { "/do", "/rd", "redo" }, desc = "Redoes the last action (from history)" ) @CommandPermissions({"worldedit.history.redo", "worldedit.history.redo.self"}) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index 1399f05b4..46e02ef25 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -31,6 +31,8 @@ import static com.sk89q.worldedit.regions.Regions.minimumBlockY; import com.boydti.fawe.FaweAPI; import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.implementation.ChunkSendProcessor; +import com.boydti.fawe.beta.implementation.NullProcessor; import com.boydti.fawe.config.BBC; import com.boydti.fawe.object.FaweLimit; import com.sk89q.jnbt.CompoundTag; @@ -74,8 +76,13 @@ import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockStateHolder; import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import com.sk89q.worldedit.world.block.BlockTypes; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; @@ -102,15 +109,29 @@ public class RegionCommands { } @Command( - name = "/set", - desc = "Sets all the blocks in the region" + name = "/air", + aliases = {"/0"}, + desc = "Sets all the blocks in the region to air" + ) + @CommandPermissions("worldedit.region.set") + @Logging(REGION) + public void air(Actor actor, EditSession editSession, + @Selection Region region, + InjectedValueAccess context) throws WorldEditException { + set(actor, editSession, region, BlockTypes.AIR, context); + } + + @Command( + name = "/set", + aliases = {"/"}, + desc = "Sets all the blocks in the region" ) @CommandPermissions("worldedit.region.set") @Logging(REGION) public void set(Actor actor, EditSession editSession, - @Selection Region region, - @Arg(desc = "The pattern of blocks to set") - Pattern pattern, InjectedValueAccess context) throws WorldEditException { + @Selection Region region, + @Arg(desc = "The pattern of blocks to set") + Pattern pattern, InjectedValueAccess context) throws WorldEditException { actor.checkConfirmationRegion(() -> { int affected = editSession.setBlocks(region, pattern); if (affected != 0) { @@ -121,6 +142,22 @@ public class RegionCommands { }, getArguments(context), region, context); } + @Command( + name = "/test", + desc = "test region" + ) + @CommandPermissions("worldedit.region.test") + @Logging(REGION) + public void test(World world, Player player, EditSession editSession, + @Selection Region region, + @Arg(desc = "The pattern of blocks to set") + Pattern pattern, InjectedValueAccess context) throws WorldEditException { + editSession.addProcessor(new ChunkSendProcessor(world, () -> Stream.of(player))); + editSession.addProcessor(NullProcessor.INSTANCE); + editSession.setBlocks(region, pattern); + System.out.println("Done"); + } + @Command( name = "/fixlighting", desc = "Get the light at a position" @@ -267,7 +304,7 @@ public class RegionCommands { @Command( name = "/replace", - aliases = { "/re", "/rep", "/r" }, + aliases = { "/repl", "/rep" }, desc = "Replace all blocks in the selection with another" ) @CommandPermissions("worldedit.region.replace") @@ -459,6 +496,7 @@ public class RegionCommands { @Command( name = "/move", + aliases = {"/mv"}, desc = "Move the contents of the selection" ) @CommandPermissions("worldedit.region.move") diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java index 4f0da9e1b..41d2e7ed8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java @@ -194,8 +194,8 @@ public class ToolUtilCommands { } @Command( - name = "/", - aliases = {","}, + name = "/superpickaxe", + aliases = {",", "sp", "/sp", "superpickaxe", "/pickaxe"}, desc = "Toggle the super pickaxe function" ) @CommandPermissions("worldedit.superpickaxe") diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index c88df6d22..aa46a1c61 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -421,7 +421,7 @@ public class UtilityCommands { @Command( name = "replacenear", - aliases = { "/replacenear" }, + aliases = { "/replacenear", "/rn" }, desc = "Replace nearby blocks" ) @CommandPermissions("worldedit.replacenear") 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 54614aae1..9da5bb016 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 @@ -20,6 +20,7 @@ package com.sk89q.worldedit.entity; import com.boydti.fawe.Fawe; +import com.boydti.fawe.beta.implementation.ChunkPacket; import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.brush.visualization.VirtualWorld; import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard; @@ -321,8 +322,6 @@ public interface Player extends Entity, Actor { */ > void sendFakeBlock(BlockVector3 pos, @Nullable B block); - void sendFakeChunk(int chunkX, int chunkZ, Supplier data); - public Region[] getCurrentRegions(); Region[] getCurrentRegions(FaweMaskManager.MaskType type); 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 8e50fa592..22ac8e8e9 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 @@ -212,11 +212,6 @@ public class PlayerProxy extends AbstractPlayerActor { basePlayer.sendFakeBlock(pos, block); } - @Override - public void sendFakeChunk(int chunkX, int chunkZ, Supplier data) { - basePlayer.sendFakeChunk(chunkX, chunkZ, data); - } - @Override public void sendTitle(String title, String sub) { basePlayer.sendTitle(title, sub); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java index 3e76ebb66..9ad7325b2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.world; import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.implementation.ChunkPacket; import com.boydti.fawe.beta.implementation.NullChunkGet; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.EditSession; @@ -28,6 +29,7 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; @@ -207,4 +209,8 @@ public class NullWorld extends AbstractWorld { return INSTANCE; } + @Override + public void sendFakeChunk(@Nullable Player player, ChunkPacket packet) { + + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java index ea7f42be5..1d3031a7d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.world; import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.implementation.ChunkPacket; import com.boydti.fawe.beta.implementation.IChunkCache; import com.boydti.fawe.object.extent.LightingExtent; import com.sk89q.worldedit.EditSession; @@ -27,6 +28,7 @@ import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.mask.Mask; @@ -304,4 +306,11 @@ public interface World extends Extent, Keyed, IChunkCache { @Override IChunkGet get(int x, int z); + + /** + * Send a fake chunk to a player/s + * @param player may be null to send to everyone + * @param packet the chunk packet + */ + void sendFakeChunk(@Nullable Player player, ChunkPacket packet); }