From cc80bc61cff860563d74166238e5440bd9b83fdb Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Thu, 25 Apr 2019 00:10:52 +1000 Subject: [PATCH 01/54] Compiles in 1.14 (yay) --- .../com/boydti/fawe/bukkit/FaweBukkit.java | 22 -- .../bukkit/listener/CFIPacketListener.java | 16 +- .../fawe/bukkit/listener/RenderListener.java | 3 +- .../fawe/bukkit/util/cui/CUIListener.java | 31 --- .../fawe/bukkit/util/cui/StructureCUI.java | 200 -------------- .../fawe/bukkit/v0/BukkitQueue_All.java | 2 +- .../fawe/bukkit/v0/PaperChunkCallback.java | 3 +- .../fawe/bukkit/v1_13/BukkitQueue_1_13.java | 2 +- .../fawe/bukkit/v1_14/BukkitQueue_1_14.java | 115 ++++---- .../v1_14/adapter/BlockMaterial_1_14.java | 2 +- .../bukkit/v1_14/adapter/Spigot_v1_14_R1.java | 5 +- .../fawe/bukkit/wrapper/AsyncBlock.java | 14 +- .../fawe/bukkit/wrapper/AsyncChunk.java | 31 +-- .../fawe/bukkit/wrapper/AsyncWorld.java | 254 +++++++++--------- .../src/main/java/com/boydti/fawe/Fawe.java | 20 -- .../src/main/java/com/boydti/fawe/IFawe.java | 3 - .../java/com/boydti/fawe/util/cui/CUI.java | 18 -- .../com/sk89q/jnbt/CompressedCompoundTag.java | 1 - .../com/sk89q/worldedit/LocalSession.java | 6 +- 19 files changed, 227 insertions(+), 521 deletions(-) delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/util/cui/CUIListener.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/util/cui/StructureCUI.java delete mode 100644 worldedit-core/src/main/java/com/boydti/fawe/util/cui/CUI.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 793f2ef1e..296ef8e53 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 @@ -24,8 +24,6 @@ import com.boydti.fawe.bukkit.util.BukkitReflectionUtils; import com.boydti.fawe.bukkit.util.BukkitTaskMan; import com.boydti.fawe.bukkit.util.ItemUtil; import com.boydti.fawe.bukkit.util.VaultUtil; -import com.boydti.fawe.bukkit.util.cui.CUIListener; -import com.boydti.fawe.bukkit.util.cui.StructureCUI; import com.boydti.fawe.bukkit.util.image.BukkitImageViewer; import com.boydti.fawe.bukkit.v0.BukkitQueue_0; import com.boydti.fawe.bukkit.v0.BukkitQueue_All; @@ -41,7 +39,6 @@ import com.boydti.fawe.regions.FaweMaskManager; import com.boydti.fawe.util.Jars; import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.TaskManager; -import com.boydti.fawe.util.cui.CUI; import com.boydti.fawe.util.image.ImageViewer; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.world.World; @@ -79,7 +76,6 @@ public class FaweBukkit implements IFawe, Listener { private CFIPacketListener packetListener; private boolean listeningCui; - private CUIListener cuiListener; public VaultUtil getVault() { return this.vault; @@ -144,24 +140,6 @@ public class FaweBukkit implements IFawe, Listener { }); } - @Override - public CUI getCUI(FawePlayer player) { - if (Settings.IMP.EXPERIMENTAL.VANILLA_CUI) { - if (listeningCui && cuiListener == null) return null; - listeningCui = true; - if (cuiListener == null) { - Plugin protocolLib = Bukkit.getPluginManager().getPlugin("ProtocolLib"); - if (protocolLib != null && protocolLib.isEnabled()) { - cuiListener = new CUIListener(plugin); - } else { - return null; - } - } - return new StructureCUI(player); - } - return null; - } - @Override public void registerPacketListener() { PluginManager manager = Bukkit.getPluginManager(); diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/listener/CFIPacketListener.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/listener/CFIPacketListener.java index 2053d8f9c..7f5ef82c5 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/listener/CFIPacketListener.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/listener/CFIPacketListener.java @@ -91,11 +91,17 @@ public class CFIPacketListener implements Listener { ItemStack hand = enumHand == EnumWrappers.Hand.MAIN_HAND ? inv.getItemInMainHand() : inv.getItemInOffHand(); if (hand != null && hand.getType().isBlock()) { Material type = hand.getType(); - if (!type.isEmpty()) { - BlockStateHolder block = BukkitAdapter.asBlockState(hand); - if (block != null) { - gen.setBlock(pt, block); - return; + switch (type) { + case AIR: + case CAVE_AIR: + case VOID_AIR: + break; + default: { + BlockStateHolder block = BukkitAdapter.asBlockState(hand); + if (block != null) { + gen.setBlock(pt, block); + return; + } } } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/listener/RenderListener.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/listener/RenderListener.java index 8824f369c..7b97ec1ad 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/listener/RenderListener.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/listener/RenderListener.java @@ -96,7 +96,8 @@ public class RenderListener implements Listener { } } } - player.setViewDistance(value); + throw new UnsupportedOperationException("TODO FIXME: PAPER 1.14"); +// player.setViewDistance(value); } public int getViewDistance(Player player) { diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/util/cui/CUIListener.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/util/cui/CUIListener.java deleted file mode 100644 index 2101d64b8..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/util/cui/CUIListener.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.boydti.fawe.bukkit.util.cui; - -import com.boydti.fawe.object.FawePlayer; -import com.boydti.fawe.util.cui.CUI; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerMoveEvent; -import org.bukkit.plugin.Plugin; - -public class CUIListener implements Listener { - - public CUIListener(Plugin plugin) { - Bukkit.getPluginManager().registerEvents(this, plugin); - } - - @EventHandler - public void onPlayerMove(PlayerMoveEvent event) { - Location from = event.getFrom(); - Location to = event.getTo(); - if ((int) from.getX() >> 2 != (int) to.getX() >> 2 || (int) from.getZ() >> 2 != (int) to.getZ() >> 2 || (int) from.getY() >> 2 != (int) to.getY() >> 2) { - FawePlayer player = FawePlayer.wrap(event.getPlayer()); - CUI cui = player.getMeta("CUI"); - if (cui instanceof StructureCUI) { - StructureCUI sCui = (StructureCUI) cui; - sCui.update(); - } - } - } -} \ No newline at end of file diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/util/cui/StructureCUI.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/util/cui/StructureCUI.java deleted file mode 100644 index b1e389cc6..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/util/cui/StructureCUI.java +++ /dev/null @@ -1,200 +0,0 @@ -package com.boydti.fawe.bukkit.util.cui; - -import com.boydti.fawe.FaweCache; -import com.boydti.fawe.bukkit.v0.BukkitQueue_0; -import com.boydti.fawe.object.FawePlayer; -import com.boydti.fawe.util.cui.CUI; -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.ProtocolManager; -import com.comphenix.protocol.events.PacketContainer; -import com.comphenix.protocol.injector.PacketConstructor; -import com.comphenix.protocol.wrappers.BlockPosition; -import com.comphenix.protocol.wrappers.nbt.NbtBase; -import com.comphenix.protocol.wrappers.nbt.NbtCompound; -import com.comphenix.protocol.wrappers.nbt.NbtFactory; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.internal.cui.CUIEvent; -import com.sk89q.worldedit.internal.cui.SelectionPointEvent; -import com.sk89q.worldedit.internal.cui.SelectionShapeEvent; -import com.sk89q.worldedit.math.BlockVector3; - -import java.lang.reflect.InvocationTargetException; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -import com.sk89q.worldedit.world.block.BlockState; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.entity.Player; - -public class StructureCUI extends CUI { - private boolean cuboid = true; - - private BlockVector3 pos1; - private BlockVector3 pos2; - - private BlockVector3 remove; - private NbtCompound removeTag; - private BlockState state; - - public StructureCUI(FawePlayer player) { - super(player); - } - - @Override - public void dispatchCUIEvent(CUIEvent event) { - if (event instanceof SelectionShapeEvent) { - clear(); - this.cuboid = event.getParameters()[0].equalsIgnoreCase("cuboid"); - } else if (cuboid && event instanceof SelectionPointEvent) { - SelectionPointEvent spe = (SelectionPointEvent) event; - String[] param = spe.getParameters(); - int id = Integer.parseInt(param[0]); - int x = Integer.parseInt(param[1]); - int y = Integer.parseInt(param[2]); - int z = Integer.parseInt(param[3]); - BlockVector3 pos = BlockVector3.at(x, y, z); - if (id == 0) { - pos1 = pos; - } else { - pos2 = pos; - } - update(); - } - } - - private int viewDistance() { - Player player = this.getPlayer().parent; - if (Bukkit.getVersion().contains("paper")) { - return player.getViewDistance(); - } else { - return Bukkit.getViewDistance(); - } - } - - public void clear() { - pos1 = null; - pos2 = null; - update(); - } - - private NbtCompound constructStructureNbt(int x, int y, int z, int posX, int posY, int posZ, int sizeX, int sizeY, int sizeZ) { - HashMap tag = new HashMap<>(); - tag.put("name", UUID.randomUUID().toString()); - tag.put("author", "Empire92"); // :D - tag.put("metadata", ""); - tag.put("x", x); - tag.put("y", y); - tag.put("z", z); - tag.put("posX", posX); - tag.put("posY", posY); - tag.put("posZ", posZ); - tag.put("sizeX", sizeX); - tag.put("sizeY", sizeY); - tag.put("sizeZ", sizeZ); - tag.put("rotation", "NONE"); - tag.put("mirror", "NONE"); - tag.put("mode", "SAVE"); - tag.put("ignoreEntities", true); - tag.put("powered", false); - tag.put("showair", false); - tag.put("showboundingbox", true); - tag.put("integrity", 1.0f); - tag.put("seed", 0); - tag.put("id", "minecraft:structure_block"); - Object nmsTag = BukkitQueue_0.fromNative(FaweCache.asTag(tag)); - return NbtFactory.fromNMSCompound(nmsTag); - } - - private void sendOp() { - Player player = this.getPlayer().parent; - ProtocolManager manager = ProtocolLibrary.getProtocolManager(); - - PacketConstructor statusCtr = manager.createPacketConstructor(PacketType.Play.Server.ENTITY_STATUS, player, (byte) 28); - PacketContainer status = statusCtr.createPacket(player, (byte) 28); - - try { - manager.sendServerPacket(player, status); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - } - - private void sendNbt(BlockVector3 pos, NbtCompound compound) { - Player player = this.getPlayer().parent; - ProtocolManager manager = ProtocolLibrary.getProtocolManager(); - - PacketContainer blockNbt = new PacketContainer(PacketType.Play.Server.TILE_ENTITY_DATA); - blockNbt.getBlockPositionModifier().write(0, new BlockPosition(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ())); - blockNbt.getIntegers().write(0, 7); - blockNbt.getNbtModifier().write(0, compound); - - - try { - manager.sendServerPacket(player, blockNbt); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - } - - public synchronized void update() { - Player player = this.getPlayer().parent; - Location playerLoc = player.getLocation(); - boolean setOp = remove == null && !player.isOp(); - if (remove != null) { - int cx = playerLoc.getBlockX() >> 4; - int cz = playerLoc.getBlockZ() >> 4; - int viewDistance = viewDistance(); - if (Math.abs(cx - (remove.getBlockX() >> 4)) <= viewDistance && Math.abs(cz - (remove.getBlockZ() >> 4)) <= viewDistance) { - Map> map = removeTag.getValue(); - map.put("sizeX", NbtFactory.of("sizeX", 0)); - sendNbt(remove, removeTag); - Location removeLoc = new Location(player.getWorld(), remove.getX(), remove.getY(), remove.getZ()); - player.sendBlockChange(removeLoc, BukkitAdapter.adapt(state)); - } - remove = null; - } - if (pos1 == null || pos2 == null) return; - BlockVector3 min = pos1.getMinimum(pos2); - BlockVector3 max = pos1.getMaximum(pos2); - - // Position - double rotX = playerLoc.getYaw(); - double rotY = playerLoc.getPitch(); - double xz = Math.cos(Math.toRadians(rotY)); - int x = (int) (playerLoc.getX() - (-xz * Math.sin(Math.toRadians(rotX))) * 12); - int z = (int) (playerLoc.getZ() - (xz * Math.cos(Math.toRadians(rotX))) * 12); - int y = Math.max(0, Math.min(Math.min(255, max.getBlockY() + 32), playerLoc.getBlockY() + 3)); - int minX = Math.max(Math.min(32, min.getBlockX() - x), -32); - int maxX = Math.max(Math.min(32, max.getBlockX() - x + 1), -32); - int minY = Math.max(Math.min(32, min.getBlockY() - y), -32); - int maxY = Math.max(Math.min(32, max.getBlockY() - y + 1), -32); - int minZ = Math.max(Math.min(32, min.getBlockZ() - z), -32); - int maxZ = Math.max(Math.min(32, max.getBlockZ() - z + 1), -32); - int sizeX = Math.min(32, maxX - minX); - int sizeY = Math.min(32, maxY - minY); - int sizeZ = Math.min(32, maxZ - minZ); - if (sizeX == 0 || sizeY == 0 || sizeZ == 0) return; - // maxX - 32; - int posX = Math.max(minX, Math.min(16, maxX) - 32); - int posY = Math.max(minY, Math.min(16, maxY) - 32); - int posZ = Math.max(minZ, Math.min(16, maxZ) - 32); - - // NBT - NbtCompound compound = constructStructureNbt(x, y, z, posX, posY, posZ, sizeX, sizeY, sizeZ); - - Block block = player.getWorld().getBlockAt(x, y, z); - remove = BlockVector3.at(x, y, z); - state = BukkitAdapter.adapt(block.getBlockData()); - removeTag = compound; - - Location blockLoc = new Location(player.getWorld(), x, y, z); - player.sendBlockChange(blockLoc, Material.STRUCTURE_BLOCK, (byte) 0); - if (setOp) sendOp(); - sendNbt(remove, compound); - } -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java index 015b3b8fc..57147096d 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java @@ -154,7 +154,7 @@ public class BukkitQueue_All extends BukkitQueue_0= bcx && cx <= tcx && cz >= bcz && cz <= tcz) { Object nmsChunk = methodGetHandleChunk.invoke(chunk); boolean mustSave = saveChunks && (boolean) methodNeedsSaving.invoke(nmsChunk, false); - chunk.unload(mustSave, false); + chunk.unload(mustSave); if (unloaded == null) unloaded = new ArrayDeque<>(); unloaded.add(chunk); } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/PaperChunkCallback.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/PaperChunkCallback.java index 20592715a..4d22f8fa8 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/PaperChunkCallback.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/PaperChunkCallback.java @@ -5,7 +5,8 @@ import org.bukkit.World; public abstract class PaperChunkCallback { public PaperChunkCallback(World world, int x, int z) { - world.getChunkAtAsync(x, z, PaperChunkCallback.this::onLoad); +// world.getChunkAtAsync(x, z, PaperChunkCallback.this::onLoad); + throw new UnsupportedOperationException("Not implemented"); } public abstract void onLoad(Chunk chunk); diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java index 3cc50d56e..2c51c965e 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java @@ -954,7 +954,7 @@ public class BukkitQueue_1_13 extends BukkitQueue_0 { @@ -535,27 +537,17 @@ public class BukkitQueue_1_14 extends BukkitQueue_0 dataPalette = section.getBlocks(); - IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); - pos.a(x, y, z); - return ibd.b(nmsWorld, pos); + return 0; } @Override public int getBrightness(ChunkSection section, int x, int y, int z) { - DataPaletteBlock dataPalette = section.getBlocks(); - IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); - return ibd.e(); + return 0; } @Override public int getOpacityBrightnessPair(ChunkSection section, int x, int y, int z) { - DataPaletteBlock dataPalette = section.getBlocks(); - IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); - pos.a(x, y, z); - int opacity = ibd.b(nmsWorld, pos); - int brightness = ibd.e(); - return MathMan.pair16(brightness, opacity); + return 0; } @Override @@ -603,16 +595,25 @@ public class BukkitQueue_1_14 extends BukkitQueue_0() { + @Override + public void accept(EntityPlayer entityPlayer) { + for (int i = 0; i < players.length; i++) { + EntityPlayer player = ((CraftPlayer) ((BukkitPlayer) players[i]).parent).getHandle(); + if (player == entityPlayer) { + watchingArr[i] = true; + watching[0] = true; + } + } + } + }); } - if (!watching) return; + if (!watching[0]) return; final LongAdder size = new LongAdder(); if (chunk instanceof VisualChunk) { size.add(((VisualChunk) chunk).size()); @@ -656,24 +657,12 @@ public class BukkitQueue_1_14 extends BukkitQueue_0() { - @Override - public Object get() { - try { - int dirtyBits = fieldDirtyBits.getInt(playerChunk); - if (dirtyBits == 0) { - ((CraftWorld) getWorld()).getHandle().getPlayerChunkMap().a(playerChunk); - } - if (mask == 0) { - dirtyBits = 65535; - } else { - dirtyBits |= mask; - } - - fieldDirtyBits.set(playerChunk, dirtyBits); - fieldDirtyCount.set(playerChunk, 64); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - return null; - } - }); } + TaskManager.IMP.sync(new Supplier() { + @Override + public Object get() { + try { + int dirtyBits = fieldDirtyBits.getInt(playerChunk); + if (dirtyBits == 0) { + ((CraftWorld) getWorld()).getHandle().getChunkProvider().playerChunkMap.a(playerChunk); + } + if (mask == 0) { + dirtyBits = 65535; + } else { + dirtyBits |= mask; + } + + fieldDirtyBits.set(playerChunk, dirtyBits); + fieldDirtyCount.set(playerChunk, 64); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + return null; + } + }); // if (mask == 0) { // PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, 65535); // for (EntityPlayer player : playerChunk.players) { @@ -763,6 +750,7 @@ public class BukkitQueue_1_14 extends BukkitQueue_0() { - @Override - public void run(BlockState[] value) { - this.value = world.getChunkAt(x, z).getTileEntities(b); - } - }); - } +// @Override +// public BlockState[] getTileEntities(boolean b) { +// if (!isLoaded()) { +// return new BlockState[0]; +// } +// return TaskManager.IMP.sync(new RunnableVal() { +// @Override +// public void run(BlockState[] value) { +// this.value = world.getChunkAt(x, z).getTileEntities(b); +// } +// }); +// } @Override public boolean isLoaded() { @@ -163,14 +163,9 @@ public class AsyncChunk implements Chunk { return load(false); } - @Override - public boolean unload(boolean save, boolean safe) { - return world.unloadChunk(x, z, save, safe); - } - @Override public boolean unload(boolean save) { - return unload(true, false); + return world.unloadChunk(x, z, save); } @Override diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java index 269cf41ab..aa3b92e81 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java @@ -68,28 +68,6 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue parent.spawnParticle(particle, v, v1, v2, i, v3, v4, v5, v6, t); } - @Override - public Entity getEntity(UUID uuid) { - return TaskManager.IMP.sync(() -> parent.getEntity(uuid)); - } - - - @Override - public boolean createExplosion(Entity source, Location loc, float power, boolean setFire, boolean breakBlocks) { - return TaskManager.IMP.sync(() -> parent.createExplosion(source, loc, power, setFire, breakBlocks)); - } - - - @Override - public void spawnParticle(Particle particle, List receivers, Player source, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data) { - parent.spawnParticle(particle, receivers, source, x, y, z, count, offsetX, offsetY, offsetZ, extra, data); - } - - @Override - public void spawnParticle(Particle particle, List list, Player player, double v, double v1, double v2, int i, double v3, double v4, double v5, double v6, T t, boolean b) { - parent.spawnParticle(particle, list, player, v, v1, v2, i, v3, v4, v5, v6, t, b); - } - /** * @deprecated use {@link #wrap(World)} instead * @param parent Parent world @@ -185,15 +163,6 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue } } - public int getHighestBlockYAt(int x, int z, com.destroystokyo.paper.HeightmapType heightmap) throws UnsupportedOperationException { - return TaskManager.IMP.sync(new Supplier() { - @Override - public Integer get() { - return parent.getHighestBlockYAt(x, z, heightmap); - } - }); - } - @Override public WorldBorder getWorldBorder() { return TaskManager.IMP.sync(new RunnableVal() { @@ -204,6 +173,11 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue }); } + @Override + public boolean unloadChunkRequest(int x, int z) { + return unloadChunk(x, z); + } + @Override public void spawnParticle(Particle particle, Location location, int i) { parent.spawnParticle(particle, location, i); @@ -320,21 +294,6 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue return parent.isChunkGenerated(x, z); } - @Override - public void getChunkAtAsync(int x, int z, ChunkLoadCallback cb) { - parent.getChunkAtAsync(x, z, cb); - } - - @Override - public void getChunkAtAsync(Location location, ChunkLoadCallback cb) { - parent.getChunkAtAsync(location, cb); - } - - @Override - public void getChunkAtAsync(Block block, ChunkLoadCallback cb) { - parent.getChunkAtAsync(block, cb); - } - @Override public boolean isChunkLoaded(Chunk chunk) { return chunk.isLoaded(); @@ -426,33 +385,17 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue @Override public boolean unloadChunk(int x, int z, boolean save) { - return unloadChunk(x, z, save, false); - } - - @Deprecated - @Override - public boolean unloadChunk(final int x, final int z, final boolean save, final boolean safe) { if (isChunkLoaded(x, z)) { return TaskManager.IMP.sync(new RunnableVal() { @Override public void run(Boolean value) { - this.value = parent.unloadChunk(x, z, save, safe); + this.value = parent.unloadChunk(x, z, save); } }); } return true; } - @Override - public boolean unloadChunkRequest(int x, int z) { - return unloadChunk(x, z); - } - - @Override - public boolean unloadChunkRequest(int x, int z, boolean safe) { - return unloadChunk(x, z, safe); - } - @Override public boolean regenerateChunk(final int x, final int z) { return TaskManager.IMP.sync(new RunnableVal() { @@ -1132,61 +1075,6 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue return adapter; } - @Override - public int getEntityCount() { - return TaskManager.IMP.sync(new RunnableVal() { - @Override - public void run(Integer value) { - this.value = parent.getEntityCount(); - } - }); - } - - @Override - public int getTileEntityCount() { - return TaskManager.IMP.sync(new RunnableVal() { - @Override - public void run(Integer value) { - this.value = parent.getTileEntityCount(); - } - }); - } - - @Override - public int getTickableTileEntityCount() { - return TaskManager.IMP.sync(new RunnableVal() { - @Override - public void run(Integer value) { - this.value = parent.getTickableTileEntityCount(); - } - }); - } - - @Override - public int getChunkCount() { - return TaskManager.IMP.sync(new RunnableVal() { - @Override - public void run(Integer value) { - this.value = parent.getChunkCount(); - } - }); - } - - @Override - public int getPlayerCount() { - return TaskManager.IMP.sync(new RunnableVal() { - @Override - public void run(Integer value) { - this.value = parent.getPlayerCount(); - } - }); - } - - @Override - public CompletableFuture getChunkAtAsync(int arg0, int arg1, boolean arg2) { - return parent.getChunkAtAsync(arg0, arg1, arg2); - } - @Override public Collection getNearbyEntities(BoundingBox arg0) { return parent.getNearbyEntities(arg0); @@ -1208,11 +1096,6 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue return parent.isChunkForceLoaded(arg0, arg1); } - @Override - public boolean isDayTime() { - return parent.isDayTime(); - } - @Override public Location locateNearestStructure(Location arg0, StructureType arg1, int arg2, boolean arg3) { return parent.locateNearestStructure(arg0, arg1, arg2, arg3); @@ -1283,4 +1166,129 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue public Collection getForceLoadedChunks() { return parent.getForceLoadedChunks(); } + +// @Override +// public int getHighestBlockYAt(int x, int z, com.destroystokyo.paper.HeightmapType heightmap) throws UnsupportedOperationException { +// return TaskManager.IMP.sync(new Supplier() { +// @Override +// public Integer get() { +// return parent.getHighestBlockYAt(x, z, heightmap); +// } +// }); +// } +// +// @Override +// public int getEntityCount() { +// return TaskManager.IMP.sync(new RunnableVal() { +// @Override +// public void run(Integer value) { +// this.value = parent.getEntityCount(); +// } +// }); +// } +// +// @Override +// public int getTileEntityCount() { +// return TaskManager.IMP.sync(new RunnableVal() { +// @Override +// public void run(Integer value) { +// this.value = parent.getTileEntityCount(); +// } +// }); +// } +// +// @Override +// public int getTickableTileEntityCount() { +// return TaskManager.IMP.sync(new RunnableVal() { +// @Override +// public void run(Integer value) { +// this.value = parent.getTickableTileEntityCount(); +// } +// }); +// } +// +// @Override +// public int getChunkCount() { +// return TaskManager.IMP.sync(new RunnableVal() { +// @Override +// public void run(Integer value) { +// this.value = parent.getChunkCount(); +// } +// }); +// } +// +// @Override +// public int getPlayerCount() { +// return TaskManager.IMP.sync(new RunnableVal() { +// @Override +// public void run(Integer value) { +// this.value = parent.getPlayerCount(); +// } +// }); +// } +// +// @Override +// public CompletableFuture getChunkAtAsync(int arg0, int arg1, boolean arg2) { +// return parent.getChunkAtAsync(arg0, arg1, arg2); +// } +// +// @Override +// public boolean isDayTime() { +// return parent.isDayTime(); +// } +// +// @Override +// public boolean unloadChunk(final int x, final int z, final boolean save, final boolean safe) { +// if (isChunkLoaded(x, z)) { +// return TaskManager.IMP.sync(new RunnableVal() { +// @Override +// public void run(Boolean value) { +// this.value = parent.unloadChunk(x, z, save, safe); +// } +// }); +// } +// return true; +// } +// +// @Override +// public boolean unloadChunkRequest(int x, int z, boolean safe) { +// return unloadChunk(x, z, safe); +// } +// +// @Override +// public void getChunkAtAsync(int x, int z, ChunkLoadCallback cb) { +// parent.getChunkAtAsync(x, z, cb); +// } +// +// @Override +// public void getChunkAtAsync(Location location, ChunkLoadCallback cb) { +// parent.getChunkAtAsync(location, cb); +// } +// +// @Override +// public void getChunkAtAsync(Block block, ChunkLoadCallback cb) { +// parent.getChunkAtAsync(block, cb); +// } +// +// @Override +// public Entity getEntity(UUID uuid) { +// return TaskManager.IMP.sync(() -> parent.getEntity(uuid)); +// } +// +// +// @Override +// public boolean createExplosion(Entity source, Location loc, float power, boolean setFire, boolean breakBlocks) { +// return TaskManager.IMP.sync(() -> parent.createExplosion(source, loc, power, setFire, breakBlocks)); +// } +// +// +// @Override +// public void spawnParticle(Particle particle, List receivers, Player source, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data) { +// parent.spawnParticle(particle, receivers, source, x, y, z, count, offsetX, offsetY, offsetZ, extra, data); +// } +// +// @Override +// public void spawnParticle(Particle particle, List list, Player player, double v, double v1, double v2, int i, double v3, double v4, double v5, double v6, T t, boolean b) { +// parent.spawnParticle(particle, list, player, v, v1, v2, i, v3, v4, v5, v6, t, b); +// } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java b/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java index ef9625376..02ccee892 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java @@ -9,7 +9,6 @@ import com.boydti.fawe.regions.general.plot.PlotSquaredFeature; import com.boydti.fawe.util.*; import com.boydti.fawe.util.chat.ChatManager; import com.boydti.fawe.util.chat.PlainChatManager; -import com.boydti.fawe.util.cui.CUI; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.factory.DefaultTransformParser; import com.sk89q.worldedit.extension.platform.Actor; @@ -199,25 +198,6 @@ public class Fawe { public void onDisable() { } - public CUI getCUI(Actor actor) { - FawePlayer fp = FawePlayer.wrap(actor); - CUI cui = fp.getMeta("CUI"); - if (cui == null) { - cui = Fawe.imp().getCUI(fp); - if (cui != null) { - synchronized (fp) { - CUI tmp = fp.getMeta("CUI"); - if (tmp == null) { - fp.setMeta("CUI", cui); - } else { - cui = tmp; - } - } - } - } - return cui; - } - public ChatManager getChatManager() { return chatManager; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/IFawe.java b/worldedit-core/src/main/java/com/boydti/fawe/IFawe.java index ecba46a2f..af59b4096 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/IFawe.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/IFawe.java @@ -5,7 +5,6 @@ import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.regions.FaweMaskManager; import com.boydti.fawe.util.TaskManager; -import com.boydti.fawe.util.cui.CUI; import com.boydti.fawe.util.image.ImageViewer; import com.sk89q.worldedit.world.World; @@ -36,8 +35,6 @@ public interface IFawe { void startMetrics(); - default CUI getCUI(FawePlayer player) { return null; } - default ImageViewer getImageViewer(FawePlayer player) { return null; } default void registerPacketListener() {} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/cui/CUI.java b/worldedit-core/src/main/java/com/boydti/fawe/util/cui/CUI.java deleted file mode 100644 index 540f6a455..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/cui/CUI.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.boydti.fawe.util.cui; - -import com.boydti.fawe.object.FawePlayer; -import com.sk89q.worldedit.internal.cui.CUIEvent; - -public abstract class CUI { - private final FawePlayer player; - - public CUI(FawePlayer player) { - this.player = player; - } - - public FawePlayer getPlayer() { - return player; - } - - public abstract void dispatchCUIEvent(CUIEvent event); -} diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/CompressedCompoundTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/CompressedCompoundTag.java index 6ce8b20f1..a65cbb029 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/CompressedCompoundTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/CompressedCompoundTag.java @@ -2,7 +2,6 @@ package com.sk89q.jnbt; import java.io.DataInputStream; import java.io.IOException; -import java.io.InputStream; import java.util.HashMap; import java.util.Map; 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 3517bb2f7..9cbae5aa6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -33,7 +33,6 @@ import com.boydti.fawe.object.clipboard.MultiClipboardHolder; import com.boydti.fawe.object.collection.SparseBitSet; import com.boydti.fawe.object.extent.ResettableExtent; import com.boydti.fawe.util.*; -import com.boydti.fawe.util.cui.CUI; import com.boydti.fawe.wrappers.WorldWrapper; import com.sk89q.jchronic.Chronic; import com.sk89q.jchronic.Options; @@ -1209,9 +1208,8 @@ public class LocalSession implements TextureHolder { if (hasCUISupport) { actor.dispatchCUIEvent(event); - } else if (actor.isPlayer()) { - CUI cui = Fawe.get().getCUI(actor); - if (cui != null) cui.dispatchCUIEvent(event); + } else if (useServerCUI) { + updateServerCUI(actor); } } From 35fd159e79ead572813cdf0cee28bc92340a7caa Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Thu, 25 Apr 2019 20:32:27 +1000 Subject: [PATCH 02/54] WIP rewrite of NMS pipeline --- .../fawe/bukkit/v1_13/beta/CachedChunk.java | 29 ++++ .../fawe/bukkit/v1_13/beta/CharBlocks.java | 5 + .../fawe/bukkit/v1_13/beta/CharGetBlocks.java | 7 + .../fawe/bukkit/v1_13/beta/CharSetBlocks.java | 14 ++ .../fawe/bukkit/v1_13/beta/IBlocks.java | 5 + .../boydti/fawe/bukkit/v1_13/beta/IChunk.java | 20 +++ .../fawe/bukkit/v1_13/beta/IGetBlocks.java | 4 + .../fawe/bukkit/v1_13/beta/ISetBlocks.java | 4 + .../bukkit/v1_13/beta/RegionCachedChunk.java | 9 ++ .../bukkit/v1_13/beta/ReusableExtent.java | 150 ++++++++++++++++++ .../bukkit/v1_13/beta/holder/ChunkHolder.java | 13 ++ .../bukkit/v1_13/beta/holder/SetChunk.java | 7 + .../java/com/boydti/fawe/config/Settings.java | 2 +- .../com/boydti/fawe/jnbt/anvil/MCAChunk.java | 3 - 14 files changed, 268 insertions(+), 4 deletions(-) create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CachedChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharBlocks.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharGetBlocks.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharSetBlocks.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IBlocks.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IGetBlocks.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ISetBlocks.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/RegionCachedChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ReusableExtent.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ChunkHolder.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SetChunk.java diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CachedChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CachedChunk.java new file mode 100644 index 000000000..3a2df1006 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CachedChunk.java @@ -0,0 +1,29 @@ +package com.boydti.fawe.bukkit.v1_13.beta; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import net.minecraft.server.v1_13_R2.Chunk; +import net.minecraft.server.v1_13_R2.ChunkSection; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.UUID; + +public class CachedChunk { + private GetBlocks get; + private SetBlocks set; + + public CachedChunk(ReusableExtent parent) { + + } + + + public void init(int X, int Z) { + + } + + +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharBlocks.java new file mode 100644 index 000000000..b1a202380 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharBlocks.java @@ -0,0 +1,5 @@ +package com.boydti.fawe.bukkit.v1_13.beta; + +public class CharBlocks implements IBlocks { + protected char[][] blocks; +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharGetBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharGetBlocks.java new file mode 100644 index 000000000..62a05b707 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharGetBlocks.java @@ -0,0 +1,7 @@ +package com.boydti.fawe.bukkit.v1_13.beta; + +import net.minecraft.server.v1_13_R2.ChunkSection; + +public class CharGetBlocks extends CharBlocks implements IGetBlocks { + private ChunkSection[] sections; +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharSetBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharSetBlocks.java new file mode 100644 index 000000000..66c2f4197 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharSetBlocks.java @@ -0,0 +1,14 @@ +package com.boydti.fawe.bukkit.v1_13.beta; + +import com.sk89q.jnbt.CompoundTag; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.UUID; + +public class CharSetBlocks extends CharBlocks implements ISetBlocks { + private byte[] biomes; + private HashMap tiles; + private HashSet entities; + private HashSet entityRemoves; +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IBlocks.java new file mode 100644 index 000000000..187a914d3 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IBlocks.java @@ -0,0 +1,5 @@ +package com.boydti.fawe.bukkit.v1_13.beta; + +public interface IBlocks { + +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IChunk.java new file mode 100644 index 000000000..b9372b0d2 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IChunk.java @@ -0,0 +1,20 @@ +package com.boydti.fawe.bukkit.v1_13.beta; + +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +public interface IChunk { + /* set */ + void setBiome(int x, int z, BiomeType biome); + + void setBlock(int x, int y, int z, BlockStateHolder holder); + + /* get */ + BiomeType getBiome(int x, int z); + + BlockState getBlock(int x, int y, int z); + + BaseBlock getFullBlock(int x, int y, int z); +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IGetBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IGetBlocks.java new file mode 100644 index 000000000..446a6a4d6 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IGetBlocks.java @@ -0,0 +1,4 @@ +package com.boydti.fawe.bukkit.v1_13.beta; + +public interface IGetBlocks extends IBlocks { +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ISetBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ISetBlocks.java new file mode 100644 index 000000000..90f45b8c8 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ISetBlocks.java @@ -0,0 +1,4 @@ +package com.boydti.fawe.bukkit.v1_13.beta; + +public interface ISetBlocks extends IBlocks { +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/RegionCachedChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/RegionCachedChunk.java new file mode 100644 index 000000000..7984a0b80 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/RegionCachedChunk.java @@ -0,0 +1,9 @@ +package com.boydti.fawe.bukkit.v1_13.beta; + +import net.minecraft.server.v1_13_R2.Chunk; + +public class RegionCachedChunk extends CachedChunk { + public RegionCachedChunk(Chunk chunk) { + super(chunk); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ReusableExtent.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ReusableExtent.java new file mode 100644 index 000000000..e095eb27c --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ReusableExtent.java @@ -0,0 +1,150 @@ +package com.boydti.fawe.bukkit.v1_13.beta; + +import com.boydti.fawe.Fawe; +import com.boydti.fawe.jnbt.anvil.MCAFilter; +import com.boydti.fawe.util.TaskManager; +import com.boydti.fawe.wrappers.WorldWrapper; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import net.minecraft.server.v1_13_R2.WorldServer; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; + +import java.util.Iterator; +import java.util.Set; +import java.util.concurrent.ForkJoinPool; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class ReusableExtent { + private WorldWrapper wrapped; + private World world; + private org.bukkit.World bukkitWorld; + private WorldServer nmsWorld; + + private void reset() { + if (world != null) { + wrapped = null; + world = null; + bukkitWorld = null; + nmsWorld = null; + lowMemory = false; + } + } + + public void init(World world) { + reset(); + checkNotNull(world); + if (world instanceof EditSession) { + world = ((EditSession) world).getWorld(); + } + checkNotNull(world); + if (world instanceof WorldWrapper) { + this.wrapped = (WorldWrapper) world; + world = WorldWrapper.unwrap(world); + } else { + this.world = WorldWrapper.wrap(world); + } + this.world = world; + if (world instanceof BukkitWorld) { + this.bukkitWorld = ((BukkitWorld) world).getWorld(); + } else { + this.bukkitWorld = Bukkit.getWorld(world.getName()); + } + checkNotNull(this.bukkitWorld); + CraftWorld craftWorld = ((CraftWorld) bukkitWorld); + this.nmsWorld = craftWorld.getHandle(); + // Save world + } + + private boolean lowMemory; + + public void setLowMemory() { + lowMemory = true; + // set queue state to active + // trim cached chunks + } + + private CachedChunk getCachedChunk(int x, int z) { + // check last + // otherwise create/load + // get cached chunk from bukkit + // otherwise load + // TODO load async (with paper) + if (lowMemory) { + if (Fawe.isMainThread()) { + // submit other chunks + next(); + } else { + // wait until empty + } + } + } + + void setBlock(int x, int y, int z, BlockStateHolder holder) { + CachedChunk chunk = getCachedChunk(x, z); + chunk.setBlock(x & 15, y, z & 15, holder); + } + + void setBiome(int x, int z, BiomeType biome) { + CachedChunk chunk = getCachedChunk(x, z); + chunk.setBiome(x, z, biome); + } + + BlockState getBlock(int x, int y, int z) { + CachedChunk chunk = getCachedChunk(x, z); + return chunk.getBlock(x & 15, y, z & 15); + } + + BiomeType getBiome(int x, int z) { + CachedChunk chunk = getCachedChunk(x, z); + return chunk.getBiome(x, z); + } + + public void apply(Region region, MCAFilter filter) { // TODO not MCAFilter, but another similar class + // TODO iterate by mca file + Set chunks = region.getChunks(); + Iterator chunksIter = chunks.iterator(); + ForkJoinPool pool = TaskManager.IMP.getPublicForkJoinPool(); + for (int i = 0; i < Runtime.getRuntime().availableProcessors(); i++) { + pool.submit(new Runnable() { + @Override + public void run() { + while (true) { + BlockVector2 pos; + synchronized (chunksIter) { + if (!chunksIter.hasNext()) return; + pos = chunksIter.next(); + } + int cx = pos.getX(); + int cz = pos.getZ(); + CachedChunk chunk = getCachedChunk(cx, cz); + try { + if (!filter.appliesChunk(cx, cz)) { + continue; + } + T value = filter.get(); + chunk = filter.applyChunk(chunk, value); + + if (chunk == null) continue; + + // TODO if region contains all parts + chunk.filter(filter); + // else + chunk.filter(region, filter); + } finally { + // TODO submit chunk + } + } + } + }); + } + } +} \ No newline at end of file diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ChunkHolder.java new file mode 100644 index 000000000..cba2c2e3a --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ChunkHolder.java @@ -0,0 +1,13 @@ +package com.boydti.fawe.bukkit.v1_13.beta.holder; + +import com.boydti.fawe.bukkit.v1_13.beta.IChunk; + +public class ChunkHolder implements IChunk { + private ChunkHolder implementation; + + public ChunkHolder() { + + } + + public ChunkHolder(IChunkH) +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SetChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SetChunk.java new file mode 100644 index 000000000..6d58ef8c4 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SetChunk.java @@ -0,0 +1,7 @@ +package com.boydti.fawe.bukkit.v1_13.beta.holder; + +import com.boydti.fawe.bukkit.v1_13.beta.IChunk; + +public class SetChunk extends ChunkHolder { + +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/config/Settings.java b/worldedit-core/src/main/java/com/boydti/fawe/config/Settings.java index f66b12a69..cedb96acf 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/config/Settings.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/config/Settings.java @@ -257,8 +257,8 @@ public class Settings extends Config { public static class QUEUE { @Comment({ "This should equal the number of processors you have", - " - Set this to 1 if you need reliable `/timings`" }) + @Final public int PARALLEL_THREADS = Math.max(1, Runtime.getRuntime().availableProcessors()); @Create public static PROGRESS PROGRESS; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java index 3e4f4262d..c382792e7 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java @@ -78,9 +78,6 @@ public class MCAChunk extends FaweChunk { } public void write(NBTOutputStream nbtOut) throws IOException { - - - nbtOut.writeNamedTagName("", NBTConstants.TYPE_COMPOUND); nbtOut.writeLazyCompoundTag("Level", out -> { out.writeNamedTag("V", (byte) 1); From 6adf0e6435a341a21685cce8fa0a3427326389e0 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Sat, 27 Apr 2019 11:15:08 +1000 Subject: [PATCH 03/54] some structure --- .../fawe/bukkit/v1_13/IQueueExtent.java | 42 +++++ .../fawe/bukkit/v1_13/beta/CachedChunk.java | 29 ---- .../fawe/bukkit/v1_13/beta/CharGetBlocks.java | 18 +++ .../v1_13/beta/DelegateQueueExtent.java | 7 + .../boydti/fawe/bukkit/v1_13/beta/Filter.java | 50 ++++++ .../bukkit/v1_13/beta/FullCharBlocks.java | 6 + .../boydti/fawe/bukkit/v1_13/beta/IChunk.java | 18 ++- .../fawe/bukkit/v1_13/beta/IGetBlocks.java | 9 ++ .../fawe/bukkit/v1_13/beta/ISetBlocks.java | 6 + .../fawe/bukkit/v1_13/beta/QueueHandler.java | 83 ++++++++++ .../bukkit/v1_13/beta/RegionCachedChunk.java | 9 -- .../bukkit/v1_13/beta/ReusableExtent.java | 150 ------------------ .../v1_13/beta/SingleThreadQueueExtent.java | 104 ++++++++++++ .../beta/bukkit/BukkitReusableExtent.java | 30 ++++ .../bukkit/v1_13/beta/holder/ChunkHolder.java | 20 ++- .../v1_13/beta/holder/DelegateChunk.java | 19 +++ .../v1_13/beta/holder/FinalizedChunk.java | 16 ++ .../bukkit/v1_13/beta/holder/FullChunk.java | 44 +++++ .../bukkit/v1_13/beta/holder/GetChunk.java | 34 ++++ .../v1_13/beta/holder/IDelegateChunk.java | 76 +++++++++ .../bukkit/v1_13/beta/holder/InitChunk.java | 47 ++++++ .../v1_13/beta/holder/ReferenceChunk.java | 23 +++ .../bukkit/v1_13/beta/holder/SetChunk.java | 25 ++- .../bukkit/v1_13/beta/holder/SoftChunk.java | 18 +++ .../bukkit/v1_13/beta/holder/WeakChunk.java | 17 ++ .../main/java/com/boydti/fawe/FaweCache.java | 78 +++++++++ 26 files changed, 781 insertions(+), 197 deletions(-) create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/IQueueExtent.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CachedChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/DelegateQueueExtent.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/Filter.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/FullCharBlocks.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/QueueHandler.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/RegionCachedChunk.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ReusableExtent.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/SingleThreadQueueExtent.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/bukkit/BukkitReusableExtent.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/DelegateChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FinalizedChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FullChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/GetChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/IDelegateChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/InitChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ReferenceChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SoftChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/WeakChunk.java diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/IQueueExtent.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/IQueueExtent.java new file mode 100644 index 000000000..7a0148ea3 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/IQueueExtent.java @@ -0,0 +1,42 @@ +package com.boydti.fawe.bukkit.v1_13; + +import com.boydti.fawe.bukkit.v1_13.beta.IChunk; +import com.boydti.fawe.bukkit.v1_13.beta.holder.ChunkHolder; +import com.boydti.fawe.bukkit.v1_13.beta.holder.IDelegateChunk; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +public interface IQueueExtent { + void init(World world); + + IChunk getCachedChunk(int X, int Z); + + default boolean setBlock(int x, int y, int z, BlockStateHolder state) { + IChunk chunk = getCachedChunk(x >> 4, z >> 4); + return chunk.setBlock(x & 15, y, z & 15, state); + } + + default boolean setBiome(int x, int y, int z, BiomeType biome) { + IChunk chunk = getCachedChunk(x >> 4, z >> 4); + return chunk.setBiome(x & 15, y, z & 15, biome); + } + + default BlockState getBlock(int x, int y, int z) { + IChunk chunk = getCachedChunk(x >> 4, z >> 4); + return chunk.getBlock(x & 15, y, z & 15); + } + + default BiomeType getBiome(int x, int z) { + IChunk chunk = getCachedChunk(x >> 4, z >> 4); + return chunk.getBiome(x & 15, z & 15); + } + + // Return ChunkHolder + ChunkHolder create(boolean full); + + // Region restrictions + IDelegateChunk wrap(IChunk root); +} \ No newline at end of file diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CachedChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CachedChunk.java deleted file mode 100644 index 3a2df1006..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CachedChunk.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13.beta; - -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; -import net.minecraft.server.v1_13_R2.Chunk; -import net.minecraft.server.v1_13_R2.ChunkSection; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.UUID; - -public class CachedChunk { - private GetBlocks get; - private SetBlocks set; - - public CachedChunk(ReusableExtent parent) { - - } - - - public void init(int X, int Z) { - - } - - -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharGetBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharGetBlocks.java index 62a05b707..c33ef3100 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharGetBlocks.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharGetBlocks.java @@ -1,7 +1,25 @@ package com.boydti.fawe.bukkit.v1_13.beta; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; import net.minecraft.server.v1_13_R2.ChunkSection; public class CharGetBlocks extends CharBlocks implements IGetBlocks { private ChunkSection[] sections; + + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + return null; + } + + @Override + public BiomeType getBiome(int x, int z) { + return null; + } + + @Override + public BlockState getBlock(int x, int y, int z) { + return null; + } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/DelegateQueueExtent.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/DelegateQueueExtent.java new file mode 100644 index 000000000..72ac950cf --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/DelegateQueueExtent.java @@ -0,0 +1,7 @@ +package com.boydti.fawe.bukkit.v1_13.beta; + +import com.boydti.fawe.bukkit.v1_13.IQueueExtent; + +public interface IDelegateQueueExtent { + IQueueExtent getParent(); +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/Filter.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/Filter.java new file mode 100644 index 000000000..e2bb721c1 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/Filter.java @@ -0,0 +1,50 @@ +package com.boydti.fawe.bukkit.v1_13.beta; + +import com.sk89q.worldedit.world.block.BaseBlock; + +public class Filter { + /** + * Check whether a chunk should be read + * + * @param cx + * @param cz + * @return + */ + public boolean appliesChunk(int cx, int cz) { + return true; + } + + /** + * Do something with the IChunk
+ * - Return null if you don't want to filter blocks
+ * - Return the chunk if you do want to filter blocks
+ * + * @param chunk + * @return + */ + public IChunk applyChunk(IChunk chunk) { + return chunk; + } + + /** + * Make changes to the block here
+ * - e.g. block.setId(...)
+ * - Note: Performance is critical here
+ * + * @param x + * @param y + * @param z + * @param block + */ + public void applyBlock(int x, int y, int z, BaseBlock block) { + } + + /** + * Do something with the IChunk after block filtering
+ * + * @param chunk + * @return + */ + public void finishChunk(IChunk chunk) { + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/FullCharBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/FullCharBlocks.java new file mode 100644 index 000000000..e07e6e5b0 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/FullCharBlocks.java @@ -0,0 +1,6 @@ +package com.boydti.fawe.bukkit.v1_13.beta; + +public class FullCharBlocks implements IBlocks { + public final boolean[] hasSections = new boolean[16]; + public final char[] blocks = new char[65536]; +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IChunk.java index b9372b0d2..21452e0b0 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IChunk.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IChunk.java @@ -7,9 +7,9 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; public interface IChunk { /* set */ - void setBiome(int x, int z, BiomeType biome); + boolean setBiome(int x, int y, int z, BiomeType biome); - void setBlock(int x, int y, int z, BlockStateHolder holder); + boolean setBlock(int x, int y, int z, BlockStateHolder holder); /* get */ BiomeType getBiome(int x, int z); @@ -17,4 +17,18 @@ public interface IChunk { BlockState getBlock(int x, int y, int z); BaseBlock getFullBlock(int x, int y, int z); + + void init(SingleThreadQueueExtent extent, int X, int Z); + + int getX(); + + int getZ(); + + void apply(); + + default IChunk getRoot() { + return this; + } + + void filter(Filter filter); } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IGetBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IGetBlocks.java index 446a6a4d6..f0c1346d4 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IGetBlocks.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IGetBlocks.java @@ -1,4 +1,13 @@ package com.boydti.fawe.bukkit.v1_13.beta; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; + public interface IGetBlocks extends IBlocks { + BaseBlock getFullBlock(int x, int y, int z); + + BiomeType getBiome(int x, int z); + + BlockState getBlock(int x, int y, int z); } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ISetBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ISetBlocks.java index 90f45b8c8..6793775b1 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ISetBlocks.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ISetBlocks.java @@ -1,4 +1,10 @@ package com.boydti.fawe.bukkit.v1_13.beta; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockStateHolder; + public interface ISetBlocks extends IBlocks { + void setBiome(int x, int z, BiomeType biome); + + void setBlock(int x, int y, int z, BlockStateHolder holder); } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/QueueHandler.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/QueueHandler.java new file mode 100644 index 000000000..9461531ab --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/QueueHandler.java @@ -0,0 +1,83 @@ +package com.boydti.fawe.bukkit.v1_13.beta; + +import com.boydti.fawe.config.Settings; +import com.boydti.fawe.util.MathMan; +import com.boydti.fawe.util.TaskManager; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.regions.Region; + +import java.util.Iterator; +import java.util.Set; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; + +public class QueueHandler { + private SingleThreadQueueExtent mainExtent; + private SingleThreadQueueExtent[] pool; + + + + public static void apply(Region region, Filter filter) { // TODO not MCAFilter, but another similar class + // The chunks positions to iterate over + Set chunks = region.getChunks(); + Iterator chunksIter = chunks.iterator(); + + // Get a pool, to operate on the chunks in parallel + ForkJoinPool pool = TaskManager.IMP.getPublicForkJoinPool(); + int size = Math.min(chunks.size(), Settings.IMP.QUEUE.PARALLEL_THREADS); + ForkJoinTask[] tasks = new ForkJoinTask[size]; + + for (int i = 0; i < size; i++) { + tasks[i] = pool.submit(new Runnable() { + @Override + public void run() { + // Create a chunk that we will reuse/reset for each operation + IChunk chunk = create(true); + + while (true) { + // Get the next chunk pos + BlockVector2 pos; + synchronized (chunksIter) { + if (!chunksIter.hasNext()) return; + pos = chunksIter.next(); + } + int X = pos.getX(); + int Z = pos.getZ(); + long pair = MathMan.pairInt(X, Z); + + // Initialize + chunk.init(SingleThreadQueueExtent.this, X, Z); + + { // Start set + lastPair = pair; + lastChunk = chunk; + } + try { + if (!filter.appliesChunk(X, Z)) { + continue; + } + chunk = filter.applyChunk(chunk); + + if (chunk == null) continue; + + chunk.filter(filter); + + filter.finishChunk(chunk); + + chunk.apply(); + } finally + { // End set + lastPair = Long.MAX_VALUE; + lastChunk = null; + } + } + } + }); + } + + // Join the tasks + for (ForkJoinTask task : tasks) { + task.join(); + } + } +} \ No newline at end of file diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/RegionCachedChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/RegionCachedChunk.java deleted file mode 100644 index 7984a0b80..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/RegionCachedChunk.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13.beta; - -import net.minecraft.server.v1_13_R2.Chunk; - -public class RegionCachedChunk extends CachedChunk { - public RegionCachedChunk(Chunk chunk) { - super(chunk); - } -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ReusableExtent.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ReusableExtent.java deleted file mode 100644 index e095eb27c..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ReusableExtent.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13.beta; - -import com.boydti.fawe.Fawe; -import com.boydti.fawe.jnbt.anvil.MCAFilter; -import com.boydti.fawe.util.TaskManager; -import com.boydti.fawe.wrappers.WorldWrapper; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.bukkit.BukkitWorld; -import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.world.World; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; -import net.minecraft.server.v1_13_R2.WorldServer; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; - -import java.util.Iterator; -import java.util.Set; -import java.util.concurrent.ForkJoinPool; - -import static com.google.common.base.Preconditions.checkNotNull; - -public class ReusableExtent { - private WorldWrapper wrapped; - private World world; - private org.bukkit.World bukkitWorld; - private WorldServer nmsWorld; - - private void reset() { - if (world != null) { - wrapped = null; - world = null; - bukkitWorld = null; - nmsWorld = null; - lowMemory = false; - } - } - - public void init(World world) { - reset(); - checkNotNull(world); - if (world instanceof EditSession) { - world = ((EditSession) world).getWorld(); - } - checkNotNull(world); - if (world instanceof WorldWrapper) { - this.wrapped = (WorldWrapper) world; - world = WorldWrapper.unwrap(world); - } else { - this.world = WorldWrapper.wrap(world); - } - this.world = world; - if (world instanceof BukkitWorld) { - this.bukkitWorld = ((BukkitWorld) world).getWorld(); - } else { - this.bukkitWorld = Bukkit.getWorld(world.getName()); - } - checkNotNull(this.bukkitWorld); - CraftWorld craftWorld = ((CraftWorld) bukkitWorld); - this.nmsWorld = craftWorld.getHandle(); - // Save world - } - - private boolean lowMemory; - - public void setLowMemory() { - lowMemory = true; - // set queue state to active - // trim cached chunks - } - - private CachedChunk getCachedChunk(int x, int z) { - // check last - // otherwise create/load - // get cached chunk from bukkit - // otherwise load - // TODO load async (with paper) - if (lowMemory) { - if (Fawe.isMainThread()) { - // submit other chunks - next(); - } else { - // wait until empty - } - } - } - - void setBlock(int x, int y, int z, BlockStateHolder holder) { - CachedChunk chunk = getCachedChunk(x, z); - chunk.setBlock(x & 15, y, z & 15, holder); - } - - void setBiome(int x, int z, BiomeType biome) { - CachedChunk chunk = getCachedChunk(x, z); - chunk.setBiome(x, z, biome); - } - - BlockState getBlock(int x, int y, int z) { - CachedChunk chunk = getCachedChunk(x, z); - return chunk.getBlock(x & 15, y, z & 15); - } - - BiomeType getBiome(int x, int z) { - CachedChunk chunk = getCachedChunk(x, z); - return chunk.getBiome(x, z); - } - - public void apply(Region region, MCAFilter filter) { // TODO not MCAFilter, but another similar class - // TODO iterate by mca file - Set chunks = region.getChunks(); - Iterator chunksIter = chunks.iterator(); - ForkJoinPool pool = TaskManager.IMP.getPublicForkJoinPool(); - for (int i = 0; i < Runtime.getRuntime().availableProcessors(); i++) { - pool.submit(new Runnable() { - @Override - public void run() { - while (true) { - BlockVector2 pos; - synchronized (chunksIter) { - if (!chunksIter.hasNext()) return; - pos = chunksIter.next(); - } - int cx = pos.getX(); - int cz = pos.getZ(); - CachedChunk chunk = getCachedChunk(cx, cz); - try { - if (!filter.appliesChunk(cx, cz)) { - continue; - } - T value = filter.get(); - chunk = filter.applyChunk(chunk, value); - - if (chunk == null) continue; - - // TODO if region contains all parts - chunk.filter(filter); - // else - chunk.filter(region, filter); - } finally { - // TODO submit chunk - } - } - } - }); - } - } -} \ No newline at end of file diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/SingleThreadQueueExtent.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/SingleThreadQueueExtent.java new file mode 100644 index 000000000..53f1984e4 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/SingleThreadQueueExtent.java @@ -0,0 +1,104 @@ +package com.boydti.fawe.bukkit.v1_13.beta; + +import com.boydti.fawe.bukkit.v1_13.IQueueExtent; +import com.boydti.fawe.bukkit.v1_13.beta.holder.ChunkHolder; +import com.boydti.fawe.bukkit.v1_13.beta.holder.IDelegateChunk; +import com.boydti.fawe.bukkit.v1_13.beta.holder.ReferenceChunk; +import com.boydti.fawe.config.Settings; +import com.boydti.fawe.util.MathMan; +import com.boydti.fawe.util.MemUtil; +import com.boydti.fawe.wrappers.WorldWrapper; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.world.World; +import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; + +import static com.google.common.base.Preconditions.checkNotNull; + +public abstract class SingleThreadQueueExtent implements IQueueExtent { + private WorldWrapper wrapped; + private World world; + + public World getWorld() { + return world; + } + + public WorldWrapper getWrappedWorld() { + return wrapped; + } + + private void reset() { + wrapped = null; + world = null; + chunks.clear(); + lastChunk = null; + lastPair = Long.MAX_VALUE; + } + + public synchronized void init(World world) { + if (world != null) { + reset(); + } + checkNotNull(world); + if (world instanceof EditSession) { + world = ((EditSession) world).getWorld(); + } + checkNotNull(world); + if (world instanceof WorldWrapper) { + this.wrapped = (WorldWrapper) world; + world = WorldWrapper.unwrap(world); + } else { + this.wrapped = WorldWrapper.wrap(world); + } + this.world = world; + } + + private IChunk lastChunk; + private long lastPair = Long.MAX_VALUE; + private final Long2ObjectLinkedOpenHashMap chunks = new Long2ObjectLinkedOpenHashMap<>(); + + private final IDelegateChunk getCachedChunk2(long pair) { + IDelegateChunk chunk = chunks.get(pair); + if (chunk instanceof ReferenceChunk) { + chunk = (ReferenceChunk) (chunk).getParent(); + } + if (chunk != null) { + lastPair = pair; + lastChunk = chunk; + } + return chunk; + } + + public final IChunk getCachedChunk(int X, int Z) { + long pair = MathMan.pairInt(X, Z); + if (pair == lastPair) { + return lastChunk; + } + + IDelegateChunk chunk = getCachedChunk2(pair); + if (chunk != null) return chunk; + + chunk = getCachedChunk2(pair); + if (chunk != null) return chunk; + + int size = chunks.size(); + if (size > Settings.IMP.QUEUE.TARGET_SIZE || MemUtil.isMemoryLimited()) { + if (size > Settings.IMP.QUEUE.PARALLEL_THREADS * 2 + 16) { + chunk = chunks.removeFirst(); + chunk.apply(); + chunk = (IDelegateChunk) chunk.findParent(ChunkHolder.class); + chunk.init(this, X, Z); + } else { + chunk = create(false); + } + } else { + chunk = create(false); + } + chunk = wrap(chunk); + + chunks.put(pair, chunk); + lastPair = pair; + lastChunk = chunk; + + return chunk; + } +} \ No newline at end of file diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/bukkit/BukkitReusableExtent.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/bukkit/BukkitReusableExtent.java new file mode 100644 index 000000000..90f34b5dd --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/bukkit/BukkitReusableExtent.java @@ -0,0 +1,30 @@ +package com.boydti.fawe.bukkit.v1_13.beta.bukkit; + +import com.boydti.fawe.bukkit.v1_13.beta.SingleThreadQueueExtent; +import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.world.World; +import net.minecraft.server.v1_13_R2.WorldServer; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class BukkitReusableExtent extends SingleThreadQueueExtent { + private org.bukkit.World bukkitWorld; + private WorldServer nmsWorld; + + public void init(World world) { + super.init(world); + world = getWorld(); + + if (world instanceof BukkitWorld) { + this.bukkitWorld = ((BukkitWorld) world).getWorld(); + } else { + this.bukkitWorld = Bukkit.getWorld(world.getName()); + } + checkNotNull(this.bukkitWorld); + CraftWorld craftWorld = ((CraftWorld) bukkitWorld); + this.nmsWorld = craftWorld.getHandle(); + } + +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ChunkHolder.java index cba2c2e3a..cf4ebf092 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ChunkHolder.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ChunkHolder.java @@ -1,13 +1,21 @@ package com.boydti.fawe.bukkit.v1_13.beta.holder; -import com.boydti.fawe.bukkit.v1_13.beta.IChunk; - -public class ChunkHolder implements IChunk { - private ChunkHolder implementation; +import com.boydti.fawe.bukkit.v1_13.beta.CharGetBlocks; +import com.boydti.fawe.bukkit.v1_13.beta.CharSetBlocks; +import com.boydti.fawe.bukkit.v1_13.beta.IGetBlocks; +import com.boydti.fawe.bukkit.v1_13.beta.ISetBlocks; +public class ChunkHolder extends DelegateChunk { public ChunkHolder() { - + super(new InitChunk(null)); + getParent().setParent(this); } - public ChunkHolder(IChunkH) + protected final IGetBlocks get() { + return new CharGetBlocks(); + } + + protected final ISetBlocks set() { + return new CharSetBlocks(); + } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/DelegateChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/DelegateChunk.java new file mode 100644 index 000000000..19ddffbc0 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/DelegateChunk.java @@ -0,0 +1,19 @@ +package com.boydti.fawe.bukkit.v1_13.beta.holder; + +import com.boydti.fawe.bukkit.v1_13.beta.IChunk; + +public class DelegateChunk implements IDelegateChunk { + private T parent; + + public DelegateChunk(T parent) { + this.parent = parent; + } + + public final T getParent() { + return parent; + } + + public final void setParent(T parent) { + this.parent = parent; + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FinalizedChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FinalizedChunk.java new file mode 100644 index 000000000..bd2e9092f --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FinalizedChunk.java @@ -0,0 +1,16 @@ +package com.boydti.fawe.bukkit.v1_13.beta.holder; + +import com.boydti.fawe.bukkit.v1_13.beta.IChunk; + +public class FinalizedChunk extends DelegateChunk { + public FinalizedChunk(IChunk parent) { + super(parent); + } + + @Override + protected void finalize() throws Throwable { + apply(); + setParent(null); + super.finalize(); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FullChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FullChunk.java new file mode 100644 index 000000000..c5c7b3272 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FullChunk.java @@ -0,0 +1,44 @@ +package com.boydti.fawe.bukkit.v1_13.beta.holder; + +import com.boydti.fawe.bukkit.v1_13.beta.IGetBlocks; +import com.boydti.fawe.bukkit.v1_13.beta.ISetBlocks; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +public class FullChunk extends DelegateChunk { + private final ISetBlocks set; + private final IGetBlocks get; + + public FullChunk(ChunkHolder parent, IGetBlocks get, ISetBlocks set) { + super(parent); + this.set = set == null ? parent.set() : set; + this.get = get == null ? parent.get() : get; + } + + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + return get.getFullBlock(x, y, z); + } + + @Override + public BiomeType getBiome(int x, int z) { + return get.getBiome(x, z); + } + + @Override + public BlockState getBlock(int x, int y, int z) { + return get.getBlock(x, y, z); + } + + @Override + public void setBiome(int x, int z, BiomeType biome) { + set.setBiome(x, z, biome); + } + + @Override + public void setBlock(int x, int y, int z, BlockStateHolder holder) { + set.setBlock(x, y, z, holder); + } +} \ No newline at end of file diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/GetChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/GetChunk.java new file mode 100644 index 000000000..d6747c328 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/GetChunk.java @@ -0,0 +1,34 @@ +package com.boydti.fawe.bukkit.v1_13.beta.holder; + +import com.boydti.fawe.bukkit.v1_13.beta.IGetBlocks; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; + +public class GetChunk extends InitChunk { + private final IGetBlocks get; + + public GetChunk(ChunkHolder parent) { + super(parent); + this.get = parent.get(); + } + + protected void init() { + getParent().setParent(new FullChunk(getParent(), get, null)); + } + + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + return get.getFullBlock(x, y, z); + } + + @Override + public BiomeType getBiome(int x, int z) { + return get.getBiome(x, z); + } + + @Override + public BlockState getBlock(int x, int y, int z) { + return get.getBlock(x, y, z); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/IDelegateChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/IDelegateChunk.java new file mode 100644 index 000000000..e71172bc4 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/IDelegateChunk.java @@ -0,0 +1,76 @@ +package com.boydti.fawe.bukkit.v1_13.beta.holder; + +import com.boydti.fawe.bukkit.v1_13.beta.IChunk; +import com.boydti.fawe.bukkit.v1_13.beta.SingleThreadQueueExtent; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +public interface IDelegateChunk extends IChunk { + T getParent(); + + default IChunk getRoot() { + IChunk root = getParent(); + while (root instanceof IDelegateChunk) { + root = ((IDelegateChunk) root).getParent(); + } + return root; + } + + @Override + default void setBiome(int x, int z, BiomeType biome) { + getParent().setBiome(x, z, biome); + } + + @Override + default void setBlock(int x, int y, int z, BlockStateHolder holder) { + getParent().setBlock(x, y, z, holder); + } + + @Override + default BiomeType getBiome(int x, int z) { + return getParent().getBiome(x, z); + } + + @Override + default BlockState getBlock(int x, int y, int z) { + return getParent().getBlock(x, y, z); + } + + @Override + default BaseBlock getFullBlock(int x, int y, int z) { + return getParent().getFullBlock(x, y, z); + } + + @Override + default void init(SingleThreadQueueExtent extent, int X, int Z) { + getParent().init(extent, X, Z); + } + + @Override + default int getX() { + return getParent().getX(); + } + + @Override + default int getZ() { + return getParent().getZ(); + } + + @Override + default void apply() { + getParent().apply(); + } + + default IChunk findParent(Class clazz) { + IChunk root = getParent(); + if (clazz.isAssignableFrom(root.getClass())) return root; + while (root instanceof IDelegateChunk) { + root = ((IDelegateChunk) root).getParent(); + if (clazz.isAssignableFrom(root.getClass())) return root; + } + return null; + } + +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/InitChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/InitChunk.java new file mode 100644 index 000000000..d2a9599b2 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/InitChunk.java @@ -0,0 +1,47 @@ +package com.boydti.fawe.bukkit.v1_13.beta.holder; + +import com.boydti.fawe.bukkit.v1_13.beta.IChunk; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +public class InitChunk extends DelegateChunk { + public InitChunk(ChunkHolder parent) { + super(parent); + } + + protected void init() { + getParent().setParent(new SetChunk(getParent())); + } + + @Override + public void setBiome(int x, int z, BiomeType biome) { + init(); + super.setBiome(x, z, biome); + } + + @Override + public void setBlock(int x, int y, int z, BlockStateHolder holder) { + init(); + super.setBlock(x, y, z, holder); + } + + @Override + public BiomeType getBiome(int x, int z) { + init(); + return super.getBiome(x, z); + } + + @Override + public BlockState getBlock(int x, int y, int z) { + init(); + return super.getBlock(x, y, z); + } + + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + init(); + return super.getFullBlock(x, y, z); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ReferenceChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ReferenceChunk.java new file mode 100644 index 000000000..24607335a --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ReferenceChunk.java @@ -0,0 +1,23 @@ +package com.boydti.fawe.bukkit.v1_13.beta.holder; + +import com.boydti.fawe.bukkit.v1_13.beta.IChunk; + +import java.lang.ref.PhantomReference; +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; + +public abstract class ReferenceChunk implements IDelegateChunk { + private final Reference ref; + + public ReferenceChunk(IChunk parent) { + this.ref = toRef(new FinalizedChunk(parent)); + } + + protected abstract Reference toRef(FinalizedChunk parent); + + @Override + public IChunk getParent() { + FinalizedChunk finalized = ref.get(); + return finalized != null ? finalized.getParent() : null; + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SetChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SetChunk.java index 6d58ef8c4..3b34c7617 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SetChunk.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SetChunk.java @@ -1,7 +1,30 @@ package com.boydti.fawe.bukkit.v1_13.beta.holder; import com.boydti.fawe.bukkit.v1_13.beta.IChunk; +import com.boydti.fawe.bukkit.v1_13.beta.ISetBlocks; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockStateHolder; -public class SetChunk extends ChunkHolder { +public class SetChunk extends InitChunk { + private final ISetBlocks set; + + public SetChunk(ChunkHolder parent) { + super(parent); + this.set = parent.set(); + } + + protected void init() { + getParent().setParent(new FullChunk(getParent(), null, set)); + } + + @Override + public void setBiome(int x, int z, BiomeType biome) { + set.setBiome(x, z, biome); + } + + @Override + public void setBlock(int x, int y, int z, BlockStateHolder holder) { + set.setBlock(x, y, z, holder); + } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SoftChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SoftChunk.java new file mode 100644 index 000000000..5c435d7a6 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SoftChunk.java @@ -0,0 +1,18 @@ +package com.boydti.fawe.bukkit.v1_13.beta.holder; + +import com.boydti.fawe.bukkit.v1_13.beta.IChunk; + +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; + +public class SoftChunk extends ReferenceChunk { + + public SoftChunk(IChunk parent) { + super(parent); + } + + @Override + protected Reference toRef(FinalizedChunk parent) { + return new SoftReference<>(parent); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/WeakChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/WeakChunk.java new file mode 100644 index 000000000..b574ed010 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/WeakChunk.java @@ -0,0 +1,17 @@ +package com.boydti.fawe.bukkit.v1_13.beta.holder; + +import com.boydti.fawe.bukkit.v1_13.beta.IChunk; + +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; + +public class WeakChunk extends ReferenceChunk { + public WeakChunk(IChunk parent) { + super(parent); + } + + @Override + protected Reference toRef(FinalizedChunk parent) { + return new WeakReference<>(parent); + } +} 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 c3ed20bf8..bf8369411 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java @@ -1,14 +1,40 @@ package com.boydti.fawe; +import com.boydti.fawe.jnbt.anvil.BitArray4096; import com.boydti.fawe.object.collection.IterableThreadLocal; +import com.boydti.fawe.util.MathMan; import com.sk89q.jnbt.*; import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; import java.lang.reflect.Field; import java.util.*; public class FaweCache { + public static final IterableThreadLocal BLOCK_TO_PALETTE_CHAR = new IterableThreadLocal() { + @Override + public char[] init() { + char[] result = new char[BlockTypes.states.length]; + Arrays.fill(result, Character.MAX_VALUE); + return result; + } + }; + + public static final IterableThreadLocal PALETTE_TO_BLOCK_CHAR = new IterableThreadLocal() { + @Override + public char[] init() { + return new char[Character.MAX_VALUE]; + } + }; + + public static final IterableThreadLocal SECTION_BLOCKS_CHAR = new IterableThreadLocal() { + @Override + public char[] init() { + return new char[4096]; + } + }; + public static final IterableThreadLocal BLOCK_TO_PALETTE = new IterableThreadLocal() { @Override public int[] init() { @@ -179,4 +205,56 @@ public class FaweCache { if (clazz == null) clazz = EndTag.class; return new ListTag(clazz, list); } + + private static final class Palette { + + } + + public void toPalette(int layer, char[] blocks) { + int[] blockToPalette = FaweCache.BLOCK_TO_PALETTE.get(); + int[] paletteToBlock = FaweCache.PALETTE_TO_BLOCK.get(); + long[] blockstates = FaweCache.BLOCK_STATES.get(); + int[] blocksCopy = FaweCache.SECTION_BLOCKS.get(); + + int blockIndexStart = layer << 12; + int blockIndexEnd = blockIndexStart + 4096; + int num_palette = 0; + try { + for (int i = blockIndexStart, j = 0; i < blockIndexEnd; i++, j++) { + int ordinal = blocks[i]; + int palette = blockToPalette[ordinal]; + if (palette == Integer.MAX_VALUE) { + BlockState state = BlockTypes.states[ordinal]; + blockToPalette[ordinal] = palette = num_palette; + paletteToBlock[num_palette] = ordinal; + num_palette++; + } + blocksCopy[j] = palette; + } + + for (int i = 0; i < num_palette; i++) { + blockToPalette[paletteToBlock[i]] = Integer.MAX_VALUE; + } + + // BlockStates + int bitsPerEntry = MathMan.log2nlz(num_palette - 1); + int blockBitArrayEnd = (bitsPerEntry * 4096) >> 6; + if (num_palette == 1) { + // Set a value, because minecraft needs it for some reason + blockstates[0] = 0; + blockBitArrayEnd = 1; + } else { + BitArray4096 bitArray = new BitArray4096(blockstates, bitsPerEntry); + bitArray.fromRaw(blocksCopy); + } + + // num_palette + // paletteToBlock + // blockstates (range: blockBitArrayEnd) + } catch (Throwable e) { + Arrays.fill(blockToPalette, Integer.MAX_VALUE); + e.printStackTrace(); + throw e; + } + } } From 57b5be84f400258b2e00bdc8f5c53ef3be3c1fc6 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Mon, 29 Apr 2019 01:44:59 +1000 Subject: [PATCH 04/54] more structure --- .../fawe/bukkit/beta/BukkitChunkHolder.java | 46 +++ .../fawe/bukkit/beta/BukkitFullChunk.java | 37 +++ .../fawe/bukkit/beta/BukkitGetBlocks.java | 8 + .../boydti/fawe/bukkit/beta/BukkitQueue.java | 32 +++ .../fawe/bukkit/v1_13/BukkitChunk_1_13.java | 266 +++++++++--------- .../fawe/bukkit/v1_13/BukkitQueue_1_13.java | 194 ++++++------- .../fawe/bukkit/v1_13/IQueueExtent.java | 42 --- .../fawe/bukkit/v1_13/beta/CharBlocks.java | 5 - .../v1_13/beta/DelegateQueueExtent.java | 7 - .../fawe/bukkit/v1_13/beta/IBlocks.java | 5 - .../fawe/bukkit/v1_13/beta/QueueHandler.java | 83 ------ .../v1_13/beta/SingleThreadQueueExtent.java | 104 ------- .../beta/bukkit/BukkitReusableExtent.java | 30 -- .../bukkit/v1_13/beta/holder/ChunkHolder.java | 21 -- .../v1_13/beta/holder/FinalizedChunk.java | 16 -- .../bukkit/v1_13/beta/holder/FullChunk.java | 44 --- .../bukkit/v1_13/beta/holder/GetChunk.java | 34 --- .../bukkit/v1_13/beta/holder/InitChunk.java | 47 ---- .../v1_13/beta/holder/ReferenceChunk.java | 23 -- .../bukkit/v1_13/beta/holder/SetChunk.java | 30 -- .../bukkit/v1_13/beta/holder/SoftChunk.java | 18 -- .../src/main/java/com/boydti/fawe/Fawe.java | 12 +- .../main/java/com/boydti/fawe/FaweCache.java | 202 ++++++++----- .../java/com/boydti/fawe}/beta/Filter.java | 12 +- .../java/com/boydti/fawe/beta/IBlocks.java | 5 + .../java/com/boydti/fawe}/beta/IChunk.java | 12 +- .../com/boydti/fawe/beta}/IDelegateChunk.java | 39 +-- .../fawe/beta/IDelegateQueueExtent.java | 44 +++ .../com/boydti/fawe}/beta/IGetBlocks.java | 4 +- .../com/boydti/fawe/beta/IQueueExtent.java | 56 ++++ .../com/boydti/fawe}/beta/ISetBlocks.java | 6 +- .../java/com/boydti/fawe/beta/Trimable.java | 5 + .../beta/implementation/QueueHandler.java | 122 ++++++++ .../SingleThreadQueueExtent.java | 154 ++++++++++ .../beta/implementation/WorldChunkCache.java | 62 ++++ .../implementation/blocks/CharBlocks.java | 7 + .../implementation/blocks}/CharGetBlocks.java | 12 +- .../implementation/blocks}/CharSetBlocks.java | 3 +- .../blocks}/FullCharBlocks.java | 4 +- .../implementation/holder/ChunkHolder.java | 243 ++++++++++++++++ .../implementation}/holder/DelegateChunk.java | 11 +- .../implementation/holder/FinalizedChunk.java | 30 ++ .../implementation/holder/ReferenceChunk.java | 23 ++ .../beta/implementation/holder/SoftChunk.java | 19 ++ .../implementation}/holder/WeakChunk.java | 8 +- 45 files changed, 1317 insertions(+), 870 deletions(-) create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitFullChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/IQueueExtent.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharBlocks.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/DelegateQueueExtent.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IBlocks.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/QueueHandler.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/SingleThreadQueueExtent.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/bukkit/BukkitReusableExtent.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ChunkHolder.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FinalizedChunk.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FullChunk.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/GetChunk.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/InitChunk.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ReferenceChunk.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SetChunk.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SoftChunk.java rename {worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13 => worldedit-core/src/main/java/com/boydti/fawe}/beta/Filter.java (71%) create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/IBlocks.java rename {worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13 => worldedit-core/src/main/java/com/boydti/fawe}/beta/IChunk.java (72%) rename {worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder => worldedit-core/src/main/java/com/boydti/fawe/beta}/IDelegateChunk.java (51%) create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateQueueExtent.java rename {worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13 => worldedit-core/src/main/java/com/boydti/fawe}/beta/IGetBlocks.java (87%) create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java rename {worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13 => worldedit-core/src/main/java/com/boydti/fawe}/beta/ISetBlocks.java (50%) create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/Trimable.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SingleThreadQueueExtent.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/WorldChunkCache.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java rename {worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta => worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks}/CharGetBlocks.java (51%) rename {worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta => worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks}/CharSetBlocks.java (78%) rename {worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta => worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks}/FullCharBlocks.java (64%) create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java rename {worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta => worldedit-core/src/main/java/com/boydti/fawe/beta/implementation}/holder/DelegateChunk.java (50%) create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/FinalizedChunk.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ReferenceChunk.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/SoftChunk.java rename {worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta => worldedit-core/src/main/java/com/boydti/fawe/beta/implementation}/holder/WeakChunk.java (50%) diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java new file mode 100644 index 000000000..5a9fcd233 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java @@ -0,0 +1,46 @@ +package com.boydti.fawe.bukkit.beta; + +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.IGetBlocks; +import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks; +import com.boydti.fawe.beta.implementation.holder.ChunkHolder; + +public class BukkitChunkHolder extends ChunkHolder { + @Override + public void init(final BukkitQueue extent, final int X, final int Z) { + super.init(extent, X, Z); + } + + @Override + public IGetBlocks get() { + BukkitQueue extent = getExtent(); + return null; + } + + @Override + public Boolean apply() { + BukkitGetBlocks get = (BukkitGetBlocks) cachedGet(); + CharSetBlocks set = (CharSetBlocks) cachedSet(); +// - getBlocks +// - set lock +// - synchronize on chunk object +// - verify section is same object as chunk's section +// - merge with setblocks +// - set section +// - verify chunk is same +// - verify section is same +// - Otherwise repeat steps on main thread +// - set status to needs relighting +// - mark as dirty +// - skip verification if main thread + throw new UnsupportedOperationException("Not implemented"); +// return true; + } + + @Override + public void filter(final Filter filter) { + // for each block + // filter.applyBlock(block) + throw new UnsupportedOperationException("Not implemented"); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitFullChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitFullChunk.java new file mode 100644 index 000000000..27104553b --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitFullChunk.java @@ -0,0 +1,37 @@ +package com.boydti.fawe.bukkit.beta; + +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.IQueueExtent; +import com.boydti.fawe.beta.ISetBlocks; +import com.boydti.fawe.beta.implementation.holder.ChunkHolder; + +public class BukkitFullChunk extends ChunkHolder { + public BukkitFullChunk() { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public void init(IQueueExtent extent, int X, int Z) { + + } + + @Override + public Object apply() { + return null; + } + + @Override + public void filter(Filter filter) { + + } + + @Override + public Object get() { + return null; + } + + @Override + public ISetBlocks set() { + return null; + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java new file mode 100644 index 000000000..85fa55a11 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java @@ -0,0 +1,8 @@ +package com.boydti.fawe.bukkit.beta; + +import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; +import net.minecraft.server.v1_13_R2.ChunkSection; + +public class BukkitGetBlocks extends CharGetBlocks { + private ChunkSection[] sections; +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java new file mode 100644 index 000000000..b8fab4466 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java @@ -0,0 +1,32 @@ +package com.boydti.fawe.bukkit.beta; + +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.implementation.SingleThreadQueueExtent; +import com.boydti.fawe.beta.implementation.WorldChunkCache; +import com.boydti.fawe.object.collection.IterableThreadLocal; +import com.sk89q.worldedit.world.World; + +public class BukkitQueue extends SingleThreadQueueExtent { + + @Override + public synchronized void init(WorldChunkCache cache) { + World world = cache.getWorld(); + super.init(cache); + } + + private static final IterableThreadLocal FULL_CHUNKS = new IterableThreadLocal() { + @Override + public BukkitFullChunk init() { + return new BukkitFullChunk(); + } + }; + + @Override + public IChunk create(boolean full) { + if (full) { + return FULL_CHUNKS.get(); + } else { + return new BukkitChunkHolder(); + } + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitChunk_1_13.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitChunk_1_13.java index 2ccfa8b5d..4b9146f8c 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitChunk_1_13.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitChunk_1_13.java @@ -81,15 +81,15 @@ public class BukkitChunk_1_13 extends IntFaweChunk { * @param x * @param z */ - public BukkitChunk_1_13(FaweQueue parent, int x, int z) { + public BukkitChunk_1_13(final FaweQueue parent, final int x, final int z) { super(parent, x, z); } - public BukkitChunk_1_13(FaweQueue parent, int x, int z, int[][] ids, short[] count, short[] air) { + public BukkitChunk_1_13(final FaweQueue parent, final int x, final int z, final int[][] ids, final short[] count, final short[] air) { super(parent, x, z, ids, count, air); } - public void storeBiomes(BiomeBase[] biomes) { + public void storeBiomes(final BiomeBase[] biomes) { if (biomes != null) { if (this.biomes == null) { this.biomes = new BiomeType[256]; @@ -111,33 +111,33 @@ public class BukkitChunk_1_13 extends IntFaweChunk { } @Override - public int[] getIdArray(int layer) { + public int[] getIdArray(final int layer) { if (this.setBlocks[layer] == null && this.sectionPalettes != null) { - ChunkSection section = this.sectionPalettes[layer]; + final ChunkSection section = this.sectionPalettes[layer]; int[] idsArray = this.setBlocks[layer]; if (section != null && idsArray == null) { this.setBlocks[layer] = idsArray = new int[4096]; if (!section.a()) { try { - DataPaletteBlock blocks = section.getBlocks(); - DataBits bits = (DataBits) BukkitQueue_1_13.fieldBits.get(blocks); - DataPalette palette = (DataPalette) BukkitQueue_1_13.fieldPalette.get(blocks); + final DataPaletteBlock blocks = section.getBlocks(); + final DataBits bits = (DataBits) BukkitQueue_1_13.fieldBits.get(blocks); + final DataPalette palette = (DataPalette) BukkitQueue_1_13.fieldPalette.get(blocks); - long[] raw = bits.a(); - int bitsPerEntry = bits.c(); + final long[] raw = bits.a(); + final int bitsPerEntry = bits.c(); new BitArray4096(raw, bitsPerEntry).toRaw(idsArray); - IBlockData defaultBlock = (IBlockData) BukkitQueue_1_13.fieldDefaultBlock.get(blocks); + final IBlockData defaultBlock = (IBlockData) BukkitQueue_1_13.fieldDefaultBlock.get(blocks); // TODO optimize away palette.a for (int i = 0; i < 4096; i++) { IBlockData ibd = palette.a(idsArray[i]); if (ibd == null) { ibd = defaultBlock; } - int ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToInt(ibd); + final int ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToInt(ibd); idsArray[i] = BlockTypes.states[ordinal].getInternalId(); } - } catch (IllegalAccessException e) { + } catch (final IllegalAccessException e) { e.printStackTrace(); } } @@ -146,23 +146,23 @@ public class BukkitChunk_1_13 extends IntFaweChunk { return this.setBlocks[layer]; } - public boolean storeTile(TileEntity tile, BlockPosition pos) { - CompoundTag nativeTag = getParent().getTag(tile); + public boolean storeTile(final TileEntity tile, final BlockPosition pos) { + final CompoundTag nativeTag = getParent().getTag(tile); setTile(pos.getX() & 15, pos.getY(), pos.getZ() & 15, nativeTag); return true; } - public boolean storeEntity(Entity ent) throws InvocationTargetException, IllegalAccessException { + public boolean storeEntity(final Entity ent) throws InvocationTargetException, IllegalAccessException { if (ent instanceof EntityPlayer || BukkitQueue_0.getAdapter() == null) { return false; } - EntityTypes type = ent.P(); - MinecraftKey id = EntityTypes.getName(type); + final EntityTypes type = ent.P(); + final MinecraftKey id = EntityTypes.getName(type); if (id != null) { - NBTTagCompound tag = new NBTTagCompound(); + final NBTTagCompound tag = new NBTTagCompound(); ent.save(tag); // readEntityIntoTag - CompoundTag nativeTag = (CompoundTag) BukkitQueue_0.toNative(tag); - Map map = ReflectionUtils.getMap(nativeTag.getValue()); + final CompoundTag nativeTag = (CompoundTag) BukkitQueue_0.toNative(tag); + final Map map = ReflectionUtils.getMap(nativeTag.getValue()); map.put("Id", new StringTag(id.toString())); setEntity(nativeTag); return true; @@ -171,7 +171,7 @@ public class BukkitChunk_1_13 extends IntFaweChunk { } } - public boolean storeSection(ChunkSection section, int layer) throws IllegalAccessException { + public boolean storeSection(final ChunkSection section, final int layer) throws IllegalAccessException { if (sectionPalettes == null) { // TODO optimize don't copy light sectionPalettes = new ChunkSection[16]; @@ -180,56 +180,56 @@ public class BukkitChunk_1_13 extends IntFaweChunk { return true; } - public ChunkSection copy(ChunkSection current) throws IllegalAccessException, InvocationTargetException, NoSuchFieldException { - ChunkSection newSection = new ChunkSection(current.getYPosition(), current.getSkyLightArray() != null); + public ChunkSection copy(final ChunkSection current) throws IllegalAccessException, InvocationTargetException, NoSuchFieldException { + final ChunkSection newSection = new ChunkSection(current.getYPosition(), current.getSkyLightArray() != null); // Copy light - NibbleArray skyLight = current.getSkyLightArray(); - NibbleArray blockLight = current.getEmittedLightArray(); + final NibbleArray skyLight = current.getSkyLightArray(); + final NibbleArray blockLight = current.getEmittedLightArray(); - NibbleArray newBlockLight = newSection.getEmittedLightArray(); - NibbleArray newSkyLight = newSection.getSkyLightArray(); + final NibbleArray newBlockLight = newSection.getEmittedLightArray(); + final NibbleArray newSkyLight = newSection.getSkyLightArray(); - byte[] newBlockBytes = newBlockLight.asBytes(); - byte[] blockLightBytes = blockLight.asBytes(); + final byte[] newBlockBytes = newBlockLight.asBytes(); + final byte[] blockLightBytes = blockLight.asBytes(); for (int i = 0; i < 2048; i++) newBlockBytes[i] = blockLightBytes[i]; if (skyLight != null) { - byte[] newSkyBytes = newSkyLight.asBytes(); - byte[] skyLightBytes = skyLight.asBytes(); + final byte[] newSkyBytes = newSkyLight.asBytes(); + final byte[] skyLightBytes = skyLight.asBytes(); for (int i = 0; i < 2048; i++) newSkyBytes[i] = skyLightBytes[i]; } // Copy counters - Object nonEmptyBlockCount = BukkitQueue_1_13.fieldNonEmptyBlockCount.get(current); + final Object nonEmptyBlockCount = BukkitQueue_1_13.fieldNonEmptyBlockCount.get(current); BukkitQueue_1_13.fieldNonEmptyBlockCount.set(newSection, nonEmptyBlockCount); - Object tickingBlockCount = BukkitQueue_1_13.fieldTickingBlockCount.get(current); + final Object tickingBlockCount = BukkitQueue_1_13.fieldTickingBlockCount.get(current); BukkitQueue_1_13.fieldTickingBlockCount.set(newSection, tickingBlockCount); - Object liquidCount = BukkitQueue_1_13.fieldLiquidCount.get(current); + final Object liquidCount = BukkitQueue_1_13.fieldLiquidCount.get(current); BukkitQueue_1_13.fieldLiquidCount.set(newSection, liquidCount); // Copy blocks - DataPaletteBlock blocks = current.getBlocks(); - DataPaletteBlock blocksCopy = copy(blocks); + final DataPaletteBlock blocks = current.getBlocks(); + final DataPaletteBlock blocksCopy = copy(blocks); BukkitQueue_1_13.fieldSection.set(newSection, blocksCopy); return newSection; } - public DataPaletteBlock copy(DataPaletteBlock current) throws IllegalAccessException, InvocationTargetException, NoSuchFieldException { + public DataPaletteBlock copy(final DataPaletteBlock current) throws IllegalAccessException, InvocationTargetException, NoSuchFieldException { // Clone palette - DataPalette currentPalette = (DataPalette) BukkitQueue_1_13.fieldPalette.get(current); - DataPaletteBlock paletteBlock = newDataPaletteBlock(); - int size = BukkitQueue_1_13.fieldSize.getInt(current); + final DataPalette currentPalette = (DataPalette) BukkitQueue_1_13.fieldPalette.get(current); + final DataPaletteBlock paletteBlock = newDataPaletteBlock(); + final int size = BukkitQueue_1_13.fieldSize.getInt(current); DataPalette newPalette = currentPalette; if (currentPalette instanceof DataPaletteHash) { // TODO optimize resize newPalette = new DataPaletteHash<>(Block.REGISTRY_ID, size, paletteBlock, GameProfileSerializer::d, GameProfileSerializer::a); - RegistryID currReg = (RegistryID) BukkitQueue_1_13.fieldHashBlocks.get(currentPalette); - RegistryID newReg = (RegistryID) BukkitQueue_1_13.fieldHashBlocks.get(newPalette); - int arrLen = 1 << size; + final RegistryID currReg = (RegistryID) BukkitQueue_1_13.fieldHashBlocks.get(currentPalette); + final RegistryID newReg = (RegistryID) BukkitQueue_1_13.fieldHashBlocks.get(newPalette); + final int arrLen = 1 << size; System.arraycopy(fieldRegistryb.get(currReg), 0, fieldRegistryb.get(newReg), 0, arrLen); System.arraycopy(fieldRegistryc.get(currReg), 0, fieldRegistryc.get(newReg), 0, arrLen); System.arraycopy(fieldRegistryd.get(currReg), 0, fieldRegistryd.get(newReg), 0, arrLen); @@ -238,8 +238,8 @@ public class BukkitChunk_1_13 extends IntFaweChunk { } else if (currentPalette instanceof DataPaletteLinear) { // TODO optimize resize newPalette = new DataPaletteLinear<>(Block.REGISTRY_ID, size, paletteBlock, GameProfileSerializer::d); - Object[] currArray = ((Object[]) BukkitQueue_1_13.fieldLinearBlocks.get(currentPalette)); - Object[] newArray = ((Object[]) BukkitQueue_1_13.fieldLinearBlocks.get(newPalette)); + final Object[] currArray = ((Object[]) BukkitQueue_1_13.fieldLinearBlocks.get(currentPalette)); + final Object[] newArray = ((Object[]) BukkitQueue_1_13.fieldLinearBlocks.get(newPalette)); BukkitQueue_1_13.fieldLinearIndex.set(newPalette, BukkitQueue_1_13.fieldLinearIndex.get(currentPalette)); for (int i = 0; i < newArray.length; i++) newArray[i] = currArray[i]; } @@ -248,12 +248,12 @@ public class BukkitChunk_1_13 extends IntFaweChunk { // Clone size BukkitQueue_1_13.fieldSize.set(paletteBlock, size); // Clone palette - DataBits currentBits = (DataBits) BukkitQueue_1_13.fieldBits.get(current); - DataBits newBits = new DataBits(currentBits.c(), currentBits.b(), currentBits.a().clone()); + final DataBits currentBits = (DataBits) BukkitQueue_1_13.fieldBits.get(current); + final DataBits newBits = new DataBits(currentBits.c(), currentBits.b(), currentBits.a().clone()); BukkitQueue_1_13.fieldBits.set(paletteBlock, newBits); // TODO copy only if different - Object defaultBlock = BukkitQueue_1_13.fieldDefaultBlock.get(current); + final Object defaultBlock = BukkitQueue_1_13.fieldDefaultBlock.get(current); if (defaultBlock != AIR) { ReflectionUtils.setFailsafeFieldValue(BukkitQueue_1_13.fieldDefaultBlock, paletteBlock, BukkitQueue_1_13.fieldDefaultBlock.get(current)); } @@ -262,8 +262,8 @@ public class BukkitChunk_1_13 extends IntFaweChunk { } @Override - public IntFaweChunk copy(boolean shallow) { - BukkitChunk_1_13 copy; + public IntFaweChunk copy(final boolean shallow) { + final BukkitChunk_1_13 copy; if (shallow) { copy = new BukkitChunk_1_13(getParent(), getX(), getZ(), setBlocks, count, air); copy.biomes = biomes; @@ -277,13 +277,13 @@ public class BukkitChunk_1_13 extends IntFaweChunk { copy.sectionPalettes = new ChunkSection[16]; try { for (int i = 0; i < sectionPalettes.length; i++) { - ChunkSection current = sectionPalettes[i]; + final ChunkSection current = sectionPalettes[i]; if (current == null) { continue; } copy.sectionPalettes[i] = copy(current); } - } catch (Throwable e) { + } catch (final Throwable e) { MainUtil.handleError(e); } } @@ -303,13 +303,13 @@ public class BukkitChunk_1_13 extends IntFaweChunk { if (sectionPalettes != null) { return; } - int[][] arrays = getCombinedIdArrays(); + final int[][] arrays = getCombinedIdArrays(); for (int layer = 0; layer < 16; layer++) { if (getCount(layer) > 0) { if (sectionPalettes == null) { sectionPalettes = new ChunkSection[16]; } - int[] array = arrays[layer]; + final int[] array = arrays[layer]; sectionPalettes[layer] = BukkitQueue_1_13.newChunkSection(layer, getParent().hasSky(), array); } } @@ -320,7 +320,7 @@ public class BukkitChunk_1_13 extends IntFaweChunk { getChunk().load(true); } - private void removeEntity(Entity entity) { + private void removeEntity(final Entity entity) { entity.b(false); entity.die(); entity.valid = false; @@ -328,32 +328,32 @@ public class BukkitChunk_1_13 extends IntFaweChunk { @Override public FaweChunk call() { - Spigot_v1_13_R2 adapter = (Spigot_v1_13_R2) BukkitQueue_0.getAdapter(); + final Spigot_v1_13_R2 adapter = (Spigot_v1_13_R2) BukkitQueue_0.getAdapter(); try { - BukkitChunk_1_13 copy = getParent().getChangeTask() != null ? new BukkitChunk_1_13(getParent(), getX(), getZ()) : null; + final BukkitChunk_1_13 copy = getParent().getChangeTask() != null ? new BukkitChunk_1_13(getParent(), getX(), getZ()) : null; final Chunk chunk = this.getChunk(); final World world = chunk.getWorld(); - Settings settings = getParent().getSettings(); - int bx = this.getX() << 4; - int bz = this.getZ() << 4; + final Settings settings = getParent().getSettings(); + final int bx = this.getX() << 4; + final int bz = this.getZ() << 4; final boolean flag = world.getEnvironment() == World.Environment.NORMAL; - net.minecraft.server.v1_13_R2.Chunk nmsChunk = ((CraftChunk) chunk).getHandle(); + final net.minecraft.server.v1_13_R2.Chunk nmsChunk = ((CraftChunk) chunk).getHandle(); nmsChunk.f(true); // Set Modified nmsChunk.mustSave = true; nmsChunk.markDirty(); - net.minecraft.server.v1_13_R2.World nmsWorld = nmsChunk.world; - ChunkSection[] sections = nmsChunk.getSections(); - List[] entities = nmsChunk.getEntitySlices(); - Map tiles = nmsChunk.getTileEntities(); + final net.minecraft.server.v1_13_R2.World nmsWorld = nmsChunk.world; + final ChunkSection[] sections = nmsChunk.getSections(); + final List[] entities = nmsChunk.getEntitySlices(); + final Map tiles = nmsChunk.getTileEntities(); // Remove entities - HashSet entsToRemove = this.getEntityRemoves(); + final HashSet entsToRemove = this.getEntityRemoves(); if (!entsToRemove.isEmpty()) { for (int i = 0; i < entities.length; i++) { - Collection ents = entities[i]; + final Collection ents = entities[i]; if (!ents.isEmpty()) { - Iterator iter = ents.iterator(); + final Iterator iter = ents.iterator(); while (iter.hasNext()) { - Entity entity = iter.next(); + final Entity entity = iter.next(); if (entsToRemove.contains(entity.getUniqueID())) { if (copy != null) { copy.storeEntity(entity); @@ -368,16 +368,16 @@ public class BukkitChunk_1_13 extends IntFaweChunk { } } for (int i = 0; i < entities.length; i++) { - int count = this.getCount(i); + final int count = this.getCount(i); if (count == 0 || settings.EXPERIMENTAL.KEEP_ENTITIES_IN_BLOCKS) { continue; } else if (count >= 4096) { - Collection ents = entities[i]; + final Collection ents = entities[i]; if (!ents.isEmpty()) { synchronized (BukkitQueue_0.class) { - Iterator iter = ents.iterator(); + final Iterator iter = ents.iterator(); while (iter.hasNext()) { - Entity entity = iter.next(); + final Entity entity = iter.next(); if (entity instanceof EntityPlayer) { continue; } @@ -390,24 +390,24 @@ public class BukkitChunk_1_13 extends IntFaweChunk { } } } else { - Collection ents = entities[i]; + final Collection ents = entities[i]; if (!ents.isEmpty()) { - int layerYStart = i << 4; - int layerYEnd = layerYStart + 15; - int[] array = this.getIdArray(i); + final int layerYStart = i << 4; + final int layerYEnd = layerYStart + 15; + final int[] array = this.getIdArray(i); if (array == null) continue; - Iterator iter = ents.iterator(); + final Iterator iter = ents.iterator(); while (iter.hasNext()) { - Entity entity = iter.next(); + final Entity entity = iter.next(); if (entity instanceof EntityPlayer) { continue; } - int y = MathMan.roundInt(entity.locY); + final int y = MathMan.roundInt(entity.locY); if (y > layerYEnd || y < layerYStart) continue; - int x = (MathMan.roundInt(entity.locX) & 15); - int z = (MathMan.roundInt(entity.locZ) & 15); + final int x = (MathMan.roundInt(entity.locX) & 15); + final int z = (MathMan.roundInt(entity.locZ) & 15); - int index = (((y & 0xF) << 8) | (z << 4) | x); + final int index = (((y & 0xF) << 8) | (z << 4) | x); if (array[index] != 0) { if (copy != null) { copy.storeEntity(entity); @@ -422,32 +422,32 @@ public class BukkitChunk_1_13 extends IntFaweChunk { } } // Set entities - Set entitiesToSpawn = this.getEntities(); + final Set entitiesToSpawn = this.getEntities(); if (!entitiesToSpawn.isEmpty()) { synchronized (BukkitQueue_0.class) { - for (CompoundTag nativeTag : entitiesToSpawn) { - Map entityTagMap = ReflectionUtils.getMap(nativeTag.getValue()); - StringTag idTag = (StringTag) entityTagMap.get("Id"); - ListTag posTag = (ListTag) entityTagMap.get("Pos"); - ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); + for (final CompoundTag nativeTag : entitiesToSpawn) { + final Map entityTagMap = ReflectionUtils.getMap(nativeTag.getValue()); + final StringTag idTag = (StringTag) entityTagMap.get("Id"); + final ListTag posTag = (ListTag) entityTagMap.get("Pos"); + final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); if (idTag == null || posTag == null || rotTag == null) { Fawe.debug("Unknown entity tag: " + nativeTag); continue; } - double x = posTag.getDouble(0); - double y = posTag.getDouble(1); - double z = posTag.getDouble(2); - float yaw = rotTag.getFloat(0); - float pitch = rotTag.getFloat(1); - String id = idTag.getValue(); - Entity entity = EntityTypes.a(nmsWorld, new MinecraftKey(id)); + final double x = posTag.getDouble(0); + final double y = posTag.getDouble(1); + final double z = posTag.getDouble(2); + final float yaw = rotTag.getFloat(0); + final float pitch = rotTag.getFloat(1); + final String id = idTag.getValue(); + final Entity entity = EntityTypes.a(nmsWorld, new MinecraftKey(id)); if (entity != null) { - UUID uuid = entity.getUniqueID(); + final UUID uuid = entity.getUniqueID(); entityTagMap.put("UUIDMost", new LongTag(uuid.getMostSignificantBits())); entityTagMap.put("UUIDLeast", new LongTag(uuid.getLeastSignificantBits())); if (nativeTag != null) { - NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_13.fromNative(nativeTag); - for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + final NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_13.fromNative(nativeTag); + for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { tag.remove(name); } entity.f(tag); @@ -462,11 +462,11 @@ public class BukkitChunk_1_13 extends IntFaweChunk { } // Set blocks for (int j = 0; j < sections.length; j++) { - int count = this.getCount(j); + final int count = this.getCount(j); if (count == 0) { continue; } - int countAir = this.getAir(j); + final int countAir = this.getAir(j); final int[] array = this.getIdArray(j); if (array == null) { continue; @@ -501,15 +501,15 @@ public class BukkitChunk_1_13 extends IntFaweChunk { continue; } } - int by = j << 4; - DataPaletteBlock nibble = section.getBlocks(); + final int by = j << 4; + final DataPaletteBlock nibble = section.getBlocks(); int nonEmptyBlockCount = 0; IBlockData existing; for (int y = 0, i = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { for (int x= 0; x < 16; x++, i++) { - int combinedId = array[i]; + final int combinedId = array[i]; switch (combinedId) { case 0: continue; @@ -534,8 +534,8 @@ public class BukkitChunk_1_13 extends IntFaweChunk { } else { nonEmptyBlockCount++; } - BlockState state = BlockState.getFromInternalId(combinedId); - IBlockData ibd = ((BlockMaterial_1_13) state.getMaterial()).getState(); + final BlockState state = BlockState.getFromInternalId(combinedId); + final IBlockData ibd = ((BlockMaterial_1_13) state.getMaterial()).getState(); nibble.setBlock(x, y, z, ibd); } } @@ -547,19 +547,19 @@ public class BukkitChunk_1_13 extends IntFaweChunk { // Trim tiles HashMap toRemove = null; if (!tiles.isEmpty()) { - Iterator> iterator = tiles.entrySet().iterator(); + final Iterator> iterator = tiles.entrySet().iterator(); while (iterator.hasNext()) { - Map.Entry tile = iterator.next(); - BlockPosition pos = tile.getKey(); - int lx = pos.getX() & 15; - int ly = pos.getY(); - int lz = pos.getZ() & 15; - int layer = ly >> 4; - int[] array = this.getIdArray(layer); + final Map.Entry tile = iterator.next(); + final BlockPosition pos = tile.getKey(); + final int lx = pos.getX() & 15; + final int ly = pos.getY(); + final int lz = pos.getZ() & 15; + final int layer = ly >> 4; + final int[] array = this.getIdArray(layer); if (array == null) { continue; } - int index = (((ly & 0xF) << 8) | (lz << 4) | lx); + final int index = (((ly & 0xF) << 8) | (lz << 4) | lx); if (array[index] != 0) { if (toRemove == null) { toRemove = new HashMap<>(); @@ -572,9 +572,9 @@ public class BukkitChunk_1_13 extends IntFaweChunk { } if (toRemove != null) { synchronized (BukkitQueue_0.class) { - for (Map.Entry entry : toRemove.entrySet()) { - BlockPosition bp = entry.getKey(); - TileEntity tile = entry.getValue(); + for (final Map.Entry entry : toRemove.entrySet()) { + final BlockPosition bp = entry.getKey(); + final TileEntity tile = entry.getValue(); nmsWorld.n(bp); tiles.remove(bp); tile.z(); @@ -586,32 +586,32 @@ public class BukkitChunk_1_13 extends IntFaweChunk { // Set biomes if (this.biomes != null) { - BiomeBase[] currentBiomes = nmsChunk.getBiomeIndex(); + final BiomeBase[] currentBiomes = nmsChunk.getBiomeIndex(); if (copy != null) { copy.storeBiomes(currentBiomes); } for (int i = 0 ; i < this.biomes.length; i++) { - BiomeType biome = this.biomes[i]; + final BiomeType biome = this.biomes[i]; if (biome != null) { - Biome craftBiome = adapter.adapt(biome); + final Biome craftBiome = adapter.adapt(biome); currentBiomes[i] = CraftBlock.biomeToBiomeBase(craftBiome); } } } // Set tiles - Map tilesToSpawn = this.getTiles(); + final Map tilesToSpawn = this.getTiles(); if (!tilesToSpawn.isEmpty()) { - for (Map.Entry entry : tilesToSpawn.entrySet()) { - CompoundTag nativeTag = entry.getValue(); - short blockHash = entry.getKey(); - int x = (blockHash >> 12 & 0xF) + bx; - int y = (blockHash & 0xFF); - int z = (blockHash >> 8 & 0xF) + bz; - BlockPosition pos = new BlockPosition(x, y, z); // Set pos + for (final Map.Entry entry : tilesToSpawn.entrySet()) { + final CompoundTag nativeTag = entry.getValue(); + final short blockHash = entry.getKey(); + final int x = (blockHash >> 12 & 0xF) + bx; + final int y = (blockHash & 0xFF); + final int z = (blockHash >> 8 & 0xF) + bz; + final BlockPosition pos = new BlockPosition(x, y, z); // Set pos synchronized (BukkitQueue_0.class) { - TileEntity tileEntity = nmsWorld.getTileEntity(pos); + final TileEntity tileEntity = nmsWorld.getTileEntity(pos); if (tileEntity != null) { - NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_13.fromNative(nativeTag); + final NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_13.fromNative(nativeTag); tag.set("x", new NBTTagInt(x)); tag.set("y", new NBTTagInt(y)); tag.set("z", new NBTTagInt(z)); @@ -624,7 +624,7 @@ public class BukkitChunk_1_13 extends IntFaweChunk { if (copy != null) { getParent().getChangeTask().run(copy, this); } - } catch (Throwable e) { + } catch (final Throwable e) { MainUtil.handleError(e); } return this; diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java index 3cc50d56e..f72b821ec 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java @@ -195,7 +195,7 @@ public class BukkitQueue_1_13 extends BukkitQueue_0 dataPalette = lastSection.getBlocks(); - IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); - int ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToInt(ibd); + public int getCombinedId4Data(final ChunkSection lastSection, final int x, final int y, final int z) { + final DataPaletteBlock dataPalette = lastSection.getBlocks(); + final IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); + final int ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToInt(ibd); return BlockTypes.states[ordinal].getInternalId(); } @Override - public BiomeType getBiome(net.minecraft.server.v1_13_R2.Chunk chunk, int x, int z) { - BiomeBase base = chunk.getBiomeIndex()[((z & 15) << 4) + (x & 15)]; + public BiomeType getBiome(final net.minecraft.server.v1_13_R2.Chunk chunk, final int x, final int z) { + final BiomeBase base = chunk.getBiomeIndex()[((z & 15) << 4) + (x & 15)]; return getAdapter().adapt(CraftBlock.biomeBaseToBiome(base)); } @Override - public int getOpacity(ChunkSection section, int x, int y, int z) { - DataPaletteBlock dataPalette = section.getBlocks(); - IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); + public int getOpacity(final ChunkSection section, final int x, final int y, final int z) { + final DataPaletteBlock dataPalette = section.getBlocks(); + final IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); pos.a(x, y, z); return ibd.b(nmsWorld, pos); } @Override - public int getBrightness(ChunkSection section, int x, int y, int z) { - DataPaletteBlock dataPalette = section.getBlocks(); - IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); + public int getBrightness(final ChunkSection section, final int x, final int y, final int z) { + final DataPaletteBlock dataPalette = section.getBlocks(); + final IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); return ibd.e(); } @Override - public int getOpacityBrightnessPair(ChunkSection section, int x, int y, int z) { - DataPaletteBlock dataPalette = section.getBlocks(); - IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); + public int getOpacityBrightnessPair(final ChunkSection section, final int x, final int y, final int z) { + final DataPaletteBlock dataPalette = section.getBlocks(); + final IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); pos.a(x, y, z); - int opacity = ibd.b(nmsWorld, pos); - int brightness = ibd.e(); + final int opacity = ibd.b(nmsWorld, pos); + final int brightness = ibd.e(); return MathMan.pair16(brightness, opacity); } @Override - public void sendChunk(int x, int z, int bitMask) { - net.minecraft.server.v1_13_R2.Chunk chunk = getCachedChunk(getWorld(), x, z); + public void sendChunk(final int x, final int z, final int bitMask) { + final net.minecraft.server.v1_13_R2.Chunk chunk = getCachedChunk(getWorld(), x, z); if (chunk != null) { sendChunk(getPlayerChunk((WorldServer) chunk.getWorld(), chunk.locX, chunk.locZ), chunk, bitMask); } } @Override - public void sendChunkUpdatePLIB(FaweChunk chunk, FawePlayer... players) { + public void sendChunkUpdatePLIB(final FaweChunk chunk, final FawePlayer... players) { // PlayerChunkMap playerManager = ((CraftWorld) getWorld()).getHandle().getPlayerChunkMap(); // ProtocolManager manager = ProtocolLibrary.getProtocolManager(); // WirePacket packet = null; @@ -602,13 +602,13 @@ public class BukkitQueue_1_13 extends BukkitQueue_0[] entities = nmsChunk.entitySlices; for (int i = 0; i < entities.length; i++) { - Collection slice = entities[i]; + final Collection slice = entities[i]; if (slice != null && !slice.isEmpty()) { return true; } } - } catch (Throwable ignore) {} + } catch (final Throwable ignore) {} return false; } @Override - public boolean removeSectionLighting(ChunkSection section, int layer, boolean sky) { + public boolean removeSectionLighting(final ChunkSection section, final int layer, final boolean sky) { if (section != null) { Arrays.fill(section.getEmittedLightArray().asBytes(), (byte) 0); if (sky) { - byte[] light = section.getSkyLightArray().asBytes(); + final byte[] light = section.getSkyLightArray().asBytes(); if (light != null) { Arrays.fill(light, (byte) 0); } @@ -779,40 +779,40 @@ public class BukkitQueue_1_13 extends BukkitQueue_0> 6; + final int blockBitArrayEnd = (bitsPerEntry * 4096) >> 6; if (num_palette == 1) { for (int i = 0; i < blockBitArrayEnd; i++) blockstates[i] = 0; } else { - BitArray4096 bitArray = new BitArray4096(blockstates, bitsPerEntry); + final BitArray4096 bitArray = new BitArray4096(blockstates, bitsPerEntry); bitArray.fromRaw(blocksCopy); } // set palette & data bits - DataPaletteBlock dataPaletteBlocks = section.getBlocks(); + final DataPaletteBlock dataPaletteBlocks = section.getBlocks(); // private DataPalette h; // protected DataBits a; - long[] bits = Arrays.copyOfRange(blockstates, 0, blockBitArrayEnd); - DataBits nmsBits = new DataBits(bitsPerEntry, 4096, bits); - DataPalette palette; + final long[] bits = Arrays.copyOfRange(blockstates, 0, blockBitArrayEnd); + final DataBits nmsBits = new DataBits(bitsPerEntry, 4096, bits); + final DataPalette palette; // palette = new DataPaletteHash<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::d, GameProfileSerializer::a); palette = new DataPaletteLinear<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::d); // set palette for (int i = 0; i < num_palette; i++) { - int ordinal = paletteToBlock[i]; + final int ordinal = paletteToBlock[i]; blockToPalette[ordinal] = Integer.MAX_VALUE; - BlockState state = BlockTypes.states[ordinal]; - IBlockData ibd = ((BlockMaterial_1_13) state.getMaterial()).getState(); + final BlockState state = BlockTypes.states[ordinal]; + final IBlockData ibd = ((BlockMaterial_1_13) state.getMaterial()).getState(); palette.a(ibd); } try { @@ -916,12 +916,12 @@ public class BukkitQueue_1_13 extends BukkitQueue_0 tiles = chunk.getTileEntities(); + public CompoundTag getTileEntity(final net.minecraft.server.v1_13_R2.Chunk chunk, final int x, final int y, final int z) { + final Map tiles = chunk.getTileEntities(); pos.c(x, y, z); - TileEntity tile = tiles.get(pos); + final TileEntity tile = tiles.get(pos); return tile != null ? getTag(tile) : null; } - public CompoundTag getTag(TileEntity tile) { + public CompoundTag getTag(final TileEntity tile) { try { - NBTTagCompound tag = new NBTTagCompound(); + final NBTTagCompound tag = new NBTTagCompound(); tile.save(tag); // readTagIntoEntity return (CompoundTag) toNative(tag); - } catch (Exception e) { + } catch (final Exception e) { MainUtil.handleError(e); return null; } @@ -951,7 +951,7 @@ public class BukkitQueue_1_13 extends BukkitQueue_0> 4, z >> 4); - return chunk.setBlock(x & 15, y, z & 15, state); - } - - default boolean setBiome(int x, int y, int z, BiomeType biome) { - IChunk chunk = getCachedChunk(x >> 4, z >> 4); - return chunk.setBiome(x & 15, y, z & 15, biome); - } - - default BlockState getBlock(int x, int y, int z) { - IChunk chunk = getCachedChunk(x >> 4, z >> 4); - return chunk.getBlock(x & 15, y, z & 15); - } - - default BiomeType getBiome(int x, int z) { - IChunk chunk = getCachedChunk(x >> 4, z >> 4); - return chunk.getBiome(x & 15, z & 15); - } - - // Return ChunkHolder - ChunkHolder create(boolean full); - - // Region restrictions - IDelegateChunk wrap(IChunk root); -} \ No newline at end of file diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharBlocks.java deleted file mode 100644 index b1a202380..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharBlocks.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13.beta; - -public class CharBlocks implements IBlocks { - protected char[][] blocks; -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/DelegateQueueExtent.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/DelegateQueueExtent.java deleted file mode 100644 index 72ac950cf..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/DelegateQueueExtent.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13.beta; - -import com.boydti.fawe.bukkit.v1_13.IQueueExtent; - -public interface IDelegateQueueExtent { - IQueueExtent getParent(); -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IBlocks.java deleted file mode 100644 index 187a914d3..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IBlocks.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13.beta; - -public interface IBlocks { - -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/QueueHandler.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/QueueHandler.java deleted file mode 100644 index 9461531ab..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/QueueHandler.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13.beta; - -import com.boydti.fawe.config.Settings; -import com.boydti.fawe.util.MathMan; -import com.boydti.fawe.util.TaskManager; -import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.regions.Region; - -import java.util.Iterator; -import java.util.Set; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.ForkJoinTask; - -public class QueueHandler { - private SingleThreadQueueExtent mainExtent; - private SingleThreadQueueExtent[] pool; - - - - public static void apply(Region region, Filter filter) { // TODO not MCAFilter, but another similar class - // The chunks positions to iterate over - Set chunks = region.getChunks(); - Iterator chunksIter = chunks.iterator(); - - // Get a pool, to operate on the chunks in parallel - ForkJoinPool pool = TaskManager.IMP.getPublicForkJoinPool(); - int size = Math.min(chunks.size(), Settings.IMP.QUEUE.PARALLEL_THREADS); - ForkJoinTask[] tasks = new ForkJoinTask[size]; - - for (int i = 0; i < size; i++) { - tasks[i] = pool.submit(new Runnable() { - @Override - public void run() { - // Create a chunk that we will reuse/reset for each operation - IChunk chunk = create(true); - - while (true) { - // Get the next chunk pos - BlockVector2 pos; - synchronized (chunksIter) { - if (!chunksIter.hasNext()) return; - pos = chunksIter.next(); - } - int X = pos.getX(); - int Z = pos.getZ(); - long pair = MathMan.pairInt(X, Z); - - // Initialize - chunk.init(SingleThreadQueueExtent.this, X, Z); - - { // Start set - lastPair = pair; - lastChunk = chunk; - } - try { - if (!filter.appliesChunk(X, Z)) { - continue; - } - chunk = filter.applyChunk(chunk); - - if (chunk == null) continue; - - chunk.filter(filter); - - filter.finishChunk(chunk); - - chunk.apply(); - } finally - { // End set - lastPair = Long.MAX_VALUE; - lastChunk = null; - } - } - } - }); - } - - // Join the tasks - for (ForkJoinTask task : tasks) { - task.join(); - } - } -} \ No newline at end of file diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/SingleThreadQueueExtent.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/SingleThreadQueueExtent.java deleted file mode 100644 index 53f1984e4..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/SingleThreadQueueExtent.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13.beta; - -import com.boydti.fawe.bukkit.v1_13.IQueueExtent; -import com.boydti.fawe.bukkit.v1_13.beta.holder.ChunkHolder; -import com.boydti.fawe.bukkit.v1_13.beta.holder.IDelegateChunk; -import com.boydti.fawe.bukkit.v1_13.beta.holder.ReferenceChunk; -import com.boydti.fawe.config.Settings; -import com.boydti.fawe.util.MathMan; -import com.boydti.fawe.util.MemUtil; -import com.boydti.fawe.wrappers.WorldWrapper; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.world.World; -import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; - -import static com.google.common.base.Preconditions.checkNotNull; - -public abstract class SingleThreadQueueExtent implements IQueueExtent { - private WorldWrapper wrapped; - private World world; - - public World getWorld() { - return world; - } - - public WorldWrapper getWrappedWorld() { - return wrapped; - } - - private void reset() { - wrapped = null; - world = null; - chunks.clear(); - lastChunk = null; - lastPair = Long.MAX_VALUE; - } - - public synchronized void init(World world) { - if (world != null) { - reset(); - } - checkNotNull(world); - if (world instanceof EditSession) { - world = ((EditSession) world).getWorld(); - } - checkNotNull(world); - if (world instanceof WorldWrapper) { - this.wrapped = (WorldWrapper) world; - world = WorldWrapper.unwrap(world); - } else { - this.wrapped = WorldWrapper.wrap(world); - } - this.world = world; - } - - private IChunk lastChunk; - private long lastPair = Long.MAX_VALUE; - private final Long2ObjectLinkedOpenHashMap chunks = new Long2ObjectLinkedOpenHashMap<>(); - - private final IDelegateChunk getCachedChunk2(long pair) { - IDelegateChunk chunk = chunks.get(pair); - if (chunk instanceof ReferenceChunk) { - chunk = (ReferenceChunk) (chunk).getParent(); - } - if (chunk != null) { - lastPair = pair; - lastChunk = chunk; - } - return chunk; - } - - public final IChunk getCachedChunk(int X, int Z) { - long pair = MathMan.pairInt(X, Z); - if (pair == lastPair) { - return lastChunk; - } - - IDelegateChunk chunk = getCachedChunk2(pair); - if (chunk != null) return chunk; - - chunk = getCachedChunk2(pair); - if (chunk != null) return chunk; - - int size = chunks.size(); - if (size > Settings.IMP.QUEUE.TARGET_SIZE || MemUtil.isMemoryLimited()) { - if (size > Settings.IMP.QUEUE.PARALLEL_THREADS * 2 + 16) { - chunk = chunks.removeFirst(); - chunk.apply(); - chunk = (IDelegateChunk) chunk.findParent(ChunkHolder.class); - chunk.init(this, X, Z); - } else { - chunk = create(false); - } - } else { - chunk = create(false); - } - chunk = wrap(chunk); - - chunks.put(pair, chunk); - lastPair = pair; - lastChunk = chunk; - - return chunk; - } -} \ No newline at end of file diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/bukkit/BukkitReusableExtent.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/bukkit/BukkitReusableExtent.java deleted file mode 100644 index 90f34b5dd..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/bukkit/BukkitReusableExtent.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13.beta.bukkit; - -import com.boydti.fawe.bukkit.v1_13.beta.SingleThreadQueueExtent; -import com.sk89q.worldedit.bukkit.BukkitWorld; -import com.sk89q.worldedit.world.World; -import net.minecraft.server.v1_13_R2.WorldServer; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; - -import static com.google.common.base.Preconditions.checkNotNull; - -public class BukkitReusableExtent extends SingleThreadQueueExtent { - private org.bukkit.World bukkitWorld; - private WorldServer nmsWorld; - - public void init(World world) { - super.init(world); - world = getWorld(); - - if (world instanceof BukkitWorld) { - this.bukkitWorld = ((BukkitWorld) world).getWorld(); - } else { - this.bukkitWorld = Bukkit.getWorld(world.getName()); - } - checkNotNull(this.bukkitWorld); - CraftWorld craftWorld = ((CraftWorld) bukkitWorld); - this.nmsWorld = craftWorld.getHandle(); - } - -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ChunkHolder.java deleted file mode 100644 index cf4ebf092..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ChunkHolder.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13.beta.holder; - -import com.boydti.fawe.bukkit.v1_13.beta.CharGetBlocks; -import com.boydti.fawe.bukkit.v1_13.beta.CharSetBlocks; -import com.boydti.fawe.bukkit.v1_13.beta.IGetBlocks; -import com.boydti.fawe.bukkit.v1_13.beta.ISetBlocks; - -public class ChunkHolder extends DelegateChunk { - public ChunkHolder() { - super(new InitChunk(null)); - getParent().setParent(this); - } - - protected final IGetBlocks get() { - return new CharGetBlocks(); - } - - protected final ISetBlocks set() { - return new CharSetBlocks(); - } -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FinalizedChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FinalizedChunk.java deleted file mode 100644 index bd2e9092f..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FinalizedChunk.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13.beta.holder; - -import com.boydti.fawe.bukkit.v1_13.beta.IChunk; - -public class FinalizedChunk extends DelegateChunk { - public FinalizedChunk(IChunk parent) { - super(parent); - } - - @Override - protected void finalize() throws Throwable { - apply(); - setParent(null); - super.finalize(); - } -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FullChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FullChunk.java deleted file mode 100644 index c5c7b3272..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FullChunk.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13.beta.holder; - -import com.boydti.fawe.bukkit.v1_13.beta.IGetBlocks; -import com.boydti.fawe.bukkit.v1_13.beta.ISetBlocks; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; - -public class FullChunk extends DelegateChunk { - private final ISetBlocks set; - private final IGetBlocks get; - - public FullChunk(ChunkHolder parent, IGetBlocks get, ISetBlocks set) { - super(parent); - this.set = set == null ? parent.set() : set; - this.get = get == null ? parent.get() : get; - } - - @Override - public BaseBlock getFullBlock(int x, int y, int z) { - return get.getFullBlock(x, y, z); - } - - @Override - public BiomeType getBiome(int x, int z) { - return get.getBiome(x, z); - } - - @Override - public BlockState getBlock(int x, int y, int z) { - return get.getBlock(x, y, z); - } - - @Override - public void setBiome(int x, int z, BiomeType biome) { - set.setBiome(x, z, biome); - } - - @Override - public void setBlock(int x, int y, int z, BlockStateHolder holder) { - set.setBlock(x, y, z, holder); - } -} \ No newline at end of file diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/GetChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/GetChunk.java deleted file mode 100644 index d6747c328..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/GetChunk.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13.beta.holder; - -import com.boydti.fawe.bukkit.v1_13.beta.IGetBlocks; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; - -public class GetChunk extends InitChunk { - private final IGetBlocks get; - - public GetChunk(ChunkHolder parent) { - super(parent); - this.get = parent.get(); - } - - protected void init() { - getParent().setParent(new FullChunk(getParent(), get, null)); - } - - @Override - public BaseBlock getFullBlock(int x, int y, int z) { - return get.getFullBlock(x, y, z); - } - - @Override - public BiomeType getBiome(int x, int z) { - return get.getBiome(x, z); - } - - @Override - public BlockState getBlock(int x, int y, int z) { - return get.getBlock(x, y, z); - } -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/InitChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/InitChunk.java deleted file mode 100644 index d2a9599b2..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/InitChunk.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13.beta.holder; - -import com.boydti.fawe.bukkit.v1_13.beta.IChunk; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; - -public class InitChunk extends DelegateChunk { - public InitChunk(ChunkHolder parent) { - super(parent); - } - - protected void init() { - getParent().setParent(new SetChunk(getParent())); - } - - @Override - public void setBiome(int x, int z, BiomeType biome) { - init(); - super.setBiome(x, z, biome); - } - - @Override - public void setBlock(int x, int y, int z, BlockStateHolder holder) { - init(); - super.setBlock(x, y, z, holder); - } - - @Override - public BiomeType getBiome(int x, int z) { - init(); - return super.getBiome(x, z); - } - - @Override - public BlockState getBlock(int x, int y, int z) { - init(); - return super.getBlock(x, y, z); - } - - @Override - public BaseBlock getFullBlock(int x, int y, int z) { - init(); - return super.getFullBlock(x, y, z); - } -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ReferenceChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ReferenceChunk.java deleted file mode 100644 index 24607335a..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ReferenceChunk.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13.beta.holder; - -import com.boydti.fawe.bukkit.v1_13.beta.IChunk; - -import java.lang.ref.PhantomReference; -import java.lang.ref.Reference; -import java.lang.ref.SoftReference; - -public abstract class ReferenceChunk implements IDelegateChunk { - private final Reference ref; - - public ReferenceChunk(IChunk parent) { - this.ref = toRef(new FinalizedChunk(parent)); - } - - protected abstract Reference toRef(FinalizedChunk parent); - - @Override - public IChunk getParent() { - FinalizedChunk finalized = ref.get(); - return finalized != null ? finalized.getParent() : null; - } -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SetChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SetChunk.java deleted file mode 100644 index 3b34c7617..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SetChunk.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13.beta.holder; - -import com.boydti.fawe.bukkit.v1_13.beta.IChunk; -import com.boydti.fawe.bukkit.v1_13.beta.ISetBlocks; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BlockStateHolder; - -public class SetChunk extends InitChunk { - - private final ISetBlocks set; - - public SetChunk(ChunkHolder parent) { - super(parent); - this.set = parent.set(); - } - - protected void init() { - getParent().setParent(new FullChunk(getParent(), null, set)); - } - - @Override - public void setBiome(int x, int z, BiomeType biome) { - set.setBiome(x, z, biome); - } - - @Override - public void setBlock(int x, int y, int z, BlockStateHolder holder) { - set.setBlock(x, y, z, holder); - } -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SoftChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SoftChunk.java deleted file mode 100644 index 5c435d7a6..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SoftChunk.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13.beta.holder; - -import com.boydti.fawe.bukkit.v1_13.beta.IChunk; - -import java.lang.ref.Reference; -import java.lang.ref.SoftReference; - -public class SoftChunk extends ReferenceChunk { - - public SoftChunk(IChunk parent) { - super(parent); - } - - @Override - protected Reference toRef(FinalizedChunk parent) { - return new SoftReference<>(parent); - } -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java b/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java index ef9625376..a7bdb8334 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java @@ -31,22 +31,22 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * [ WorldEdit action] - * | + * | * \|/ * [ EditSession ] - The change is processed (area restrictions, change limit, block type) - * | + * | * \|/ * [Block change] - A block change from some location - * | + * | * \|/ * [ Set Queue ] - The SetQueue manages the implementation specific queue - * | + * | * \|/ * [ Fawe Queue] - A queue of chunks - check if the queue has the chunk for a change - * | + * | * \|/ * [ Fawe Chunk Implementation ] - Otherwise create a new FaweChunk object which is a wrapper around the Chunk object - * | + * | * \|/ * [ Execution ] - When done, the queue then sets the blocks for the chunk, performs lighting updates and sends the chunk packet to the clients *

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 bf8369411..ab34b9fc5 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java @@ -1,5 +1,6 @@ package com.boydti.fawe; +import com.boydti.fawe.beta.Trimable; import com.boydti.fawe.jnbt.anvil.BitArray4096; import com.boydti.fawe.object.collection.IterableThreadLocal; import com.boydti.fawe.util.MathMan; @@ -11,29 +12,21 @@ import com.sk89q.worldedit.world.block.BlockTypes; import java.lang.reflect.Field; import java.util.*; -public class FaweCache { - public static final IterableThreadLocal BLOCK_TO_PALETTE_CHAR = new IterableThreadLocal() { - @Override - public char[] init() { - char[] result = new char[BlockTypes.states.length]; - Arrays.fill(result, Character.MAX_VALUE); - return result; - } - }; +public class FaweCache implements Trimable { - public static final IterableThreadLocal PALETTE_TO_BLOCK_CHAR = new IterableThreadLocal() { - @Override - public char[] init() { - return new char[Character.MAX_VALUE]; - } - }; + /* + Palette buffers / cache + */ - public static final IterableThreadLocal SECTION_BLOCKS_CHAR = new IterableThreadLocal() { - @Override - public char[] init() { - return new char[4096]; - } - }; + @Override + public boolean trim(boolean aggressive) { + BLOCK_TO_PALETTE.clean(); + PALETTE_TO_BLOCK.clean(); + BLOCK_STATES.clean(); + SECTION_BLOCKS.clean(); + PALETTE_CACHE.clean(); + return false; + } public static final IterableThreadLocal BLOCK_TO_PALETTE = new IterableThreadLocal() { @Override @@ -75,6 +68,121 @@ public class FaweCache { return map; } + private static final class Palette { + public int paletteToBlockLength; + /** + * Reusable buffer array, MUST check paletteToBlockLength for actual length + */ + public int[] paletteToBlock; + + public int blockstatesLength; + /** + * Reusable buffer array, MUST check blockstatesLength for actual length + */ + public long[] blockstates; + } + + private static final IterableThreadLocal PALETTE_CACHE = new IterableThreadLocal() { + @Override + public Palette init() { + return new Palette(); + } + }; + + /** + * Convert raw char array to palette + * @param layer + * @param blocks + * @return palette + */ + public static Palette toPalette(int layer, char[] blocks) { + return toPalette(layer, null, blocks); + } + + /** + * Convert raw int array to palette + * @param layer + * @param blocks + * @return palette + */ + public static Palette toPalette(int layer, int[] blocks) { + return toPalette(layer, blocks, null); + } + + private static Palette toPalette(int layer, int[] blocksInts, char[] blocksChars) { + int[] blockToPalette = BLOCK_TO_PALETTE.get(); + int[] paletteToBlock = PALETTE_TO_BLOCK.get(); + long[] blockstates = BLOCK_STATES.get(); + int[] blocksCopy = SECTION_BLOCKS.get(); + + int blockIndexStart = layer << 12; + int blockIndexEnd = blockIndexStart + 4096; + int num_palette = 0; + try { + if (blocksChars != null) { + for (int i = blockIndexStart, j = 0; i < blockIndexEnd; i++, j++) { + int ordinal = blocksChars[i]; + int palette = blockToPalette[ordinal]; + if (palette == Integer.MAX_VALUE) { + BlockState state = BlockTypes.states[ordinal]; + blockToPalette[ordinal] = palette = num_palette; + paletteToBlock[num_palette] = ordinal; + num_palette++; + } + blocksCopy[j] = palette; + } + } else if (blocksInts != null) { + for (int i = blockIndexStart, j = 0; i < blockIndexEnd; i++, j++) { + int ordinal = blocksInts[i]; + int palette = blockToPalette[ordinal]; + if (palette == Integer.MAX_VALUE) { + BlockState state = BlockTypes.states[ordinal]; + blockToPalette[ordinal] = palette = num_palette; + paletteToBlock[num_palette] = ordinal; + num_palette++; + } + blocksCopy[j] = palette; + } + } else { + throw new IllegalArgumentException(); + } + + for (int i = 0; i < num_palette; i++) { + blockToPalette[paletteToBlock[i]] = Integer.MAX_VALUE; + } + + // BlockStates + int bitsPerEntry = MathMan.log2nlz(num_palette - 1); + int blockBitArrayEnd = (bitsPerEntry * 4096) >> 6; + if (num_palette == 1) { + // Set a value, because minecraft needs it for some reason + blockstates[0] = 0; + blockBitArrayEnd = 1; + } else { + BitArray4096 bitArray = new BitArray4096(blockstates, bitsPerEntry); + bitArray.fromRaw(blocksCopy); + } + + // Construct palette + Palette palette = PALETTE_CACHE.get(); + palette.paletteToBlockLength = num_palette; + palette.paletteToBlock = paletteToBlock; + + palette.blockstatesLength = blockBitArrayEnd; + palette.blockstates = blockstates; + + return palette; + } catch (Throwable e) { + Arrays.fill(blockToPalette, Integer.MAX_VALUE); + e.printStackTrace(); + throw e; + } + } + + /* + Conversion methods between JNBT tags and raw values + */ + public static ShortTag asTag(short value) { return new ShortTag(value); } @@ -205,56 +313,4 @@ public class FaweCache { if (clazz == null) clazz = EndTag.class; return new ListTag(clazz, list); } - - private static final class Palette { - - } - - public void toPalette(int layer, char[] blocks) { - int[] blockToPalette = FaweCache.BLOCK_TO_PALETTE.get(); - int[] paletteToBlock = FaweCache.PALETTE_TO_BLOCK.get(); - long[] blockstates = FaweCache.BLOCK_STATES.get(); - int[] blocksCopy = FaweCache.SECTION_BLOCKS.get(); - - int blockIndexStart = layer << 12; - int blockIndexEnd = blockIndexStart + 4096; - int num_palette = 0; - try { - for (int i = blockIndexStart, j = 0; i < blockIndexEnd; i++, j++) { - int ordinal = blocks[i]; - int palette = blockToPalette[ordinal]; - if (palette == Integer.MAX_VALUE) { - BlockState state = BlockTypes.states[ordinal]; - blockToPalette[ordinal] = palette = num_palette; - paletteToBlock[num_palette] = ordinal; - num_palette++; - } - blocksCopy[j] = palette; - } - - for (int i = 0; i < num_palette; i++) { - blockToPalette[paletteToBlock[i]] = Integer.MAX_VALUE; - } - - // BlockStates - int bitsPerEntry = MathMan.log2nlz(num_palette - 1); - int blockBitArrayEnd = (bitsPerEntry * 4096) >> 6; - if (num_palette == 1) { - // Set a value, because minecraft needs it for some reason - blockstates[0] = 0; - blockBitArrayEnd = 1; - } else { - BitArray4096 bitArray = new BitArray4096(blockstates, bitsPerEntry); - bitArray.fromRaw(blocksCopy); - } - - // num_palette - // paletteToBlock - // blockstates (range: blockBitArrayEnd) - } catch (Throwable e) { - Arrays.fill(blockToPalette, Integer.MAX_VALUE); - e.printStackTrace(); - throw e; - } - } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/Filter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java similarity index 71% rename from worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/Filter.java rename to worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java index e2bb721c1..6038aacb5 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/Filter.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java @@ -1,8 +1,8 @@ -package com.boydti.fawe.bukkit.v1_13.beta; +package com.boydti.fawe.beta; import com.sk89q.worldedit.world.block.BaseBlock; -public class Filter { +public interface Filter { /** * Check whether a chunk should be read * @@ -10,7 +10,7 @@ public class Filter { * @param cz * @return */ - public boolean appliesChunk(int cx, int cz) { + default boolean appliesChunk(final int cx, final int cz) { return true; } @@ -22,7 +22,7 @@ public class Filter { * @param chunk * @return */ - public IChunk applyChunk(IChunk chunk) { + default IChunk applyChunk(final IChunk chunk) { return chunk; } @@ -36,7 +36,7 @@ public class Filter { * @param z * @param block */ - public void applyBlock(int x, int y, int z, BaseBlock block) { + default void applyBlock(final int x, final int y, final int z, final BaseBlock block) { } /** @@ -45,6 +45,6 @@ public class Filter { * @param chunk * @return */ - public void finishChunk(IChunk chunk) { + default void finishChunk(final IChunk chunk) { } } 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 new file mode 100644 index 000000000..951ec4a9b --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IBlocks.java @@ -0,0 +1,5 @@ +package com.boydti.fawe.beta; + +public interface IBlocks { + +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java similarity index 72% rename from worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IChunk.java rename to worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java index 21452e0b0..5472773fc 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java @@ -1,15 +1,15 @@ -package com.boydti.fawe.bukkit.v1_13.beta; +package com.boydti.fawe.beta; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; -public interface IChunk { +public interface IChunk { /* set */ boolean setBiome(int x, int y, int z, BiomeType biome); - boolean setBlock(int x, int y, int z, BlockStateHolder holder); + boolean setBlock(int x, int y, int z, BlockStateHolder block); /* get */ BiomeType getBiome(int x, int z); @@ -18,14 +18,14 @@ public interface IChunk { BaseBlock getFullBlock(int x, int y, int z); - void init(SingleThreadQueueExtent extent, int X, int Z); + void init(V extent, int X, int Z); + + T apply(); int getX(); int getZ(); - void apply(); - default IChunk getRoot() { return this; } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/IDelegateChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java similarity index 51% rename from worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/IDelegateChunk.java rename to worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java index e71172bc4..bc36a19f1 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/IDelegateChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java @@ -1,14 +1,13 @@ -package com.boydti.fawe.bukkit.v1_13.beta.holder; +package com.boydti.fawe.beta; -import com.boydti.fawe.bukkit.v1_13.beta.IChunk; -import com.boydti.fawe.bukkit.v1_13.beta.SingleThreadQueueExtent; +import com.boydti.fawe.beta.implementation.SingleThreadQueueExtent; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; -public interface IDelegateChunk extends IChunk { - T getParent(); +public interface IDelegateChunk> extends IChunk { + U getParent(); default IChunk getRoot() { IChunk root = getParent(); @@ -19,32 +18,32 @@ public interface IDelegateChunk extends IChunk { } @Override - default void setBiome(int x, int z, BiomeType biome) { - getParent().setBiome(x, z, biome); + default boolean setBiome(final int x, final int y, final int z, final BiomeType biome) { + return getParent().setBiome(x, y, z, biome); } @Override - default void setBlock(int x, int y, int z, BlockStateHolder holder) { - getParent().setBlock(x, y, z, holder); + default boolean setBlock(final int x, final int y, final int z, final BlockStateHolder holder) { + return getParent().setBlock(x, y, z, holder); } @Override - default BiomeType getBiome(int x, int z) { + default BiomeType getBiome(final int x, final int z) { return getParent().getBiome(x, z); } @Override - default BlockState getBlock(int x, int y, int z) { + default BlockState getBlock(final int x, final int y, final int z) { return getParent().getBlock(x, y, z); } @Override - default BaseBlock getFullBlock(int x, int y, int z) { + default BaseBlock getFullBlock(final int x, final int y, final int z) { return getParent().getFullBlock(x, y, z); } @Override - default void init(SingleThreadQueueExtent extent, int X, int Z) { + default void init(final V extent, final int X, final int Z) { getParent().init(extent, X, Z); } @@ -59,18 +58,22 @@ public interface IDelegateChunk extends IChunk { } @Override - default void apply() { - getParent().apply(); + default T apply() { + return getParent().apply(); } - default IChunk findParent(Class clazz) { + default T findParent(final Class clazz) { IChunk root = getParent(); - if (clazz.isAssignableFrom(root.getClass())) return root; + if (clazz.isAssignableFrom(root.getClass())) return (T) root; while (root instanceof IDelegateChunk) { root = ((IDelegateChunk) root).getParent(); - if (clazz.isAssignableFrom(root.getClass())) return root; + if (clazz.isAssignableFrom(root.getClass())) return (T) root; } return null; } + @Override + default void filter(Filter filter) { + getParent().filter(filter); + } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateQueueExtent.java new file mode 100644 index 000000000..32f78095d --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateQueueExtent.java @@ -0,0 +1,44 @@ +package com.boydti.fawe.beta; + +import com.boydti.fawe.beta.implementation.WorldChunkCache; + +import java.util.concurrent.Future; + +public interface IDelegateQueueExtent extends IQueueExtent { + IQueueExtent getParent(); + + @Override + default void init(WorldChunkCache cache) { + getParent().init(cache); + } + + @Override + default IChunk getCachedChunk(int X, int Z) { + return getParent().getCachedChunk(X, Z); + } + + @Override + default Future submit(IChunk chunk) { + return getParent().submit(chunk); + } + + @Override + default IChunk create(boolean full) { + return getParent().create(full); + } + + @Override + default IChunk wrap(IChunk root) { + return getParent().wrap(root); + } + + @Override + default void flush() { + getParent().flush(); + } + + @Override + default boolean trim(boolean aggressive) { + return getParent().trim(aggressive); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IGetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IGetBlocks.java similarity index 87% rename from worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IGetBlocks.java rename to worldedit-core/src/main/java/com/boydti/fawe/beta/IGetBlocks.java index f0c1346d4..bd4ca9271 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IGetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IGetBlocks.java @@ -1,4 +1,4 @@ -package com.boydti.fawe.bukkit.v1_13.beta; +package com.boydti.fawe.beta; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; @@ -10,4 +10,6 @@ public interface IGetBlocks extends IBlocks { BiomeType getBiome(int x, int z); BlockState getBlock(int x, int y, int z); + + void trim(); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java new file mode 100644 index 000000000..67cc845df --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java @@ -0,0 +1,56 @@ +package com.boydti.fawe.beta; + +import com.boydti.fawe.beta.implementation.WorldChunkCache; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import java.io.Flushable; +import java.util.concurrent.Future; + +public interface IQueueExtent extends Flushable, Trimable { + void init(WorldChunkCache world); + + IChunk getCachedChunk(int X, int Z); + + Future submit(IChunk chunk); + + default boolean setBlock(final int x, final int y, final int z, final BlockStateHolder state) { + final IChunk chunk = getCachedChunk(x >> 4, z >> 4); + return chunk.setBlock(x & 15, y, z & 15, state); + } + + default boolean setBiome(final int x, final int y, final int z, final BiomeType biome) { + final IChunk chunk = getCachedChunk(x >> 4, z >> 4); + return chunk.setBiome(x & 15, y, z & 15, biome); + } + + default BlockState getBlock(final int x, final int y, final int z) { + final IChunk chunk = getCachedChunk(x >> 4, z >> 4); + return chunk.getBlock(x & 15, y, z & 15); + } + + default BiomeType getBiome(final int x, final int z) { + final IChunk chunk = getCachedChunk(x >> 4, z >> 4); + return chunk.getBiome(x & 15, z & 15); + } + + /** + * Return the IChunk + * @param full + * @return + */ + IChunk create(boolean full); + + /** + * Wrap the chunk object (i.e. for region restrictions etc.) + * @param root + * @return wrapped chunk + */ + default IChunk wrap(IChunk root) { + return root; + } + + @Override + void flush(); +} \ No newline at end of file diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ISetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java similarity index 50% rename from worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ISetBlocks.java rename to worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java index 6793775b1..f4b453e12 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ISetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java @@ -1,10 +1,10 @@ -package com.boydti.fawe.bukkit.v1_13.beta; +package com.boydti.fawe.beta; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockStateHolder; public interface ISetBlocks extends IBlocks { - void setBiome(int x, int z, BiomeType biome); + boolean setBiome(int x, int y, int z, BiomeType biome); - void setBlock(int x, int y, int z, BlockStateHolder holder); + boolean setBlock(int x, int y, int z, BlockStateHolder holder); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/Trimable.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/Trimable.java new file mode 100644 index 000000000..3cfaffd34 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/Trimable.java @@ -0,0 +1,5 @@ +package com.boydti.fawe.beta; + +public interface Trimable { + boolean trim(boolean aggressive); +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java new file mode 100644 index 000000000..d6dbff8ac --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java @@ -0,0 +1,122 @@ +package com.boydti.fawe.beta.implementation; + +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.IQueueExtent; +import com.boydti.fawe.beta.Trimable; +import com.boydti.fawe.object.collection.IterableThreadLocal; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.World; + +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +public abstract class QueueHandler implements Trimable { + private Map> chunkCache = new HashMap<>(); + private IterableThreadLocal pool = new IterableThreadLocal() { + @Override + public IQueueExtent init() { + return create(); + } + }; + + public WorldChunkCache getOrCreate(final World world) { + synchronized (chunkCache) { + final WeakReference ref = chunkCache.get(world); + if (ref != null) { + final WorldChunkCache cached = ref.get(); + if (cached != null) { + return cached; + } + } + final WorldChunkCache created = new WorldChunkCache(world); + chunkCache.put(world, new WeakReference<>(created)); + return created; + } + } + + public abstract IQueueExtent create(); + + public boolean trim(final boolean aggressive) { + boolean result = true; + synchronized (chunkCache) { + final Iterator>> iter = chunkCache.entrySet().iterator(); + while (iter.hasNext()) { + final Map.Entry> entry = iter.next(); + final WeakReference value = entry.getValue(); + final WorldChunkCache cache = value.get(); + if (cache == null || cache.size() == 0 || cache.trim(aggressive)) { + iter.remove(); + continue; + } + result = false; + } + } + return result; + } + + public static void apply(final Region region, final Filter filter) { // TODO not MCAFilter, but another similar class +// // The chunks positions to iterate over +// final Set chunks = region.getChunks(); +// final Iterator chunksIter = chunks.iterator(); +// +// // Get a pool, to operate on the chunks in parallel +// final ForkJoinPool pool = TaskManager.IMP.getPublicForkJoinPool(); +// final int size = Math.min(chunks.size(), Settings.IMP.QUEUE.PARALLEL_THREADS); +// final ForkJoinTask[] tasks = new ForkJoinTask[size]; +// +// for (int i = 0; i < size; i++) { +// tasks[i] = pool.submit(new Runnable() { +// @Override +// public void run() { +// // Create a chunk that we will reuse/reset for each operation +// IChunk chunk = create(true); +// +// while (true) { +// // Get the next chunk pos +// final BlockVector2 pos; +// synchronized (chunksIter) { +// if (!chunksIter.hasNext()) return; +// pos = chunksIter.next(); +// } +// final int X = pos.getX(); +// final int Z = pos.getZ(); +// final long pair = MathMan.pairInt(X, Z); +// +// // Initialize +// chunk.init(SingleThreadQueueExtent.this, X, Z); +// +// { // Start set +// lastPair = pair; +// lastChunk = chunk; +// } +// try { +// if (!filter.appliesChunk(X, Z)) { +// continue; +// } +// chunk = filter.applyChunk(chunk); +// +// if (chunk == null) continue; +// +// chunk.filter(filter); +// +// filter.finishChunk(chunk); +// +// chunk.apply(); +// } finally +// { // End set +// lastPair = Long.MAX_VALUE; +// lastChunk = null; +// } +// } +// } +// }); +// } +// +// // Join the tasks +// for (final ForkJoinTask task : tasks) { +// task.join(); +// } + } +} \ No newline at end of file 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 new file mode 100644 index 000000000..fa66b8395 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SingleThreadQueueExtent.java @@ -0,0 +1,154 @@ +package com.boydti.fawe.beta.implementation; + +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IQueueExtent; +import com.boydti.fawe.beta.implementation.holder.ReferenceChunk; +import com.boydti.fawe.config.Settings; +import com.boydti.fawe.util.MathMan; +import com.boydti.fawe.util.MemUtil; +import com.boydti.fawe.util.TaskManager; +import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; + +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; + +import static com.google.common.base.Preconditions.checkNotNull; + +public abstract class SingleThreadQueueExtent implements IQueueExtent { + private WorldChunkCache cache; + private Thread currentThread; + + private void checkThread() { + if (Thread.currentThread() != currentThread && currentThread != null) { + throw new UnsupportedOperationException("This class must be used from a single thread. Use multiple queues for concurrent operations"); + } + } + + public WorldChunkCache getCache() { + return cache; + } + + protected synchronized void reset() { + checkThread(); + cache = null; + if (!chunks.isEmpty()) { + for (IChunk chunk : chunks.values()) { + chunk = chunk.getRoot(); + if (chunk != null) { + chunkPool.add(chunk); + } + } + chunks.clear(); + } + lastChunk = null; + lastPair = Long.MAX_VALUE; + currentThread = null; + } + + @Override + public synchronized void init(final WorldChunkCache cache) { + if (cache != null) { + reset(); + } + currentThread = Thread.currentThread(); + checkNotNull(cache); + this.cache = cache; + } + + private IChunk lastChunk; + private long lastPair = Long.MAX_VALUE; + private final Long2ObjectLinkedOpenHashMap chunks = new Long2ObjectLinkedOpenHashMap<>(); + private final ConcurrentLinkedQueue chunkPool = new ConcurrentLinkedQueue<>(); + + @Override + public ForkJoinTask submit(final IChunk tmp) { + final ForkJoinPool pool = TaskManager.IMP.getPublicForkJoinPool(); + return pool.submit(new Callable() { + @Override + public T call() { + IChunk chunk = tmp; + + T result = chunk.apply(); + + chunk = chunk.getRoot(); + if (chunk != null) { + chunkPool.add(chunk); + } + return result; + } + }); + } + + @Override + public synchronized boolean trim(boolean aggressive) { + chunkPool.clear(); + if (Thread.currentThread() == currentThread) { + lastChunk = null; + lastPair = Long.MAX_VALUE; + return chunks.isEmpty(); + } + synchronized (this) { + return currentThread == null; + } + } + + private IChunk pool(final int X, final int Z) { + IChunk next = chunkPool.poll(); + if (next == null) next = create(false); + next.init(this, X, Z); + return next; + } + + public final IChunk getCachedChunk(final int X, final int Z) { + final long pair = MathMan.pairInt(X, Z); + if (pair == lastPair) { + return lastChunk; + } + + IChunk chunk = chunks.get(pair); + if (chunk instanceof ReferenceChunk) { + chunk = ((ReferenceChunk) (chunk)).getParent(); + } + if (chunk != null) { + lastPair = pair; + lastChunk = chunk; + } + if (chunk != null) return chunk; + + checkThread(); + final int size = chunks.size(); + if (size > Settings.IMP.QUEUE.TARGET_SIZE || MemUtil.isMemoryLimited()) { + if (size > Settings.IMP.QUEUE.PARALLEL_THREADS * 2 + 16) { + chunk = chunks.removeFirst(); + submit(chunk); + } + } + chunk = pool(X, Z); + chunk = wrap(chunk); + + chunks.put(pair, chunk); + lastPair = pair; + lastChunk = chunk; + + return chunk; + } + + @Override + public synchronized void flush() { + checkThread(); + if (!chunks.isEmpty()) { + final ForkJoinTask[] tasks = new ForkJoinTask[chunks.size()]; + int i = 0; + for (final IChunk chunk : chunks.values()) { + tasks[i++] = submit(chunk); + } + chunks.clear(); + for (final ForkJoinTask task : tasks) { + if (task != null) task.join(); + } + } + reset(); + } +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/WorldChunkCache.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/WorldChunkCache.java new file mode 100644 index 000000000..93ee2fda9 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/WorldChunkCache.java @@ -0,0 +1,62 @@ +package com.boydti.fawe.beta.implementation; + +import com.boydti.fawe.beta.IGetBlocks; +import com.boydti.fawe.beta.Trimable; +import com.sk89q.worldedit.world.World; +import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.objects.ObjectIterator; + +import java.lang.ref.WeakReference; +import java.util.function.Supplier; + +public class WorldChunkCache implements Trimable { + protected final Long2ObjectLinkedOpenHashMap> getCache; + private final World world; + + protected WorldChunkCache(final World world) { + this.world = world; + this.getCache = new Long2ObjectLinkedOpenHashMap<>(); + } + + public World getWorld() { + return world; + } + + public synchronized int size() { + return getCache.size(); + } + + public synchronized IGetBlocks get(final long index, final Supplier provider) { + final WeakReference ref = getCache.get(index); + if (ref != null) { + final IGetBlocks blocks = ref.get(); + if (blocks != null) return blocks; + } + final IGetBlocks blocks = provider.get(); + getCache.put(index, new WeakReference<>(blocks)); + return blocks; + } + + @Override + public synchronized boolean trim(final boolean aggressive) { + boolean result = true; + if (!getCache.isEmpty()) { + final ObjectIterator>> iter = getCache.long2ObjectEntrySet().fastIterator(); + while (iter.hasNext()) { + final Long2ObjectMap.Entry> entry = iter.next(); + final WeakReference value = entry.getValue(); + final IGetBlocks igb = value.get(); + if (igb == null) iter.remove(); + else { + result = false; + if (!aggressive) return result; + synchronized (igb) { + igb.trim(); + } + } + } + } + return result; + } +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java new file mode 100644 index 000000000..f07b8b44b --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java @@ -0,0 +1,7 @@ +package com.boydti.fawe.beta.implementation.blocks; + +import com.boydti.fawe.beta.IBlocks; + +public class CharBlocks implements IBlocks { + protected char[][] blocks; +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharGetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java similarity index 51% rename from worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharGetBlocks.java rename to worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java index c33ef3100..fe3287145 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharGetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java @@ -1,25 +1,23 @@ -package com.boydti.fawe.bukkit.v1_13.beta; +package com.boydti.fawe.beta.implementation.blocks; +import com.boydti.fawe.beta.IGetBlocks; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; -import net.minecraft.server.v1_13_R2.ChunkSection; public class CharGetBlocks extends CharBlocks implements IGetBlocks { - private ChunkSection[] sections; @Override - public BaseBlock getFullBlock(int x, int y, int z) { + public BaseBlock getFullBlock(final int x, final int y, final int z) { return null; } @Override - public BiomeType getBiome(int x, int z) { - return null; + public BiomeType getBiome(final int x, final int z) { } @Override - public BlockState getBlock(int x, int y, int z) { + public BlockState getBlock(final int x, final int y, final int z) { return null; } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharSetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java similarity index 78% rename from worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharSetBlocks.java rename to worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java index 66c2f4197..f7395d847 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharSetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java @@ -1,5 +1,6 @@ -package com.boydti.fawe.bukkit.v1_13.beta; +package com.boydti.fawe.beta.implementation.blocks; +import com.boydti.fawe.beta.ISetBlocks; import com.sk89q.jnbt.CompoundTag; import java.util.HashMap; diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/FullCharBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/FullCharBlocks.java similarity index 64% rename from worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/FullCharBlocks.java rename to worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/FullCharBlocks.java index e07e6e5b0..695387bca 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/FullCharBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/FullCharBlocks.java @@ -1,4 +1,6 @@ -package com.boydti.fawe.bukkit.v1_13.beta; +package com.boydti.fawe.beta.implementation.blocks; + +import com.boydti.fawe.beta.IBlocks; public class FullCharBlocks implements IBlocks { public final boolean[] hasSections = new boolean[16]; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java new file mode 100644 index 000000000..9204fa951 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java @@ -0,0 +1,243 @@ +package com.boydti.fawe.beta.implementation.holder; + +import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; +import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks; +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IGetBlocks; +import com.boydti.fawe.beta.ISetBlocks; +import com.boydti.fawe.beta.implementation.SingleThreadQueueExtent; +import com.boydti.fawe.beta.implementation.WorldChunkCache; +import com.boydti.fawe.util.MathMan; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import java.util.function.Supplier; + +public abstract class ChunkHolder implements IChunk, Supplier { + private IGetBlocks get; + private ISetBlocks set; + private IBlockDelegate delegate; + private SingleThreadQueueExtent extent; + private int X,Z; + + public ChunkHolder() { + this.delegate = NULL; + } + + public ChunkHolder(IBlockDelegate delegate) { + this.delegate = delegate; + } + + public final IGetBlocks cachedGet() { + if (get == null) get = newGet(); + return get; + } + + public final ISetBlocks cachedSet() { + if (set == null) set = set(); + return set; + } + + public ISetBlocks set() { + return new CharSetBlocks(); + } + + private IGetBlocks newGet() { + WorldChunkCache cache = extent.getCache(); + cache.get(MathMan.pairInt(X, Z), this); + return new CharGetBlocks(); + } + + public void init(final SingleThreadQueueExtent extent, final int X, final int Z) { + this.extent = extent; + this.X = X; + this.Z = Z; + set = null; + if (delegate == BOTH) { + delegate = GET; + } else if (delegate == SET) { + delegate = NULL; + } + } + + public V getExtent() { + return (V) extent; + } + + @Override + public int getX() { + return X; + } + + @Override + public int getZ() { + return Z; + } + + @Override + public boolean setBiome(final int x, final int y, final int z, final BiomeType biome) { + return delegate.setBiome(this, x, y, z, biome); + } + + @Override + public boolean setBlock(final int x, final int y, final int z, final BlockStateHolder block) { + return delegate.setBlock(this, x, y, z, block); + } + + @Override + public BiomeType getBiome(final int x, final int z) { + return delegate.getBiome(this, x, z); + } + + @Override + public BlockState getBlock(final int x, final int y, final int z) { + return delegate.getBlock(this, x, y, z); + } + + @Override + public BaseBlock getFullBlock(final int x, final int y, final int z) { + return delegate.getFullBlock(this, x, y, z); + } + + public interface IBlockDelegate { + boolean setBiome(final ChunkHolder chunk, final int x, final int y, final int z, final BiomeType biome); + + boolean setBlock(final ChunkHolder chunk, final int x, final int y, final int z, final BlockStateHolder holder); + + BiomeType getBiome(final ChunkHolder chunk, final int x, final int z); + + BlockState getBlock(final ChunkHolder chunk, final int x, final int y, final int z); + + BaseBlock getFullBlock(final ChunkHolder chunk, final int x, final int y, final int z); + } + + public static final IBlockDelegate NULL = new IBlockDelegate() { + @Override + public boolean setBiome(final ChunkHolder chunk, final int x, final int y, final int z, final BiomeType biome) { + chunk.cachedSet(); + chunk.delegate = SET; + return chunk.setBiome(x, y, z, biome); + } + + @Override + public boolean setBlock(final ChunkHolder chunk, final int x, final int y, final int z, final BlockStateHolder block) { + chunk.cachedSet(); + chunk.delegate = SET; + return chunk.setBlock(x, y, z, block); + } + + @Override + public BiomeType getBiome(final ChunkHolder chunk, final int x, final int z) { + chunk.cachedGet(); + chunk.delegate = GET; + return chunk.getBiome(x, z); + } + + @Override + public BlockState getBlock(final ChunkHolder chunk, final int x, final int y, final int z) { + chunk.cachedGet(); + chunk.delegate = GET; + return chunk.getBlock(x, y, z); + } + + @Override + public BaseBlock getFullBlock(final ChunkHolder chunk, final int x, final int y, final int z) { + chunk.cachedGet(); + chunk.delegate = GET; + return chunk.getFullBlock(x, y, z); + } + }; + + public static final IBlockDelegate GET = new IBlockDelegate() { + @Override + public boolean setBiome(final ChunkHolder chunk, final int x, final int y, final int z, final BiomeType biome) { + chunk.cachedSet(); + chunk.delegate = BOTH; + return chunk.setBiome(x, y, z, biome); + } + + @Override + public boolean setBlock(final ChunkHolder chunk, final int x, final int y, final int z, final BlockStateHolder block) { + chunk.cachedSet(); + chunk.delegate = BOTH; + return chunk.setBlock(x, y, z, block); + } + + @Override + public BiomeType getBiome(final ChunkHolder chunk, final int x, final int z) { + return chunk.get.getBiome(x, z); + } + + @Override + public BlockState getBlock(final ChunkHolder chunk, final int x, final int y, final int z) { + return chunk.get.getBlock(x, y, z); + } + + @Override + public BaseBlock getFullBlock(final ChunkHolder chunk, final int x, final int y, final int z) { + return chunk.get.getFullBlock(x, y, z); + } + }; + + public static final IBlockDelegate SET = new IBlockDelegate() { + @Override + public boolean setBiome(final ChunkHolder chunk, final int x, final int y, final int z, final BiomeType biome) { + return chunk.set.setBiome(x, y, z, biome); + } + + @Override + public boolean setBlock(final ChunkHolder chunk, final int x, final int y, final int z, final BlockStateHolder block) { + return chunk.set.setBlock(x, y, z, block); + } + + @Override + public BiomeType getBiome(final ChunkHolder chunk, final int x, final int z) { + chunk.cachedGet(); + chunk.delegate = BOTH; + return chunk.getBiome(x, z); + } + + @Override + public BlockState getBlock(final ChunkHolder chunk, final int x, final int y, final int z) { + chunk.cachedGet(); + chunk.delegate = BOTH; + return chunk.getBlock(x, y, z); + } + + @Override + public BaseBlock getFullBlock(final ChunkHolder chunk, final int x, final int y, final int z) { + chunk.cachedGet(); + chunk.delegate = BOTH; + return chunk.getFullBlock(x, y, z); + } + }; + + public static final IBlockDelegate BOTH = new IBlockDelegate() { + @Override + public boolean setBiome(final ChunkHolder chunk, final int x, final int y, final int z, final BiomeType biome) { + return chunk.set.setBiome(x, y, z, biome); + } + + @Override + public boolean setBlock(final ChunkHolder chunk, final int x, final int y, final int z, final BlockStateHolder block) { + return chunk.set.setBlock(x, y, z, block); + } + + @Override + public BiomeType getBiome(final ChunkHolder chunk, final int x, final int z) { + return chunk.get.getBiome(x, z); + } + + @Override + public BlockState getBlock(final ChunkHolder chunk, final int x, final int y, final int z) { + return chunk.get.getBlock(x, y, z); + } + + @Override + public BaseBlock getFullBlock(final ChunkHolder chunk, final int x, final int y, final int z) { + return chunk.get.getFullBlock(x, y, z); + } + }; +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/DelegateChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java similarity index 50% rename from worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/DelegateChunk.java rename to worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java index 19ddffbc0..73ee2db00 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/DelegateChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java @@ -1,11 +1,12 @@ -package com.boydti.fawe.bukkit.v1_13.beta.holder; +package com.boydti.fawe.beta.implementation.holder; -import com.boydti.fawe.bukkit.v1_13.beta.IChunk; +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IDelegateChunk; public class DelegateChunk implements IDelegateChunk { private T parent; - public DelegateChunk(T parent) { + public DelegateChunk(final T parent) { this.parent = parent; } @@ -13,7 +14,7 @@ public class DelegateChunk implements IDelegateChunk { return parent; } - public final void setParent(T parent) { + public final void setParent(final T parent) { this.parent = parent; } -} +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/FinalizedChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/FinalizedChunk.java new file mode 100644 index 000000000..18d6e2d6a --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/FinalizedChunk.java @@ -0,0 +1,30 @@ +package com.boydti.fawe.beta.implementation.holder; + +import com.boydti.fawe.beta.IQueueExtent; +import com.boydti.fawe.beta.IChunk; + +/** + * Used by {@link ReferenceChunk} to allow the chunk to be garbage collected + * - When the object is finalized, add it to the queue + */ +public class FinalizedChunk extends DelegateChunk { + private final IQueueExtent queueExtent; + + public FinalizedChunk(final IChunk parent, IQueueExtent queueExtent) { + super(parent); + this.queueExtent = queueExtent; + } + + /** + * Submit the chunk to the queue + * @throws Throwable + */ + @Override + protected void finalize() throws Throwable { + if (getParent() != null) { + apply(); + setParent(null); + } + super.finalize(); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ReferenceChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ReferenceChunk.java new file mode 100644 index 000000000..956865d6a --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ReferenceChunk.java @@ -0,0 +1,23 @@ +package com.boydti.fawe.beta.implementation.holder; + +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IDelegateChunk; +import com.boydti.fawe.beta.IQueueExtent; + +import java.lang.ref.Reference; + +public abstract class ReferenceChunk implements IDelegateChunk { + private final Reference ref; + + public ReferenceChunk(final IChunk parent, IQueueExtent queueExtent) { + this.ref = toRef(new FinalizedChunk(parent, queueExtent)); + } + + protected abstract Reference toRef(FinalizedChunk parent); + + @Override + public IChunk getParent() { + final FinalizedChunk finalized = ref.get(); + return finalized != null ? finalized.getParent() : null; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/SoftChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/SoftChunk.java new file mode 100644 index 000000000..d23c28f57 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/SoftChunk.java @@ -0,0 +1,19 @@ +package com.boydti.fawe.beta.implementation.holder; + +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IQueueExtent; + +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; + +public class SoftChunk extends ReferenceChunk { + + public SoftChunk(final IChunk parent, IQueueExtent queueExtent) { + super(parent, queueExtent); + } + + @Override + protected Reference toRef(final FinalizedChunk parent) { + return new SoftReference<>(parent); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/WeakChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/WeakChunk.java similarity index 50% rename from worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/WeakChunk.java rename to worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/WeakChunk.java index b574ed010..ad8225bea 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/WeakChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/WeakChunk.java @@ -1,17 +1,17 @@ -package com.boydti.fawe.bukkit.v1_13.beta.holder; +package com.boydti.fawe.beta.implementation.holder; -import com.boydti.fawe.bukkit.v1_13.beta.IChunk; +import com.boydti.fawe.beta.IChunk; import java.lang.ref.Reference; import java.lang.ref.WeakReference; public class WeakChunk extends ReferenceChunk { - public WeakChunk(IChunk parent) { + public WeakChunk(final IChunk parent) { super(parent); } @Override - protected Reference toRef(FinalizedChunk parent) { + protected Reference toRef(final FinalizedChunk parent) { return new WeakReference<>(parent); } } From 6692a2eb92b22f9d83ba83ad72c77cda9e08a271 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Mon, 29 Apr 2019 03:36:23 +1000 Subject: [PATCH 05/54] document some methods --- .../fawe/bukkit/beta/BukkitChunkHolder.java | 2 +- .../fawe/bukkit/beta/BukkitFullChunk.java | 2 +- .../java/com/boydti/fawe/beta/Filter.java | 14 ++++- .../java/com/boydti/fawe/beta/IBlocks.java | 5 +- .../java/com/boydti/fawe/beta/IChunk.java | 61 +++++++++++++----- .../com/boydti/fawe/beta/IDelegateChunk.java | 26 +++++++- .../fawe/beta/IDelegateQueueExtent.java | 3 + .../java/com/boydti/fawe/beta/IGetBlocks.java | 8 ++- .../com/boydti/fawe/beta/IQueueExtent.java | 26 +++++++- .../java/com/boydti/fawe/beta/ISetBlocks.java | 5 ++ .../java/com/boydti/fawe/beta/Trimable.java | 9 +++ .../beta/implementation/QueueHandler.java | 15 ++++- .../SingleThreadQueueExtent.java | 63 +++++++++++++++---- .../beta/implementation/WorldChunkCache.java | 12 +++- .../implementation/holder/ChunkHolder.java | 8 +++ .../implementation/holder/DelegateChunk.java | 4 ++ .../implementation/holder/ReferenceChunk.java | 5 ++ .../beta/implementation/holder/SoftChunk.java | 5 +- .../beta/implementation/holder/WeakChunk.java | 8 ++- 19 files changed, 237 insertions(+), 44 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java index 5a9fcd233..3faba2ebf 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java @@ -38,7 +38,7 @@ public class BukkitChunkHolder extends ChunkHolder { } @Override - public void filter(final Filter filter) { + public void set(final Filter filter) { // for each block // filter.applyBlock(block) throw new UnsupportedOperationException("Not implemented"); diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitFullChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitFullChunk.java index 27104553b..61306140e 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitFullChunk.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitFullChunk.java @@ -21,7 +21,7 @@ public class BukkitFullChunk extends ChunkHolder { } @Override - public void filter(Filter filter) { + public void set(Filter filter) { } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java index 6038aacb5..0d1450fe9 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java @@ -2,7 +2,10 @@ package com.boydti.fawe.beta; import com.sk89q.worldedit.world.block.BaseBlock; -public interface Filter { +/** + * A filter is an interface used for setting blocks + */ +public interface Filter { /** * Check whether a chunk should be read * @@ -47,4 +50,13 @@ public interface Filter { */ default void finishChunk(final IChunk chunk) { } + + /** + * Fork this for use by another thread + * - Typically filters are simple and don't need to create another copy to be thread safe here + * @return this + */ + default Filter fork() { + return this; + } } 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 951ec4a9b..064510830 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,5 +1,8 @@ package com.boydti.fawe.beta; +/** + * Shared interface for IGetBlocks and ISetBlocks + */ public interface IBlocks { -} +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java index 5472773fc..32206ef75 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java @@ -5,30 +5,59 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; -public interface IChunk { - /* set */ - boolean setBiome(int x, int y, int z, BiomeType biome); - - boolean setBlock(int x, int y, int z, BlockStateHolder block); - - /* get */ - BiomeType getBiome(int x, int z); - - BlockState getBlock(int x, int y, int z); - - BaseBlock getFullBlock(int x, int y, int z); - +/** + * Represents a chunk in the queue {@link IQueueExtent} + * Used for getting and setting blocks / biomes / entities + * @param The result type (typically returns true when the chunk is applied) + * @param The IQueue class + */ +public interface IChunk extends Trimable { + /** + * Initialize at the location + * @param extent + * @param X + * @param Z + */ void init(V extent, int X, int Z); - T apply(); - int getX(); int getZ(); + /** + * If the chunk is a delegate, returns it's paren'ts root + * @return root IChunk + */ default IChunk getRoot() { return this; } - void filter(Filter filter); + /** + * @return true if no changes are queued for this chunk + */ + boolean isEmpty(); + + /** + * Apply the queued changes to the world + * @return + */ + T apply(); + + /* set - queues a change */ + boolean setBiome(int x, int y, int z, BiomeType biome); + + boolean setBlock(int x, int y, int z, BlockStateHolder block); + + /** + * Set using the filter + * @param filter + */ + void set(Filter filter); + + /* get - from the world */ + BiomeType getBiome(int x, int z); + + BlockState getBlock(int x, int y, int z); + + BaseBlock getFullBlock(int x, int y, int z); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java index bc36a19f1..e919fb90e 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java @@ -1,11 +1,16 @@ package com.boydti.fawe.beta; -import com.boydti.fawe.beta.implementation.SingleThreadQueueExtent; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; +/** + * Delegate for IChunk + * @param The result type (typically returns true when the chunk is applied) + * @param The IQueue class + * @param parent class + */ public interface IDelegateChunk> extends IChunk { U getParent(); @@ -57,11 +62,26 @@ public interface IDelegateChunk T findParent(final Class clazz) { IChunk root = getParent(); if (clazz.isAssignableFrom(root.getClass())) return (T) root; @@ -73,7 +93,7 @@ public interface IDelegateChunk result type + * @return result + */ Future submit(IChunk chunk); default boolean setBlock(final int x, final int y, final int z, final BlockStateHolder state) { @@ -36,14 +52,16 @@ public interface IQueueExtent extends Flushable, Trimable { } /** - * Return the IChunk + * Create a new root IChunk object
+ * - Full chunks will be reused, so a more optimized chunk can be returned in that case
+ * - Don't wrap the chunk, that should be done in {@link #wrap(IChunk)} * @param full * @return */ IChunk create(boolean full); /** - * Wrap the chunk object (i.e. for region restrictions etc.) + * Wrap the chunk object (i.e. for region restrictions / limits etc.) * @param root * @return wrapped chunk */ @@ -51,6 +69,10 @@ public interface IQueueExtent extends Flushable, Trimable { return root; } + /** + * Flush all changes to the world + * - Best to call this async so it doesn't hang the server + */ @Override void flush(); } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java index f4b453e12..f06a4fd6d 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java @@ -3,8 +3,13 @@ package com.boydti.fawe.beta; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockStateHolder; +/** + * Interface for setting blocks + */ public interface ISetBlocks extends IBlocks { boolean setBiome(int x, int y, int z, BiomeType biome); boolean setBlock(int x, int y, int z, BlockStateHolder holder); + + boolean isEmpty(); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/Trimable.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/Trimable.java index 3cfaffd34..34efe59ae 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/Trimable.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/Trimable.java @@ -1,5 +1,14 @@ package com.boydti.fawe.beta; +/** + * Interface for objects that can be trimmed (memory related)
+ * - Trimming will reduce it's memory footprint + */ public interface Trimable { + /** + * Trim the object, reducing it's memory footprint + * @param aggressive if trimming should be aggressive e.g. Not return early when the first element cannot be trimmed + * @return if this object is empty at the end of the trim, and can therefore be deleted + */ boolean trim(boolean aggressive); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java index d6dbff8ac..213c903d4 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java @@ -4,6 +4,7 @@ import com.boydti.fawe.beta.Filter; import com.boydti.fawe.beta.IQueueExtent; import com.boydti.fawe.beta.Trimable; import com.boydti.fawe.object.collection.IterableThreadLocal; +import com.boydti.fawe.wrappers.WorldWrapper; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.World; @@ -12,8 +13,12 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; +/** + * Class which handles all the queues {@link IQueueExtent} + */ public abstract class QueueHandler implements Trimable { private Map> chunkCache = new HashMap<>(); + private IterableThreadLocal pool = new IterableThreadLocal() { @Override public IQueueExtent init() { @@ -21,7 +26,14 @@ public abstract class QueueHandler implements Trimable { } }; - public WorldChunkCache getOrCreate(final World world) { + /** + * Get or create the WorldChunkCache for a world + * @param world + * @return + */ + public WorldChunkCache getOrCreate(World world) { + world = WorldWrapper.unwrap(world); + synchronized (chunkCache) { final WeakReference ref = chunkCache.get(world); if (ref != null) { @@ -38,6 +50,7 @@ public abstract class QueueHandler implements Trimable { public abstract IQueueExtent create(); + @Override public boolean trim(final boolean aggressive) { boolean result = true; synchronized (chunkCache) { 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 fa66b8395..bab38ff70 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 @@ -6,6 +6,7 @@ import com.boydti.fawe.beta.implementation.holder.ReferenceChunk; import com.boydti.fawe.config.Settings; import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.MemUtil; +import com.boydti.fawe.util.SetQueue; import com.boydti.fawe.util.TaskManager; import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; @@ -16,20 +17,37 @@ import java.util.concurrent.ForkJoinTask; import static com.google.common.base.Preconditions.checkNotNull; +/** + * Single threaded implementation for IQueueExtent (still abstract) + * - Does not implement creation of chunks (that has to implemented by the platform e.g. Bukkit) + * + * This queue is reusable {@link #init(WorldChunkCache)} + */ public abstract class SingleThreadQueueExtent implements IQueueExtent { private WorldChunkCache cache; private Thread currentThread; + /** + * Safety check to ensure that the thread being used matches the one being initialized on + * - Can be removed later + */ private void checkThread() { if (Thread.currentThread() != currentThread && currentThread != null) { throw new UnsupportedOperationException("This class must be used from a single thread. Use multiple queues for concurrent operations"); } } + /** + * Get the {@link WorldChunkCache} + * @return + */ public WorldChunkCache getCache() { return cache; } + /** + * Reset the queue + */ protected synchronized void reset() { checkThread(); cache = null; @@ -37,7 +55,7 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { for (IChunk chunk : chunks.values()) { chunk = chunk.getRoot(); if (chunk != null) { - chunkPool.add(chunk); + CHUNK_POOL.add(chunk); } } chunks.clear(); @@ -47,6 +65,10 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { currentThread = null; } + /** + * Initialize the queue + * @param cache + */ @Override public synchronized void init(final WorldChunkCache cache) { if (cache != null) { @@ -57,24 +79,32 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { this.cache = cache; } + // Last access pointers private IChunk lastChunk; private long lastPair = Long.MAX_VALUE; + // Chunks currently being queued / worked on private final Long2ObjectLinkedOpenHashMap chunks = new Long2ObjectLinkedOpenHashMap<>(); - private final ConcurrentLinkedQueue chunkPool = new ConcurrentLinkedQueue<>(); + // Pool discarded chunks for reuse (can safely be cleared by another thread) + private static final ConcurrentLinkedQueue CHUNK_POOL = new ConcurrentLinkedQueue<>(); @Override - public ForkJoinTask submit(final IChunk tmp) { + public ForkJoinTask submit(final IChunk chunk) { + if (chunk.isEmpty()) { + CHUNK_POOL.add(chunk); + return null; + } + // TODO use SetQueue to run in parallel final ForkJoinPool pool = TaskManager.IMP.getPublicForkJoinPool(); return pool.submit(new Callable() { @Override public T call() { - IChunk chunk = tmp; + IChunk tmp = chunk; - T result = chunk.apply(); + T result = tmp.apply(); - chunk = chunk.getRoot(); - if (chunk != null) { - chunkPool.add(chunk); + tmp = tmp.getRoot(); + if (tmp != null) { + CHUNK_POOL.add(tmp); } return result; } @@ -83,7 +113,8 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { @Override public synchronized boolean trim(boolean aggressive) { - chunkPool.clear(); + // TODO trim individial chunk sections + CHUNK_POOL.clear(); if (Thread.currentThread() == currentThread) { lastChunk = null; lastPair = Long.MAX_VALUE; @@ -94,13 +125,21 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { } } - private IChunk pool(final int X, final int Z) { - IChunk next = chunkPool.poll(); + /** + * Get a new IChunk from either the pool, or create a new one
+ * + Initialize it at the coordinates + * @param X + * @param Z + * @return IChunk + */ + private IChunk poolOrCreate(final int X, final int Z) { + IChunk next = CHUNK_POOL.poll(); if (next == null) next = create(false); next.init(this, X, Z); return next; } + @Override public final IChunk getCachedChunk(final int X, final int Z) { final long pair = MathMan.pairInt(X, Z); if (pair == lastPair) { @@ -125,7 +164,7 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { submit(chunk); } } - chunk = pool(X, Z); + chunk = poolOrCreate(X, Z); chunk = wrap(chunk); chunks.put(pair, chunk); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/WorldChunkCache.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/WorldChunkCache.java index 93ee2fda9..9e5d4461f 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/WorldChunkCache.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/WorldChunkCache.java @@ -10,6 +10,10 @@ import it.unimi.dsi.fastutil.objects.ObjectIterator; import java.lang.ref.WeakReference; import java.util.function.Supplier; +/** + * IGetBlocks may be cached by the WorldChunkCache so that it can be used between multiple IQueueExtents + * - avoids conversion between palette and raw data on every block get + */ public class WorldChunkCache implements Trimable { protected final Long2ObjectLinkedOpenHashMap> getCache; private final World world; @@ -27,6 +31,12 @@ public class WorldChunkCache implements Trimable { return getCache.size(); } + /** + * Get or create the IGetBlocks + * @param index chunk index {@link com.boydti.fawe.util.MathMan#pairInt(int, int)} + * @param provider used to create if it isn't already cached + * @return cached IGetBlocks + */ public synchronized IGetBlocks get(final long index, final Supplier provider) { final WeakReference ref = getCache.get(index); if (ref != null) { @@ -52,7 +62,7 @@ public class WorldChunkCache implements Trimable { result = false; if (!aggressive) return result; synchronized (igb) { - igb.trim(); + igb.trim(aggressive); } } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java index 9204fa951..024da75bf 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java @@ -15,6 +15,9 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import java.util.function.Supplier; +/** + * Abstract IChunk class that implements basic get/set blocks + */ public abstract class ChunkHolder implements IChunk, Supplier { private IGetBlocks get; private ISetBlocks set; @@ -30,6 +33,11 @@ public abstract class ChunkHolder implemen this.delegate = delegate; } + @Override + public boolean isEmpty() { + return set == null || set.isEmpty(); + } + public final IGetBlocks cachedGet() { if (get == null) get = newGet(); return get; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java index 73ee2db00..a41e8357e 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java @@ -3,6 +3,10 @@ package com.boydti.fawe.beta.implementation.holder; import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.IDelegateChunk; +/** + * Implementation of IDelegateChunk + * @param + */ public class DelegateChunk implements IDelegateChunk { private T parent; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ReferenceChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ReferenceChunk.java index 956865d6a..6ef9b01a1 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ReferenceChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ReferenceChunk.java @@ -6,6 +6,11 @@ import com.boydti.fawe.beta.IQueueExtent; import java.lang.ref.Reference; +/** + * An IChunk may be wrapped by a ReferenceChunk if there is low memory
+ * A reference chunk stores a reference (for garbage collection purposes)
+ * - If it is garbage collected, the {@link FinalizedChunk} logic is run + */ public abstract class ReferenceChunk implements IDelegateChunk { private final Reference ref; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/SoftChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/SoftChunk.java index d23c28f57..361b7083d 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/SoftChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/SoftChunk.java @@ -6,9 +6,12 @@ import com.boydti.fawe.beta.IQueueExtent; import java.lang.ref.Reference; import java.lang.ref.SoftReference; +/** + * Soft reference implementation of {@link ReferenceChunk} + */ public class SoftChunk extends ReferenceChunk { - public SoftChunk(final IChunk parent, IQueueExtent queueExtent) { + public SoftChunk(final IChunk parent, final IQueueExtent queueExtent) { super(parent, queueExtent); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/WeakChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/WeakChunk.java index ad8225bea..a97c915d5 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/WeakChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/WeakChunk.java @@ -1,13 +1,17 @@ package com.boydti.fawe.beta.implementation.holder; import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IQueueExtent; import java.lang.ref.Reference; import java.lang.ref.WeakReference; +/** + * Weak reference implementation of {@link ReferenceChunk} + */ public class WeakChunk extends ReferenceChunk { - public WeakChunk(final IChunk parent) { - super(parent); + public WeakChunk(final IChunk parent, final IQueueExtent queueExtent) { + super(parent, queueExtent); } @Override From 33e119ccb6e7fa744cb86541dc56fd2e8db6fd94 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Wed, 1 May 2019 02:19:10 +1000 Subject: [PATCH 06/54] implement block get --- worldedit-bukkit/build.gradle | 2 +- .../com/boydti/fawe/bukkit/FaweBukkit.java | 8 + .../adapter/v1_13_1/Spigot_v1_13_R2.java | 16 +- .../fawe/bukkit/beta/BukkitChunkHolder.java | 18 +- .../fawe/bukkit/beta/BukkitFullChunk.java | 9 +- .../fawe/bukkit/beta/BukkitGetBlocks.java | 167 ++++++++++++ .../boydti/fawe/bukkit/beta/BukkitQueue.java | 39 ++- .../fawe/bukkit/beta/BukkitQueueHandler.java | 11 + .../fawe/bukkit/v1_13/BukkitQueue_1_13.java | 5 +- .../src/main/java/com/boydti/fawe/Fawe.java | 14 + .../main/java/com/boydti/fawe/FaweCache.java | 55 ++-- .../src/main/java/com/boydti/fawe/IFawe.java | 3 + .../com/boydti/fawe/beta/CharFilterBlock.java | 249 ++++++++++++++++++ .../com/boydti/fawe/beta/ChunkFuture.java | 60 +++++ .../java/com/boydti/fawe/beta/Filter.java | 9 +- .../com/boydti/fawe/beta/FilterBlock.java | 60 +++++ .../java/com/boydti/fawe/beta/IBlocks.java | 4 +- .../java/com/boydti/fawe/beta/IChunk.java | 20 +- .../com/boydti/fawe/beta/IDelegateChunk.java | 24 +- .../fawe/beta/IDelegateQueueExtent.java | 2 +- .../java/com/boydti/fawe/beta/IGetBlocks.java | 5 + .../com/boydti/fawe/beta/IQueueExtent.java | 11 +- .../beta/implementation/QueueHandler.java | 153 ++++++----- .../implementation/SimpleCharQueueExtent.java | 13 + .../SingleThreadQueueExtent.java | 54 ++-- .../implementation/blocks/CharBlocks.java | 90 ++++++- .../implementation/blocks/CharGetBlocks.java | 49 +++- .../implementation/blocks/CharSetBlocks.java | 38 ++- .../implementation/blocks/FullCharBlocks.java | 18 +- .../implementation/holder/ChunkHolder.java | 63 ++++- .../implementation/holder/FinalizedChunk.java | 5 +- .../boydti/fawe/beta/test/CountFilter.java | 58 ++++ .../boydti/fawe/jnbt/anvil/BitArray4096.java | 34 +++ .../worldedit/command/RegionCommands.java | 23 ++ .../worldedit/command/SelectionCommands.java | 2 +- .../worldedit/command/UtilityCommands.java | 3 + .../worldedit/world/block/BaseBlock.java | 18 +- .../worldedit/world/block/BlockState.java | 17 +- .../world/block/BlockStateHolder.java | 3 + 39 files changed, 1234 insertions(+), 198 deletions(-) create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueueHandler.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFuture.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/test/CountFilter.java diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle index 42df6e565..205c447d8 100644 --- a/worldedit-bukkit/build.gradle +++ b/worldedit-bukkit/build.gradle @@ -10,7 +10,7 @@ repositories { dependencies { compile project(':worldedit-core') - compile 'org.bukkit:craftbukkit-1.14:pre5' +// compile 'org.bukkit:craftbukkit-1.14:pre5' compile 'net.milkbowl.vault:VaultAPI:1.7' compile 'com.sk89q:dummypermscompat:1.10' compile 'com.destroystokyo.paper:paper-api:1.13.2-R0.1-SNAPSHOT' 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 793f2ef1e..eb872c73a 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 @@ -2,6 +2,9 @@ package com.boydti.fawe.bukkit; import com.boydti.fawe.Fawe; import com.boydti.fawe.IFawe; +import com.boydti.fawe.beta.implementation.QueueHandler; +import com.boydti.fawe.bukkit.beta.BukkitQueue; +import com.boydti.fawe.bukkit.beta.BukkitQueueHandler; import com.boydti.fawe.bukkit.chat.BukkitChatManager; import com.boydti.fawe.bukkit.listener.AsyncTabCompleteListener; import com.boydti.fawe.bukkit.listener.BrushListener; @@ -144,6 +147,11 @@ public class FaweBukkit implements IFawe, Listener { }); } + @Override + public QueueHandler getQueueHandler() { + return new BukkitQueueHandler(); + } + @Override public CUI getCUI(FawePlayer player) { if (Settings.IMP.EXPERIMENTAL.VANILLA_CUI) { diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/Spigot_v1_13_R2.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/Spigot_v1_13_R2.java index 1d3b5fb53..9c9f341d5 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/Spigot_v1_13_R2.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/Spigot_v1_13_R2.java @@ -92,16 +92,16 @@ public final class Spigot_v1_13_R2 extends CachedBukkitAdapter implements Bukkit nbtCreateTagMethod.setAccessible(true); } - public int[] idbToStateOrdinal; + public char[] idbToStateOrdinal; private boolean init() { if (idbToStateOrdinal != null) return false; - idbToStateOrdinal = new int[Block.REGISTRY_ID.a()]; // size + idbToStateOrdinal = new char[Block.REGISTRY_ID.a()]; // size for (int i = 0; i < idbToStateOrdinal.length; i++) { BlockState state = BlockTypes.states[i]; BlockMaterial_1_13 material = (BlockMaterial_1_13) state.getMaterial(); int id = Block.REGISTRY_ID.getId(material.getState()); - idbToStateOrdinal[id] = state.getOrdinal(); + idbToStateOrdinal[id] = state.getOrdinalChar(); } return true; } @@ -532,6 +532,16 @@ public final class Spigot_v1_13_R2 extends CachedBukkitAdapter implements Bukkit } } + public char adaptToChar(IBlockData ibd) { + try { + int id = Block.REGISTRY_ID.getId(ibd); + return idbToStateOrdinal[id]; + } catch (NullPointerException e) { + if (init()) return adaptToChar(ibd); + throw e; + } + } + @Override public BlockData adapt(BlockStateHolder state) { BlockMaterial_1_13 material = (BlockMaterial_1_13) state.getMaterial(); diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java index 3faba2ebf..e36c29777 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java @@ -2,23 +2,24 @@ package com.boydti.fawe.bukkit.beta; import com.boydti.fawe.beta.Filter; import com.boydti.fawe.beta.IGetBlocks; +import com.boydti.fawe.beta.IQueueExtent; import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks; import com.boydti.fawe.beta.implementation.holder.ChunkHolder; -public class BukkitChunkHolder extends ChunkHolder { +public class BukkitChunkHolder extends ChunkHolder { @Override - public void init(final BukkitQueue extent, final int X, final int Z) { + public void init(final IQueueExtent extent, final int X, final int Z) { super.init(extent, X, Z); } @Override public IGetBlocks get() { - BukkitQueue extent = getExtent(); - return null; + BukkitQueue extent = (BukkitQueue) getExtent(); + return new BukkitGetBlocks(extent.getNmsWorld(), getX(), getZ()); } @Override - public Boolean apply() { + public boolean applyAsync() { BukkitGetBlocks get = (BukkitGetBlocks) cachedGet(); CharSetBlocks set = (CharSetBlocks) cachedSet(); // - getBlocks @@ -37,10 +38,15 @@ public class BukkitChunkHolder extends ChunkHolder { // return true; } + @Override + public boolean applySync() { + return true; + } + @Override public void set(final Filter filter) { // for each block // filter.applyBlock(block) throw new UnsupportedOperationException("Not implemented"); } -} +} \ No newline at end of file diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitFullChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitFullChunk.java index 61306140e..c69c48bdb 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitFullChunk.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitFullChunk.java @@ -16,8 +16,13 @@ public class BukkitFullChunk extends ChunkHolder { } @Override - public Object apply() { - return null; + public boolean applyAsync() { + return false; + } + + @Override + public boolean applySync() { + return false; } @Override diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java index 85fa55a11..d3d4f478d 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java @@ -1,8 +1,175 @@ package com.boydti.fawe.bukkit.beta; +import com.boydti.fawe.FaweCache; import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; +import com.boydti.fawe.bukkit.adapter.v1_13_1.Spigot_v1_13_R2; +import com.boydti.fawe.bukkit.v1_13.BukkitQueue_1_13; +import com.boydti.fawe.jnbt.anvil.BitArray4096; +import com.boydti.fawe.util.TaskManager; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockTypes; +import net.minecraft.server.v1_13_R2.Chunk; +import net.minecraft.server.v1_13_R2.ChunkCoordIntPair; +import net.minecraft.server.v1_13_R2.ChunkProviderServer; import net.minecraft.server.v1_13_R2.ChunkSection; +import net.minecraft.server.v1_13_R2.DataBits; +import net.minecraft.server.v1_13_R2.DataPalette; +import net.minecraft.server.v1_13_R2.DataPaletteBlock; +import net.minecraft.server.v1_13_R2.DataPaletteHash; +import net.minecraft.server.v1_13_R2.DataPaletteLinear; +import net.minecraft.server.v1_13_R2.IBlockData; +import net.minecraft.server.v1_13_R2.World; + +import static com.boydti.fawe.bukkit.v0.BukkitQueue_0.getAdapter; public class BukkitGetBlocks extends CharGetBlocks { private ChunkSection[] sections; + private Chunk nmsChunk; + private World nmsWorld; + private int X, Z; + + public BukkitGetBlocks(World nmsWorld, int X, int Z) {/*d*/ + this.nmsWorld = nmsWorld; + this.X = X; + this.Z = Z; + } + + @Override + public BiomeType getBiome(int x, int z) { + // TODO + return null; + } + + @Override + public CompoundTag getTag(int x, int y, int z) { + // TODO + return null; + } + + @Override + protected char[] load(int layer) { + return load(layer, null); + } + + @Override + protected char[] load(int layer, char[] data) { + ChunkSection section = getSections()[layer]; + // Section is null, return empty array + if (section == null) { + return FaweCache.EMPTY_CHAR_4096; + } + if (data == null || data == FaweCache.EMPTY_CHAR_4096) { + data = new char[4096]; + } + + // Efficiently convert ChunkSection to raw data + try { + final DataPaletteBlock blocks = section.getBlocks(); + final DataBits bits = (DataBits) BukkitQueue_1_13.fieldBits.get(blocks); + final DataPalette palette = (DataPalette) BukkitQueue_1_13.fieldPalette.get(blocks); + final int bitsPerEntry = bits.c(); + + final long[] blockStates = bits.a(); + new BitArray4096(blockStates, bitsPerEntry).toRaw(data); + + int num_palette; + if (palette instanceof DataPaletteLinear) { + num_palette = ((DataPaletteLinear) palette).b(); + } else if (palette instanceof DataPaletteHash) { + num_palette = ((DataPaletteHash) palette).b(); + } else { + num_palette = 0; + int[] paletteToBlockInts = FaweCache.PALETTE_TO_BLOCK.get(); + char[] paletteToBlockChars = FaweCache.PALETTE_TO_BLOCK_CHAR.get(); + try { + for (int i = 0; i < 4096; i++) { + char paletteVal = data[i]; + char ordinal = paletteToBlockChars[paletteVal]; + if (ordinal == Character.MAX_VALUE) { + paletteToBlockInts[num_palette++] = paletteVal; + IBlockData ibd = palette.a(data[i]); + if (ibd == null) { + ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar(); + } else { + ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToChar(ibd); + } + paletteToBlockChars[paletteVal] = ordinal; + } + data[i] = ordinal; + } + } finally { + for (int i = 0; i < num_palette; i++) { + int paletteVal = paletteToBlockInts[i]; + paletteToBlockChars[paletteVal] = Character.MAX_VALUE; + } + } + return data; + } + + char[] paletteToBlockChars = FaweCache.PALETTE_TO_BLOCK_CHAR.get(); + try { + for (int i = 0; i < num_palette; i++) { + IBlockData ibd = palette.a(i); + char ordinal; + if (ibd == null) { + ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar(); + System.out.println("Invalid palette"); + } else { + ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToChar(ibd); + } + paletteToBlockChars[i] = ordinal; + } + for (int i = 0; i < 4096; i++) { + char paletteVal = data[i]; + data[i] = paletteToBlockChars[paletteVal]; + } + } finally { + for (int i = 0; i < num_palette; i++) { + paletteToBlockChars[i] = Character.MAX_VALUE; + } + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + return data; + } + + private ChunkSection[] getSections() { + ChunkSection[] tmp = sections; + if (tmp == null) { + Chunk chunk = getChunk(); + sections = tmp = chunk.getSections(); + } + return tmp; + } + + private Chunk getChunk() { + Chunk tmp = nmsChunk; + if (tmp == null) { + ChunkProviderServer provider = (ChunkProviderServer) nmsWorld.getChunkProvider(); + nmsChunk = tmp = provider.chunks.get(ChunkCoordIntPair.a(X, Z)); + if (tmp == null) { + System.out.println("SYNC"); + // TOOD load with paper + nmsChunk = tmp = TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(X, Z)); + } + } + return tmp; + } + + @Override + public boolean hasSection(int layer) { + return getSections()[layer] != null; + } + + @Override + public boolean trim(boolean aggressive) { + if (aggressive) { + sections = null; + nmsChunk = null; + } + return super.trim(aggressive); + } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java index b8fab4466..616f84c99 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java @@ -1,19 +1,50 @@ package com.boydti.fawe.bukkit.beta; import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.implementation.SimpleCharQueueExtent; import com.boydti.fawe.beta.implementation.SingleThreadQueueExtent; import com.boydti.fawe.beta.implementation.WorldChunkCache; import com.boydti.fawe.object.collection.IterableThreadLocal; +import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.world.World; +import net.minecraft.server.v1_13_R2.WorldServer; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; -public class BukkitQueue extends SingleThreadQueueExtent { +import static com.google.common.base.Preconditions.checkNotNull; + +public class BukkitQueue extends SimpleCharQueueExtent { + + private org.bukkit.World bukkitWorld; + private WorldServer nmsWorld; @Override public synchronized void init(WorldChunkCache cache) { World world = cache.getWorld(); + if (world instanceof BukkitWorld) { + this.bukkitWorld = ((BukkitWorld) world).getWorld(); + } else { + this.bukkitWorld = Bukkit.getWorld(world.getName()); + } + checkNotNull(this.bukkitWorld); + CraftWorld craftWorld = ((CraftWorld) bukkitWorld); + this.nmsWorld = craftWorld.getHandle(); super.init(cache); } + public WorldServer getNmsWorld() { + return nmsWorld; + } + + public org.bukkit.World getBukkitWorld() { + return bukkitWorld; + } + + @Override + protected synchronized void reset() { + super.reset(); + } + private static final IterableThreadLocal FULL_CHUNKS = new IterableThreadLocal() { @Override public BukkitFullChunk init() { @@ -24,9 +55,9 @@ public class BukkitQueue extends SingleThreadQueueExtent { @Override public IChunk create(boolean full) { if (full) { - return FULL_CHUNKS.get(); - } else { - return new BukkitChunkHolder(); + // TODO implement +// return FULL_CHUNKS.get(); } + return new BukkitChunkHolder(); } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueueHandler.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueueHandler.java new file mode 100644 index 000000000..00528d29a --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueueHandler.java @@ -0,0 +1,11 @@ +package com.boydti.fawe.bukkit.beta; + +import com.boydti.fawe.beta.IQueueExtent; +import com.boydti.fawe.beta.implementation.QueueHandler; + +public class BukkitQueueHandler extends QueueHandler { + @Override + public IQueueExtent create() { + return new BukkitQueue(); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java index f72b821ec..8f0f188b6 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java @@ -68,8 +68,9 @@ import java.util.function.Supplier; public class BukkitQueue_1_13 extends BukkitQueue_0 { - protected final static Field fieldBits; - protected final static Field fieldPalette; + public final static Field fieldBits; + public final static Field fieldPalette; + protected final static Field fieldSize; protected final static Field fieldHashBlocks; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java b/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java index a7bdb8334..38838b309 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java @@ -1,5 +1,6 @@ package com.boydti.fawe; +import com.boydti.fawe.beta.implementation.QueueHandler; import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.Commands; import com.boydti.fawe.config.Settings; @@ -82,6 +83,8 @@ public class Fawe { private DefaultTransformParser transformParser; private ChatManager chatManager = new PlainChatManager(); + private QueueHandler queueHandler; + /** * Get the implementation specific class * @@ -199,6 +202,17 @@ public class Fawe { public void onDisable() { } + public QueueHandler getQueueHandler() { + if (queueHandler == null) { + synchronized (this) { + if (queueHandler == null) { + queueHandler = IMP.getQueueHandler(); + } + } + } + return queueHandler; + } + public CUI getCUI(Actor actor) { FawePlayer fp = FawePlayer.wrap(actor); CUI cui = fp.getMeta("CUI"); 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 ab34b9fc5..6b4820e0c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java @@ -13,6 +13,7 @@ import java.lang.reflect.Field; import java.util.*; public class FaweCache implements Trimable { + public static final char[] EMPTY_CHAR_4096 = new char[4096]; /* Palette buffers / cache @@ -40,7 +41,16 @@ public class FaweCache implements Trimable { public static final IterableThreadLocal PALETTE_TO_BLOCK = new IterableThreadLocal() { @Override public int[] init() { - return new int[Character.MAX_VALUE]; + return new int[Character.MAX_VALUE + 1]; + } + }; + + public static final IterableThreadLocal PALETTE_TO_BLOCK_CHAR = new IterableThreadLocal() { + @Override + public char[] init() { + char[] result = new char[Character.MAX_VALUE + 1]; + Arrays.fill(result, Character.MAX_VALUE); + return result; } }; @@ -58,17 +68,10 @@ public class FaweCache implements Trimable { } }; - public static Map asMap(Object... pairs) { - HashMap map = new HashMap<>(pairs.length >> 1); - for (int i = 0; i < pairs.length; i += 2) { - String key = (String) pairs[i]; - Object value = pairs[i + 1]; - map.put(key, value); - } - return map; - } - - private static final class Palette { + /** + * Holds data for a palette used in a chunk section + */ + public static final class Palette { public int paletteToBlockLength; /** * Reusable buffer array, MUST check paletteToBlockLength for actual length @@ -91,31 +94,31 @@ public class FaweCache implements Trimable { /** * Convert raw char array to palette - * @param layer + * @param layerOffset * @param blocks * @return palette */ - public static Palette toPalette(int layer, char[] blocks) { - return toPalette(layer, null, blocks); + public static Palette toPalette(int layerOffset, char[] blocks) { + return toPalette(layerOffset, null, blocks); } /** * Convert raw int array to palette - * @param layer + * @param layerOffset * @param blocks * @return palette */ - public static Palette toPalette(int layer, int[] blocks) { - return toPalette(layer, blocks, null); + public static Palette toPalette(int layerOffset, int[] blocks) { + return toPalette(layerOffset, blocks, null); } - private static Palette toPalette(int layer, int[] blocksInts, char[] blocksChars) { + private static Palette toPalette(int layerOffset, int[] blocksInts, char[] blocksChars) { int[] blockToPalette = BLOCK_TO_PALETTE.get(); int[] paletteToBlock = PALETTE_TO_BLOCK.get(); long[] blockstates = BLOCK_STATES.get(); int[] blocksCopy = SECTION_BLOCKS.get(); - int blockIndexStart = layer << 12; + int blockIndexStart = layerOffset << 12; int blockIndexEnd = blockIndexStart + 4096; int num_palette = 0; try { @@ -124,7 +127,7 @@ public class FaweCache implements Trimable { int ordinal = blocksChars[i]; int palette = blockToPalette[ordinal]; if (palette == Integer.MAX_VALUE) { - BlockState state = BlockTypes.states[ordinal]; +// BlockState state = BlockTypes.states[ordinal]; blockToPalette[ordinal] = palette = num_palette; paletteToBlock[num_palette] = ordinal; num_palette++; @@ -183,6 +186,16 @@ public class FaweCache implements Trimable { Conversion methods between JNBT tags and raw values */ + public static Map asMap(Object... pairs) { + HashMap map = new HashMap<>(pairs.length >> 1); + for (int i = 0; i < pairs.length; i += 2) { + String key = (String) pairs[i]; + Object value = pairs[i + 1]; + map.put(key, value); + } + return map; + } + public static ShortTag asTag(short value) { return new ShortTag(value); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/IFawe.java b/worldedit-core/src/main/java/com/boydti/fawe/IFawe.java index ecba46a2f..f41dca35c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/IFawe.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/IFawe.java @@ -1,5 +1,6 @@ package com.boydti.fawe; +import com.boydti.fawe.beta.implementation.QueueHandler; import com.boydti.fawe.object.FaweCommand; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FaweQueue; @@ -62,4 +63,6 @@ public interface IFawe { return ""; } + QueueHandler getQueueHandler(); + } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java new file mode 100644 index 000000000..b0f8ac231 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java @@ -0,0 +1,249 @@ +package com.boydti.fawe.beta; + +import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.registry.BlockMaterial; +import static com.sk89q.worldedit.world.block.BlockTypes.states; +public class CharFilterBlock implements FilterBlock { + private IQueueExtent queue; + private CharGetBlocks chunk; + private char[] section; + + @Override + public void init(IQueueExtent queue) { + this.queue = queue; + } + + @Override + public void init(int X, int Z, IGetBlocks chunk) { + this.chunk = (CharGetBlocks) chunk; + this.X = X; + this.Z = Z; + this.xx = X << 4; + this.zz = Z << 4; + } + + public void init(char[] section, int layer) { + this.section = section; + this.layer = layer; + this.yy = layer << 4; + } + + // local + public int layer, index, x, y, z, xx, yy, zz, X, Z; + + @Override + public int getX() { + return xx + x; + } + + @Override + public int getY() { + return yy + y; + } + + @Override + public int getZ() { + return zz + z; + } + + @Override + public int getLocalX() { + return x; + } + + @Override + public int getLocalY() { + return y; + } + + @Override + public int getLocalZ() { + return z; + } + + @Override + public int getChunkX() { + return X; + } + + @Override + public int getChunkZ() { + return Z; + } + + @Override + public int getOrdinal() { + return section[index]; + } + + @Override + public BlockState getState() { + int ordinal = section[index]; + return BlockTypes.states[ordinal]; + } + + @Override + public BaseBlock getBaseBlock() { + BlockState state = getState(); + BlockMaterial material = state.getMaterial(); + if (material.hasContainer()) { + CompoundTag tag = chunk.getTag(x, y + (layer << 4), z); + return state.toBaseBlock(tag); + } + return state.toBaseBlock(); + } + + @Override + public CompoundTag getTag() { + return null; + } + + public BlockState getOrdinalBelow() { + if (y > 0) { + return states[section[index - 256]]; + } + if (layer > 0) { + final int newLayer = layer - 1; + final CharGetBlocks chunk = this.chunk; + return states[chunk.sections[newLayer].get(chunk, newLayer, index + 3840)]; + } + return BlockTypes.__RESERVED__.getDefaultState(); + } + + public BlockState getStateAbove() { + if (y < 16) { + return states[section[index + 256]]; + } + if (layer < 16) { + final int newLayer = layer + 1; + final CharGetBlocks chunk = this.chunk; + return states[chunk.sections[newLayer].get(chunk, newLayer, index - 3840)]; + } + return BlockTypes.__RESERVED__.getDefaultState(); + } + + public BlockState getStateRelativeY(int y) { + int newY = this.y + y; + int layerAdd = newY >> 4; + switch (layerAdd) { + case 0: + return states[section[this.index + (y << 8)]]; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: { + int newLayer = layer + layerAdd; + if (newLayer < 16) { + int index = this.index + ((y & 15) << 8); + return states[chunk.sections[newLayer].get(chunk, newLayer, index)]; + } + break; + } + case -1: + case -2: + case -3: + case -4: + case -5: + case -6: + case -7: + case -8: + case -9: + case -10: + case -11: + case -12: + case -13: + case -14: + case -15: { + int newLayer = layer + layerAdd; + if (newLayer >= 0) { + int index = this.index + ((y & 15) << 8); + return states[chunk.sections[newLayer].get(chunk, newLayer, index)]; + } + break; + } + } + return BlockTypes.__RESERVED__.getDefaultState(); + } + + public BlockState getStateRelative(final int x, final int y, final int z) { + int newX = this.x + x; + if (newX >> 4 == 0) { + int newZ = this.z + z; + if (newZ >> 4 == 0) { + int newY = this.y + y; + int layerAdd = newY >> 4; + switch (layerAdd) { + case 0: + return states[section[this.index + ((y << 8) | (z << 4) | x)]]; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: { + int newLayer = layer + layerAdd; + if (newLayer < 16) { + int index = this.index + (((y & 15) << 8) | (z << 4) | x); + return states[chunk.sections[newLayer].get(chunk, newLayer, index)]; + } + break; + } + case -1: + case -2: + case -3: + case -4: + case -5: + case -6: + case -7: + case -8: + case -9: + case -10: + case -11: + case -12: + case -13: + case -14: + case -15: { + int newLayer = layer + layerAdd; + if (newLayer >= 0) { + int index = this.index + (((y & 15) << 8) | (z << 4) | x); + return states[chunk.sections[newLayer].get(chunk, newLayer, index)]; + } + break; + } + } + return BlockTypes.__RESERVED__.getDefaultState(); + } + } +// queue.get + // TODO return normal get block + int newY = this.y + y + yy; + if (newY >= 0 && newY <= 256) { + return queue.getBlock(xx + newX, newY, this.zz + this.z + z); + } + return BlockTypes.__RESERVED__.getDefaultState(); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFuture.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFuture.java new file mode 100644 index 000000000..68721cd82 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFuture.java @@ -0,0 +1,60 @@ +package com.boydti.fawe.beta; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class ChunkFuture implements Future { + private final IChunk chunk; + private volatile boolean cancelled; + private volatile boolean done; + + public ChunkFuture(IChunk chunk) { + this.chunk = chunk; + } + + public IChunk getChunk() { + return chunk; + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + cancelled = true; + if (done) return false; + return true; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public boolean isDone() { + return done; + } + + @Override + public Void get() throws InterruptedException, ExecutionException { + synchronized (chunk) { + if (!done) { + this.wait(); + } + } + return null; + } + + @Override + public Void get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + synchronized (chunk) { + if (!done) { + this.wait(unit.toMillis(timeout)); + if (!done) { + throw new TimeoutException(); + } + } + } + return null; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java index 0d1450fe9..fe3adaea9 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java @@ -34,12 +34,9 @@ public interface Filter { * - e.g. block.setId(...)
* - Note: Performance is critical here
* - * @param x - * @param y - * @param z * @param block */ - default void applyBlock(final int x, final int y, final int z, final BaseBlock block) { + default void applyBlock(final FilterBlock block) { } /** @@ -59,4 +56,8 @@ public interface Filter { default Filter fork() { return this; } + + default void join(Filter parent) { + + } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java new file mode 100644 index 000000000..79fb85799 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java @@ -0,0 +1,60 @@ +package com.boydti.fawe.beta; + +import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; + +public interface FilterBlock { + void init(IQueueExtent queue); + + void init(int X, int Z, IGetBlocks chunk); + + int getOrdinal(); + + BlockState getState(); + + BaseBlock getBaseBlock(); + + CompoundTag getTag(); + + default BlockState getOrdinalBelow() { + return getStateRelative(0, -1, 0); + } + + default BlockState getStateAbove() { + return getStateRelative(0, 1, 0); + } + + default BlockState getStateRelativeY(int y) { + return getStateRelative(0, y, 0); + } + + int getX(); + + int getY(); + + int getZ(); + + default int getLocalX() { + return getX() & 15; + } + + default int getLocalY() { + return getY() & 15; + } + + default int getLocalZ() { + return getZ() & 15; + } + + default int getChunkX() { + return getX() >> 4; + } + + default int getChunkZ() { + return getZ() >> 4; + } + + BlockState getStateRelative(final int x, final int y, final int z); +} 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 064510830..0a63725e1 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 @@ -3,6 +3,8 @@ package com.boydti.fawe.beta; /** * Shared interface for IGetBlocks and ISetBlocks */ -public interface IBlocks { +public interface IBlocks extends Trimable { + boolean hasSection(int layer); + void reset(); } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java index 32206ef75..dcd9fbf6c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java @@ -8,17 +8,15 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; /** * Represents a chunk in the queue {@link IQueueExtent} * Used for getting and setting blocks / biomes / entities - * @param The result type (typically returns true when the chunk is applied) - * @param The IQueue class */ -public interface IChunk extends Trimable { +public interface IChunk extends Trimable { /** * Initialize at the location * @param extent * @param X * @param Z */ - void init(V extent, int X, int Z); + void init(IQueueExtent extent, int X, int Z); int getX(); @@ -38,10 +36,16 @@ public interface IChunk extends Trimable { boolean isEmpty(); /** - * Apply the queued changes to the world - * @return + * Apply the queued async changes to the world + * @return false if applySync needs to run */ - T apply(); + boolean applyAsync(); + + /** + * Apply the queued sync changes to the world + * @return true + */ + boolean applySync(); /* set - queues a change */ boolean setBiome(int x, int y, int z, BiomeType biome); @@ -60,4 +64,6 @@ public interface IChunk extends Trimable { BlockState getBlock(int x, int y, int z); BaseBlock getFullBlock(int x, int y, int z); + + void filter(Filter filter, FilterBlock mutable); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java index e919fb90e..62786336f 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java @@ -7,11 +7,9 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; /** * Delegate for IChunk - * @param The result type (typically returns true when the chunk is applied) - * @param The IQueue class * @param parent class */ -public interface IDelegateChunk> extends IChunk { +public interface IDelegateChunk extends IChunk { U getParent(); default IChunk getRoot() { @@ -48,7 +46,7 @@ public interface IDelegateChunk Future submit(IChunk chunk) { + default Future submit(IChunk chunk) { return getParent().submit(chunk); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IGetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IGetBlocks.java index 97f47af8e..bdddaff22 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IGetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IGetBlocks.java @@ -1,5 +1,6 @@ package com.boydti.fawe.beta; +import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -14,6 +15,10 @@ public interface IGetBlocks extends IBlocks, Trimable { BlockState getBlock(int x, int y, int z); + CompoundTag getTag(int x, int y, int z); + @Override boolean trim(boolean aggressive); + + void filter(Filter filter, FilterBlock block); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java index 3e3604275..4e6c35a01 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java @@ -15,6 +15,12 @@ import java.util.concurrent.Future; public interface IQueueExtent extends Flushable, Trimable { void init(WorldChunkCache world); + /** + * Get the {@link WorldChunkCache} + * @return + */ + WorldChunkCache getCache(); + /** * Get the IChunk at a position (and cache it if it's not already) * @param X @@ -26,10 +32,9 @@ public interface IQueueExtent extends Flushable, Trimable { /** * Submit the chunk so that it's changes are applied to the world * @param chunk - * @param result type * @return result */ - Future submit(IChunk chunk); + Future submit(IChunk chunk); default boolean setBlock(final int x, final int y, final int z, final BlockStateHolder state) { final IChunk chunk = getCachedChunk(x >> 4, z >> 4); @@ -75,4 +80,6 @@ public interface IQueueExtent extends Flushable, Trimable { */ @Override void flush(); + + FilterBlock initFilterBlock(); } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java index 213c903d4..a78bfddc9 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java @@ -1,10 +1,17 @@ package com.boydti.fawe.beta.implementation; +import com.boydti.fawe.Fawe; import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.FilterBlock; +import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.IQueueExtent; import com.boydti.fawe.beta.Trimable; +import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.collection.IterableThreadLocal; +import com.boydti.fawe.util.MathMan; +import com.boydti.fawe.util.TaskManager; import com.boydti.fawe.wrappers.WorldWrapper; +import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.World; @@ -12,6 +19,10 @@ import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.Set; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; +import java.util.concurrent.Future; /** * Class which handles all the queues {@link IQueueExtent} @@ -26,6 +37,17 @@ public abstract class QueueHandler implements Trimable { } }; + public Future submit(IChunk chunk) { + if (Fawe.isMainThread()) { + if (!chunk.applyAsync()) { + chunk.applySync(); + } + return null; + } + // TODO return future + return null; + } + /** * Get or create the WorldChunkCache for a world * @param world @@ -50,6 +72,12 @@ public abstract class QueueHandler implements Trimable { public abstract IQueueExtent create(); + public IQueueExtent getQueue(World world) { + IQueueExtent queue = pool.get(); + queue.init(getOrCreate(world)); + return queue; + } + @Override public boolean trim(final boolean aggressive) { boolean result = true; @@ -69,67 +97,68 @@ public abstract class QueueHandler implements Trimable { return result; } - public static void apply(final Region region, final Filter filter) { // TODO not MCAFilter, but another similar class -// // The chunks positions to iterate over -// final Set chunks = region.getChunks(); -// final Iterator chunksIter = chunks.iterator(); -// -// // Get a pool, to operate on the chunks in parallel -// final ForkJoinPool pool = TaskManager.IMP.getPublicForkJoinPool(); -// final int size = Math.min(chunks.size(), Settings.IMP.QUEUE.PARALLEL_THREADS); -// final ForkJoinTask[] tasks = new ForkJoinTask[size]; -// -// for (int i = 0; i < size; i++) { -// tasks[i] = pool.submit(new Runnable() { -// @Override -// public void run() { -// // Create a chunk that we will reuse/reset for each operation -// IChunk chunk = create(true); -// -// while (true) { -// // Get the next chunk pos -// final BlockVector2 pos; -// synchronized (chunksIter) { -// if (!chunksIter.hasNext()) return; -// pos = chunksIter.next(); -// } -// final int X = pos.getX(); -// final int Z = pos.getZ(); -// final long pair = MathMan.pairInt(X, Z); -// -// // Initialize -// chunk.init(SingleThreadQueueExtent.this, X, Z); -// -// { // Start set -// lastPair = pair; -// lastChunk = chunk; -// } -// try { -// if (!filter.appliesChunk(X, Z)) { -// continue; -// } -// chunk = filter.applyChunk(chunk); -// -// if (chunk == null) continue; -// -// chunk.filter(filter); -// -// filter.finishChunk(chunk); -// -// chunk.apply(); -// } finally -// { // End set -// lastPair = Long.MAX_VALUE; -// lastChunk = null; -// } -// } -// } -// }); -// } -// -// // Join the tasks -// for (final ForkJoinTask task : tasks) { -// task.join(); -// } + public void apply(final World world, final Region region, final Filter filter) { + // The chunks positions to iterate over + final Set chunks = region.getChunks(); + final Iterator chunksIter = chunks.iterator(); + + // Get a pool, to operate on the chunks in parallel + final ForkJoinPool pool = TaskManager.IMP.getPublicForkJoinPool(); + final int size = Math.min(chunks.size(), Settings.IMP.QUEUE.PARALLEL_THREADS); + final ForkJoinTask[] tasks = new ForkJoinTask[size]; + + for (int i = 0; i < size; i++) { + tasks[i] = pool.submit(new Runnable() { + @Override + public void run() { + Filter newFilter = filter.fork(); + // Create a chunk that we will reuse/reset for each operation + IQueueExtent queue = getQueue(world); + FilterBlock block = null; + + while (true) { + // Get the next chunk pos + final BlockVector2 pos; + synchronized (chunksIter) { + if (!chunksIter.hasNext()) return; + pos = chunksIter.next(); + } + final int X = pos.getX(); + final int Z = pos.getZ(); + // TODO create full + IChunk chunk = queue.getCachedChunk(X, Z); + // Initialize + chunk.init(queue, X, Z); + try { + if (!newFilter.appliesChunk(X, Z)) { + continue; + } + chunk = newFilter.applyChunk(chunk); + + if (chunk == null) continue; + + if (block == null) block = queue.initFilterBlock(); + chunk.filter(newFilter, block); + + newFilter.finishChunk(chunk); + + queue.submit(chunk); + } finally + { + if (filter != newFilter) { + synchronized (filter) { + newFilter.join(filter); + } + } + } + } + } + }); + } + + // Join the tasks + for (final ForkJoinTask task : tasks) { + task.join(); + } } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java new file mode 100644 index 000000000..f6419164e --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java @@ -0,0 +1,13 @@ +package com.boydti.fawe.beta.implementation; + +import com.boydti.fawe.beta.CharFilterBlock; +import com.boydti.fawe.beta.FilterBlock; + +public abstract class SimpleCharQueueExtent extends SingleThreadQueueExtent { + @Override + public FilterBlock initFilterBlock() { + CharFilterBlock filter = new CharFilterBlock(); + filter.init(this); + return filter; + } +} 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 bab38ff70..1e0809a75 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 @@ -1,5 +1,6 @@ package com.boydti.fawe.beta.implementation; +import com.boydti.fawe.Fawe; import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.IQueueExtent; import com.boydti.fawe.beta.implementation.holder.ReferenceChunk; @@ -12,8 +13,10 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinTask; +import java.util.concurrent.Future; import static com.google.common.base.Preconditions.checkNotNull; @@ -37,10 +40,7 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { } } - /** - * Get the {@link WorldChunkCache} - * @return - */ + @Override public WorldChunkCache getCache() { return cache; } @@ -52,12 +52,7 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { checkThread(); cache = null; if (!chunks.isEmpty()) { - for (IChunk chunk : chunks.values()) { - chunk = chunk.getRoot(); - if (chunk != null) { - CHUNK_POOL.add(chunk); - } - } + CHUNK_POOL.addAll(chunks.values()); chunks.clear(); } lastChunk = null; @@ -88,27 +83,19 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { private static final ConcurrentLinkedQueue CHUNK_POOL = new ConcurrentLinkedQueue<>(); @Override - public ForkJoinTask submit(final IChunk chunk) { + public Future submit(final IChunk chunk) { if (chunk.isEmpty()) { CHUNK_POOL.add(chunk); return null; } - // TODO use SetQueue to run in parallel - final ForkJoinPool pool = TaskManager.IMP.getPublicForkJoinPool(); - return pool.submit(new Callable() { - @Override - public T call() { - IChunk tmp = chunk; - - T result = tmp.apply(); - - tmp = tmp.getRoot(); - if (tmp != null) { - CHUNK_POOL.add(tmp); - } - return result; + if (Fawe.isMainThread()) { + if (!chunk.applyAsync()) { + chunk.applySync(); } - }); + return null; + } + QueueHandler handler = Fawe.get().getQueueHandler(); + return handler.submit(chunk); } @Override @@ -141,7 +128,7 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { @Override public final IChunk getCachedChunk(final int X, final int Z) { - final long pair = MathMan.pairInt(X, Z); + final long pair = (((long) X) << 32) | (Z & 0xffffffffL); if (pair == lastPair) { return lastChunk; } @@ -178,14 +165,21 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { public synchronized void flush() { checkThread(); if (!chunks.isEmpty()) { - final ForkJoinTask[] tasks = new ForkJoinTask[chunks.size()]; + final Future[] tasks = new ForkJoinTask[chunks.size()]; int i = 0; for (final IChunk chunk : chunks.values()) { tasks[i++] = submit(chunk); } chunks.clear(); - for (final ForkJoinTask task : tasks) { - if (task != null) task.join(); + for (final Future task : tasks) { + if (task != null) { + try { + task.get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } } } reset(); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java index f07b8b44b..c348f8d18 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java @@ -3,5 +3,93 @@ package com.boydti.fawe.beta.implementation.blocks; import com.boydti.fawe.beta.IBlocks; public class CharBlocks implements IBlocks { - protected char[][] blocks; + public final char[][] blocks; + public final Section[] sections; + + public CharBlocks() { + blocks = new char[16][]; + sections = new Section[16]; + for (int i = 0; i < 16; i++) sections[i] = NULL; + } + + @Override + public boolean trim(boolean aggressive) { + boolean result = true; + for (int i = 0; i < 16; i++) { + if (sections[i] == NULL) { + blocks[i] = null; + } else { + result = false; + } + } + return result; + } + + @Override + public void reset() { + for (int i = 0; i < 16; i++) sections[i] = NULL; + } + + protected char[] load(int layer) { + return new char[4096]; + } + + protected char[] load(int layer, char[] data) { + for (int i = 0; i < 4096; i++) data[i] = 0; + return data; + } + + @Override + public boolean hasSection(int layer) { + return sections[layer] == FULL; + } + + public char get(int x, int y, int z) { + int layer = y >> 4; + int index = ((y & 15) << 8) | (z << 4) | (x & 15); + return sections[layer].get(this, layer, index); + } + + public char set(int x, int y, int z, char value) { + int layer = y >> 4; + int index = ((y & 15) << 8) | (z << 4) | (x & 15); + return sections[layer].set(this, layer, index, value); + } + + /* + Section + */ + + public static abstract class Section { + public abstract char[] get(CharBlocks blocks, int layer); + + public final char get(CharBlocks blocks, int layer, int index) { + return get(blocks, layer)[index]; + } + + public final char set(CharBlocks blocks, int layer, int index, char value) { + return get(blocks, layer)[index] = value; + } + } + + public static final Section NULL = new Section() { + @Override + public final char[] get(CharBlocks blocks, int layer) { + blocks.sections[layer] = FULL; + char[] arr = blocks.blocks[layer]; + if (arr == null) { + arr = blocks.blocks[layer] = blocks.load(layer); + } else { + blocks.blocks[layer] = blocks.load(layer, arr); + } + return arr; + } + }; + + public static final Section FULL = new Section() { + @Override + public final char[] get(CharBlocks blocks, int layer) { + return blocks.blocks[layer]; + } + }; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java index fe3287145..1bed28997 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java @@ -1,23 +1,52 @@ package com.boydti.fawe.beta.implementation.blocks; +import com.boydti.fawe.beta.CharFilterBlock; +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.beta.IGetBlocks; -import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; -public class CharGetBlocks extends CharBlocks implements IGetBlocks { - +public abstract class CharGetBlocks extends CharBlocks implements IGetBlocks { @Override public BaseBlock getFullBlock(final int x, final int y, final int z) { - return null; - } - - @Override - public BiomeType getBiome(final int x, final int z) { + return BlockTypes.states[get(x, y, z)].toBaseBlock(); } @Override public BlockState getBlock(final int x, final int y, final int z) { - return null; + return BlockTypes.states[get(x, y, z)]; } -} + + @Override + public void filter(Filter filter, FilterBlock block) { + CharFilterBlock b = (CharFilterBlock) block; + for (int layer = 0; layer < 16; layer++) { + if (!hasSection(layer)) continue; + char[] arr = sections[layer].get(this, layer); + b.init(arr, layer); + for (b.y = 0, b.index = 0; b.y < 16; b.y++) { + for (b.z = 0; b.z < 16; b.z++) { + for (b.x = 0; b.x < 16; b.x++, b.index++) { + filter.applyBlock(b); + } + } + } + } + } + + @Override + public boolean trim(boolean aggressive) { + for (int i = 0; i < 16; i++) { + sections[i] = NULL; + blocks[i] = null; + } + return true; + } + + @Override + public void reset() { + super.reset(); + } +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java index f7395d847..9be7c4391 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java @@ -2,14 +2,48 @@ package com.boydti.fawe.beta.implementation.blocks; import com.boydti.fawe.beta.ISetBlocks; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockStateHolder; import java.util.HashMap; import java.util.HashSet; import java.util.UUID; public class CharSetBlocks extends CharBlocks implements ISetBlocks { - private byte[] biomes; + private BiomeType[] biomes; private HashMap tiles; private HashSet entities; private HashSet entityRemoves; -} + + @Override + public boolean setBiome(int x, int y, int z, BiomeType biome) { + if (biomes == null) { + biomes = new BiomeType[256]; + } + biomes[x + (z << 4)] = biome; + return true; + } + + @Override + public boolean setBlock(int x, int y, int z, BlockStateHolder holder) { + set(x, y, z, holder.getOrdinalChar()); + return true; + } + + @Override + public boolean isEmpty() { + if (biomes != null) return false; + for (int i = 0; i < 16; i++) { + if (hasSection(i)) { + return false; + } + } + return true; + } + + @Override + public void reset() { + biomes = null; + super.reset(); + } +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/FullCharBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/FullCharBlocks.java index 695387bca..9d0732d11 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/FullCharBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/FullCharBlocks.java @@ -2,7 +2,23 @@ package com.boydti.fawe.beta.implementation.blocks; import com.boydti.fawe.beta.IBlocks; +// TODO implement public class FullCharBlocks implements IBlocks { public final boolean[] hasSections = new boolean[16]; public final char[] blocks = new char[65536]; -} + + @Override + public boolean hasSection(int layer) { + return false; + } + + @Override + public void reset() { + + } + + @Override + public boolean trim(boolean aggressive) { + return false; + } +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java index 024da75bf..efed7128a 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java @@ -1,5 +1,9 @@ package com.boydti.fawe.beta.implementation.holder; +import com.boydti.fawe.beta.CharFilterBlock; +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.FilterBlock; +import com.boydti.fawe.beta.IQueueExtent; import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks; import com.boydti.fawe.beta.IChunk; @@ -18,11 +22,11 @@ import java.util.function.Supplier; /** * Abstract IChunk class that implements basic get/set blocks */ -public abstract class ChunkHolder implements IChunk, Supplier { +public abstract class ChunkHolder implements IChunk, Supplier { private IGetBlocks get; private ISetBlocks set; private IBlockDelegate delegate; - private SingleThreadQueueExtent extent; + private IQueueExtent extent; private int X,Z; public ChunkHolder() { @@ -33,6 +37,37 @@ public abstract class ChunkHolder implemen this.delegate = delegate; } + @Override + public void filter(Filter filter, FilterBlock block) { + block.init(X, Z, get); + IGetBlocks get = cachedGet(); + get.filter(filter, block); + } + + @Override + public boolean trim(boolean aggressive) { + if (set != null) { + boolean result = set.trim(aggressive); + if (result) { + delegate = NULL; + get = null; + set = null; + return true; + } + } + if (aggressive) { + get = null; + if (delegate == BOTH) { + delegate = SET; + } else if (delegate == GET) { + delegate = NULL; + } + } else { + get.trim(false); + } + return false; + } + @Override public boolean isEmpty() { return set == null || set.isEmpty(); @@ -53,25 +88,29 @@ public abstract class ChunkHolder implemen } private IGetBlocks newGet() { - WorldChunkCache cache = extent.getCache(); - cache.get(MathMan.pairInt(X, Z), this); - return new CharGetBlocks(); + if (extent instanceof SingleThreadQueueExtent) { + WorldChunkCache cache = ((SingleThreadQueueExtent) extent).getCache(); + return cache.get(MathMan.pairInt(X, Z), this); + } + return get(); } - public void init(final SingleThreadQueueExtent extent, final int X, final int Z) { + @Override + public void init(IQueueExtent extent, final int X, final int Z) { this.extent = extent; this.X = X; this.Z = Z; - set = null; - if (delegate == BOTH) { - delegate = GET; - } else if (delegate == SET) { + if (set != null) { + set.reset(); + delegate = SET; + } else { delegate = NULL; } + get = null; } - public V getExtent() { - return (V) extent; + public IQueueExtent getExtent() { + return extent; } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/FinalizedChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/FinalizedChunk.java index 18d6e2d6a..527bcf5ce 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/FinalizedChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/FinalizedChunk.java @@ -22,9 +22,10 @@ public class FinalizedChunk extends DelegateChunk { @Override protected void finalize() throws Throwable { if (getParent() != null) { - apply(); + // TODO apply safely +// apply(); setParent(null); } super.finalize(); } -} +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/test/CountFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/test/CountFilter.java new file mode 100644 index 000000000..9117391f2 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/test/CountFilter.java @@ -0,0 +1,58 @@ +package com.boydti.fawe.beta.test; + +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.FilterBlock; +import com.boydti.fawe.config.BBC; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.util.Countable; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class CountFilter implements Filter { + private int[] counter = new int[BlockTypes.states.length]; + + @Override + public void applyBlock(FilterBlock block) { + counter[block.getOrdinal()]++; + } + + public List> getDistribution() { + List> distribution = new ArrayList<>(); + for (int i = 0; i < counter.length; i++) { + int count = counter[i]; + if (count != 0) { + distribution.add(new Countable<>(BlockTypes.states[i], count)); + } + } + Collections.sort(distribution); + return distribution; + } + + public void print(Actor actor, long size) { + for (Countable c : getDistribution()) { + String name = c.getID().toString(); + String str = String.format("%-7s (%.3f%%) %s", + String.valueOf(c.getAmount()), + c.getAmount() / (double) size * 100, + name); + actor.print(BBC.getPrefix() + str); + } + } + + @Override + public Filter fork() { + return new CountFilter(); + } + + @Override + public void join(Filter parent) { + CountFilter other = (CountFilter) parent; + for (int i = 0; i < counter.length; i++) { + other.counter[i] += this.counter[i]; + } + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/BitArray4096.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/BitArray4096.java index d0a93bcc8..497059c2f 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/BitArray4096.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/BitArray4096.java @@ -159,4 +159,38 @@ public final class BitArray4096 { } return buffer; } + + public final char[] toRaw(char[] buffer) { + final long[] data = this.data; + final int dataLength = longLen; + final int bitsPerEntry = this.bitsPerEntry; + final int maxEntryValue = this.maxEntryValue; + final int maxSeqLocIndex = this.maxSeqLocIndex; + + int localStart = 0; + char lastVal; + int arrI = 0; + long l; + for (int i = 0; i < dataLength; i++) { + l = data[i]; + for (; localStart <= maxSeqLocIndex; localStart += bitsPerEntry) { + lastVal = (char) (l >>> localStart & maxEntryValue); + buffer[arrI++] = lastVal; + } + if (localStart < 64) { + if (i != dataLength - 1) { + lastVal = (char) (l >>> localStart); + localStart -= maxSeqLocIndex; + l = data[i + 1]; + int localShift = bitsPerEntry - localStart; + lastVal |= l << localShift; + lastVal &= maxEntryValue; + buffer[arrI++] = lastVal; + } + } else { + localStart = 0; + } + } + return buffer; + } } \ No newline at end of file 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 bb528fc1e..3fefa6ab9 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 @@ -19,7 +19,12 @@ package com.sk89q.worldedit.command; +import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweAPI; +import com.boydti.fawe.beta.IQueueExtent; +import com.boydti.fawe.beta.implementation.QueueHandler; +import com.boydti.fawe.beta.implementation.WorldChunkCache; +import com.boydti.fawe.beta.test.CountFilter; import com.boydti.fawe.config.BBC; import com.boydti.fawe.example.NMSMappedFaweQueue; import com.boydti.fawe.object.FaweLimit; @@ -61,20 +66,25 @@ import com.sk89q.worldedit.math.convolution.HeightMap; import com.sk89q.worldedit.math.convolution.HeightMapFilter; import com.sk89q.worldedit.math.noise.RandomNoise; import com.sk89q.worldedit.regions.*; +import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.util.command.binding.Range; import com.sk89q.worldedit.util.command.binding.Switch; import com.sk89q.worldedit.util.command.binding.Text; import com.sk89q.worldedit.util.command.parametric.Optional; +import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.biome.Biomes; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.registry.BiomeRegistry; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -261,6 +271,19 @@ public class RegionCommands extends MethodCommands { BBC.VISITOR_BLOCK.send(player, blocksChanged); } + @Command( + aliases = {"debugtest"}, + usage = "", + desc = "debugtest", + help = "debugtest" + ) + public void debugtest(Player player, @Selection Region region) throws WorldEditException { + QueueHandler queueHandler = Fawe.get().getQueueHandler(); + World world = player.getWorld(); + CountFilter filter = new CountFilter(); + queueHandler.apply(world, region, filter); + } + @Command( aliases = {"/curve", "/spline"}, usage = " [thickness]", diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index 840cb6d7c..27d4d33a6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -710,7 +710,7 @@ public class SelectionCommands { distributionData = (List) editSession.getBlockDistributionWithData(region); else distributionData = (List) editSession.getBlockDistribution(region); - size = session.getSelection(player.getWorld()).getArea(); + size = region.getArea(); if (distributionData.size() <= 0) { player.printError(BBC.getPrefix() + "No blocks counted."); 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 437e6db74..31ada8944 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 @@ -21,6 +21,8 @@ package com.sk89q.worldedit.command; import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweAPI; +import com.boydti.fawe.beta.implementation.QueueHandler; +import com.boydti.fawe.beta.implementation.WorldChunkCache; import com.boydti.fawe.command.FaweParser; import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.Commands; @@ -70,6 +72,7 @@ import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.visitor.EntityVisitor; import com.sk89q.worldedit.internal.annotation.Direction; +import com.sk89q.worldedit.internal.annotation.Selection; import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java index 38285926c..886dee7cc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java @@ -19,25 +19,23 @@ package com.sk89q.worldedit.world.block; -import static com.google.common.base.Preconditions.checkNotNull; - import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.world.registry.BlockMaterial; -import com.sk89q.worldedit.world.registry.LegacyMapper; -import com.sk89q.worldedit.blocks.TileEntityBlock; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.registry.state.PropertyKey; +import com.sk89q.worldedit.world.registry.BlockMaterial; +import com.sk89q.worldedit.world.registry.LegacyMapper; import javax.annotation.Nullable; - import java.util.Map; import java.util.Objects; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Represents a "snapshot" of a block with NBT Data. * @@ -84,7 +82,6 @@ public class BaseBlock implements BlockStateHolder { */ public BaseBlock(BlockState blockState) { -// this(blockState, blockState.getNbtData()); this.blockState = blockState; } @@ -210,7 +207,12 @@ public class BaseBlock implements BlockStateHolder { } @Override - public BaseBlock toBaseBlock() { + public final char getOrdinalChar() { + return blockState.getOrdinalChar(); + } + + @Override + public final BaseBlock toBaseBlock() { return this; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index 71c6b7ad0..3aef40e27 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -52,6 +52,7 @@ import java.util.stream.Stream; public class BlockState implements BlockStateHolder, FawePattern { private final int internalId; private final int ordinal; + private final char ordinalChar; private final BlockType blockType; private BlockMaterial material; private BaseBlock emptyBaseBlock; @@ -60,6 +61,7 @@ public class BlockState implements BlockStateHolder, FawePattern { this.blockType = blockType; this.internalId = internalId; this.ordinal = ordinal; + this.ordinalChar = (char) ordinal; this.emptyBaseBlock = new BaseBlock(this); } @@ -285,7 +287,7 @@ public class BlockState implements BlockStateHolder, FawePattern { } @Override - public BaseBlock toBaseBlock() { + public final BaseBlock toBaseBlock() { return this.emptyBaseBlock; } @@ -330,10 +332,15 @@ public class BlockState implements BlockStateHolder, FawePattern { return material; } - @Override - public int getOrdinal() { - return this.ordinal; - } + @Override + public int getOrdinal() { + return this.ordinal; + } + + @Override + public final char getOrdinalChar() { + return this.ordinalChar; + } @Override public String toString() { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java index 6ab42e12c..6747f670a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java @@ -63,6 +63,9 @@ public interface BlockStateHolder> extends FawePat @Deprecated int getOrdinal(); + @Deprecated + char getOrdinalChar(); + BlockMaterial getMaterial(); /** * Get type id (legacy uses) From eec08c81ad51d0ff32d9d4f7233d8e4373db093f Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Thu, 2 May 2019 01:45:18 +1000 Subject: [PATCH 07/54] async chunk loading --- .../fawe/bukkit/beta/BukkitChunkHolder.java | 51 +- .../fawe/bukkit/beta/BukkitFullChunk.java | 42 - .../fawe/bukkit/beta/BukkitGetBlocks.java | 24 +- .../boydti/fawe/bukkit/beta/BukkitQueue.java | 203 ++- .../boydti/fawe/bukkit/beta/DelegateLock.java | 78 ++ .../fawe/bukkit/v1_13/BukkitQueue_1_13.java | 151 ++- .../main/java/com/boydti/fawe/FaweCache.java | 19 + .../com/boydti/fawe/beta/CharFilterBlock.java | 75 +- .../java/com/boydti/fawe/beta/IChunk.java | 38 +- .../com/boydti/fawe/beta/IDelegateChunk.java | 11 +- .../java/com/boydti/fawe/beta/IGetBlocks.java | 4 + .../com/boydti/fawe/beta/IQueueExtent.java | 2 +- .../java/com/boydti/fawe/beta/ISetBlocks.java | 4 + .../beta/implementation/QueueHandler.java | 105 +- .../SingleThreadQueueExtent.java | 111 +- .../implementation/blocks/CharGetBlocks.java | 13 +- .../implementation/holder/ChunkHolder.java | 37 +- .../worldedit/command/RegionCommands.java | 3 + .../sk89q/worldedit/world/block/BlockID.java | 1128 ++++++++--------- .../worldedit/world/block/BlockTypes.java | 7 +- 20 files changed, 1224 insertions(+), 882 deletions(-) delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitFullChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/DelegateLock.java diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java index e36c29777..61d872767 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java @@ -6,7 +6,9 @@ import com.boydti.fawe.beta.IQueueExtent; import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks; import com.boydti.fawe.beta.implementation.holder.ChunkHolder; -public class BukkitChunkHolder extends ChunkHolder { +import java.util.concurrent.Future; + +public class BukkitChunkHolder> extends ChunkHolder { @Override public void init(final IQueueExtent extent, final int X, final int Z) { super.init(extent, X, Z); @@ -19,30 +21,37 @@ public class BukkitChunkHolder extends ChunkHolder { } @Override - public boolean applyAsync() { - BukkitGetBlocks get = (BukkitGetBlocks) cachedGet(); - CharSetBlocks set = (CharSetBlocks) cachedSet(); -// - getBlocks -// - set lock -// - synchronize on chunk object -// - verify section is same object as chunk's section -// - merge with setblocks -// - set section -// - verify chunk is same -// - verify section is same -// - Otherwise repeat steps on main thread -// - set status to needs relighting -// - mark as dirty -// - skip verification if main thread + public T call() { + BukkitQueue extent = (BukkitQueue) getExtent(); + BukkitGetBlocks get = (BukkitGetBlocks) getOrCreateGet(); + CharSetBlocks set = (CharSetBlocks) getOrCreateSet(); + + + + /* + + - getBlocks + - set ChunkSection lock with a tracking lock + - synchronize on chunk object (so no other FAWE thread updates it at the same time) + - verify cached section is same object as NMS chunk section + otherwise, fetch the new section, set the tracking lock and reconstruct the getBlocks array + - Merge raw getBlocks and setBlocks array + - Construct the ChunkSection + - In parallel on the main thread + - if the tracking lock has had no updates and the cached ChunkSection == the NMS chunk section + - Otherwise, reconstruct the ChunkSection (TODO: Benchmark if this is a performance concern) + - swap in the new ChunkSection + - Update tile entities/entities (if necessary) + - Merge the biome array (if necessary) + - set chunk status to needs relighting + - mark as dirty + + */ + throw new UnsupportedOperationException("Not implemented"); // return true; } - @Override - public boolean applySync() { - return true; - } - @Override public void set(final Filter filter) { // for each block diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitFullChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitFullChunk.java deleted file mode 100644 index c69c48bdb..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitFullChunk.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.boydti.fawe.bukkit.beta; - -import com.boydti.fawe.beta.Filter; -import com.boydti.fawe.beta.IQueueExtent; -import com.boydti.fawe.beta.ISetBlocks; -import com.boydti.fawe.beta.implementation.holder.ChunkHolder; - -public class BukkitFullChunk extends ChunkHolder { - public BukkitFullChunk() { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void init(IQueueExtent extent, int X, int Z) { - - } - - @Override - public boolean applyAsync() { - return false; - } - - @Override - public boolean applySync() { - return false; - } - - @Override - public void set(Filter filter) { - - } - - @Override - public Object get() { - return null; - } - - @Override - public ISetBlocks set() { - return null; - } -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java index d3d4f478d..d1d8d135e 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java @@ -24,10 +24,10 @@ import net.minecraft.server.v1_13_R2.World; import static com.boydti.fawe.bukkit.v0.BukkitQueue_0.getAdapter; public class BukkitGetBlocks extends CharGetBlocks { - private ChunkSection[] sections; - private Chunk nmsChunk; - private World nmsWorld; - private int X, Z; + public ChunkSection[] sections; + public Chunk nmsChunk; + public World nmsWorld; + public int X, Z; public BukkitGetBlocks(World nmsWorld, int X, int Z) {/*d*/ this.nmsWorld = nmsWorld; @@ -48,12 +48,12 @@ public class BukkitGetBlocks extends CharGetBlocks { } @Override - protected char[] load(int layer) { + public char[] load(int layer) { return load(layer, null); } @Override - protected char[] load(int layer, char[] data) { + public char[] load(int layer, char[] data) { ChunkSection section = getSections()[layer]; // Section is null, return empty array if (section == null) { @@ -136,7 +136,7 @@ public class BukkitGetBlocks extends CharGetBlocks { return data; } - private ChunkSection[] getSections() { + public ChunkSection[] getSections() { ChunkSection[] tmp = sections; if (tmp == null) { Chunk chunk = getChunk(); @@ -145,16 +145,10 @@ public class BukkitGetBlocks extends CharGetBlocks { return tmp; } - private Chunk getChunk() { + public Chunk getChunk() { Chunk tmp = nmsChunk; if (tmp == null) { - ChunkProviderServer provider = (ChunkProviderServer) nmsWorld.getChunkProvider(); - nmsChunk = tmp = provider.chunks.get(ChunkCoordIntPair.a(X, Z)); - if (tmp == null) { - System.out.println("SYNC"); - // TOOD load with paper - nmsChunk = tmp = TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(X, Z)); - } + nmsChunk = tmp = BukkitQueue.ensureLoaded(nmsWorld, X, Z); } return tmp; } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java index 616f84c99..5c869bc29 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java @@ -1,16 +1,43 @@ package com.boydti.fawe.bukkit.beta; +import com.boydti.fawe.Fawe; +import com.boydti.fawe.FaweCache; import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.implementation.SimpleCharQueueExtent; import com.boydti.fawe.beta.implementation.SingleThreadQueueExtent; import com.boydti.fawe.beta.implementation.WorldChunkCache; +import com.boydti.fawe.bukkit.adapter.v1_13_1.BlockMaterial_1_13; +import com.boydti.fawe.config.Settings; +import com.boydti.fawe.jnbt.anvil.BitArray4096; import com.boydti.fawe.object.collection.IterableThreadLocal; +import com.boydti.fawe.util.MathMan; +import com.boydti.fawe.util.TaskManager; import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BlockID; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; +import net.minecraft.server.v1_13_R2.Block; +import net.minecraft.server.v1_13_R2.Chunk; +import net.minecraft.server.v1_13_R2.ChunkCoordIntPair; +import net.minecraft.server.v1_13_R2.ChunkProviderServer; +import net.minecraft.server.v1_13_R2.ChunkSection; +import net.minecraft.server.v1_13_R2.DataBits; +import net.minecraft.server.v1_13_R2.DataPalette; +import net.minecraft.server.v1_13_R2.DataPaletteBlock; +import net.minecraft.server.v1_13_R2.DataPaletteLinear; +import net.minecraft.server.v1_13_R2.GameProfileSerializer; +import net.minecraft.server.v1_13_R2.IBlockData; import net.minecraft.server.v1_13_R2.WorldServer; import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_13_R2.CraftChunk; import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + import static com.google.common.base.Preconditions.checkNotNull; public class BukkitQueue extends SimpleCharQueueExtent { @@ -45,19 +72,177 @@ public class BukkitQueue extends SimpleCharQueueExtent { super.reset(); } - private static final IterableThreadLocal FULL_CHUNKS = new IterableThreadLocal() { - @Override - public BukkitFullChunk init() { - return new BukkitFullChunk(); - } - }; +// private static final IterableThreadLocal FULL_CHUNKS = new IterableThreadLocal() { +// @Override +// public BukkitFullChunk init() { +// return new BukkitFullChunk(); +// } +// }; @Override public IChunk create(boolean full) { - if (full) { - // TODO implement +// if (full) { +// //TODO implement // return FULL_CHUNKS.get(); - } +// } return new BukkitChunkHolder(); } + + /* + NMS fields + */ + public final static Field fieldBits; + public final static Field fieldPalette; + public final static Field fieldSize; + + public final static Field fieldFluidCount; + public final static Field fieldTickingBlockCount; + public final static Field fieldNonEmptyBlockCount; + + static { + try { + fieldSize = DataPaletteBlock.class.getDeclaredField("i"); + fieldSize.setAccessible(true); + fieldBits = DataPaletteBlock.class.getDeclaredField("a"); + fieldBits.setAccessible(true); + fieldPalette = DataPaletteBlock.class.getDeclaredField("h"); + fieldPalette.setAccessible(true); + + fieldFluidCount = ChunkSection.class.getDeclaredField("e"); + fieldFluidCount.setAccessible(true); + fieldTickingBlockCount = ChunkSection.class.getDeclaredField("tickingBlockCount"); + fieldTickingBlockCount.setAccessible(true); + fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount"); + fieldNonEmptyBlockCount.setAccessible(true); + } catch (RuntimeException e) { + throw e; + } catch (Throwable rethrow) { + rethrow.printStackTrace(); + throw new RuntimeException(rethrow); + } + } + + private static boolean PAPER = true; + + public Chunk ensureLoaded(int X, int Z) { + return ensureLoaded(nmsWorld, X, Z); + } + + public static Chunk ensureLoaded(net.minecraft.server.v1_13_R2.World nmsWorld, int X, int Z) { + ChunkProviderServer provider = (ChunkProviderServer) nmsWorld.getChunkProvider(); + Chunk nmsChunk = provider.chunks.get(ChunkCoordIntPair.a(X, Z)); + if (nmsChunk != null) { + return nmsChunk; + } + if (Fawe.isMainThread()) { + return nmsWorld.getChunkAt(X, Z); + } + if (PAPER) { + CraftWorld craftWorld = nmsWorld.getWorld(); + CompletableFuture future = craftWorld.getChunkAtAsync(X, Z, true); + try { + CraftChunk chunk = (CraftChunk) future.get(); + return chunk.getHandle(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } catch (Throwable e) { + System.out.println("Error, cannot load chunk async (paper not installed?)"); + PAPER = false; + } + } + // TODO optimize + return TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(X, Z)); + } + + /* + NMS conversion + */ + + public static ChunkSection newChunkSection(final int y2, final boolean flag, final char[] blocks) { + ChunkSection section = new ChunkSection(y2 << 4, flag); + if (blocks == null) { + return section; + } + final int[] blockToPalette = FaweCache.BLOCK_TO_PALETTE.get(); + final int[] paletteToBlock = FaweCache.PALETTE_TO_BLOCK.get(); + final long[] blockstates = FaweCache.BLOCK_STATES.get(); + final int[] blocksCopy = FaweCache.SECTION_BLOCKS.get(); + try { + int num_palette = 0; + int air = 0; + for (int i = 0; i < 4096; i++) { + char ordinal = blocks[i]; + switch (ordinal) { + case 0: + case BlockID.AIR: + case BlockID.CAVE_AIR: + case BlockID.VOID_AIR: + air++; + } + int palette = blockToPalette[ordinal]; + if (palette == Integer.MAX_VALUE) { + blockToPalette[ordinal] = palette = num_palette; + paletteToBlock[num_palette] = ordinal; + num_palette++; + } + blocksCopy[i] = palette; + } + + // BlockStates + int bitsPerEntry = MathMan.log2nlz(num_palette - 1); + if (Settings.IMP.PROTOCOL_SUPPORT_FIX || num_palette != 1) { + bitsPerEntry = Math.max(bitsPerEntry, 4); // Protocol support breaks <4 bits per entry + } else { + bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries + } + + final int blockBitArrayEnd = (bitsPerEntry * 4096) >> 6; + if (num_palette == 1) { + for (int i = 0; i < blockBitArrayEnd; i++) blockstates[i] = 0; + } else { + final BitArray4096 bitArray = new BitArray4096(blockstates, bitsPerEntry); + bitArray.fromRaw(blocksCopy); + } + + // set palette & data bits + final DataPaletteBlock dataPaletteBlocks = section.getBlocks(); + // private DataPalette h; + // protected DataBits a; + final long[] bits = Arrays.copyOfRange(blockstates, 0, blockBitArrayEnd); + final DataBits nmsBits = new DataBits(bitsPerEntry, 4096, bits); + final DataPalette palette; +// palette = new DataPaletteHash<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::d, GameProfileSerializer::a); + palette = new DataPaletteLinear<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::d); + + // set palette + for (int i = 0; i < num_palette; i++) { + final int ordinal = paletteToBlock[i]; + blockToPalette[ordinal] = Integer.MAX_VALUE; + final BlockState state = BlockTypes.states[ordinal]; + final IBlockData ibd = ((BlockMaterial_1_13) state.getMaterial()).getState(); + palette.a(ibd); + } + try { + fieldBits.set(dataPaletteBlocks, nmsBits); + fieldPalette.set(dataPaletteBlocks, palette); + fieldSize.set(dataPaletteBlocks, bitsPerEntry); + setCount(0, 4096 - air, section); + } catch (final IllegalAccessException | NoSuchFieldException e) { + throw new RuntimeException(e); + } + + return section; + } catch (final Throwable e){ + Arrays.fill(blockToPalette, Integer.MAX_VALUE); + throw e; + } + } + + public static void setCount(final int tickingBlockCount, final int nonEmptyBlockCount, final ChunkSection section) throws NoSuchFieldException, IllegalAccessException { + fieldFluidCount.set(section, 0); // TODO FIXME + fieldTickingBlockCount.set(section, tickingBlockCount); + fieldNonEmptyBlockCount.set(section, nonEmptyBlockCount); + } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/DelegateLock.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/DelegateLock.java new file mode 100644 index 000000000..59bfccd3b --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/DelegateLock.java @@ -0,0 +1,78 @@ +package com.boydti.fawe.bukkit.beta; + +import java.util.Collection; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +public class DelegateLock extends ReentrantLock { + private final ReentrantLock parent; + private volatile boolean modified; + + public DelegateLock(ReentrantLock parent) { + this.parent = parent; + } + + @Override + public void lock() { + modified = true; + parent.lock(); + } + + @Override + public synchronized void lockInterruptibly() throws InterruptedException { + parent.lockInterruptibly(); + } + + @Override + public synchronized boolean tryLock() { + return parent.tryLock(); + } + + @Override + public synchronized boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { + return parent.tryLock(timeout, unit); + } + + @Override + public synchronized void unlock() { + modified = true; + parent.unlock(); + this.notifyAll(); + } + + @Override + public synchronized Condition newCondition() { + return parent.newCondition(); + } + + @Override + public synchronized int getHoldCount() { + return parent.getHoldCount(); + } + + @Override + public synchronized boolean isHeldByCurrentThread() { + return parent.isHeldByCurrentThread(); + } + + @Override + public synchronized boolean isLocked() { + return parent.isLocked(); + } + + @Override + public synchronized boolean hasWaiters(Condition condition) { + return parent.hasWaiters(condition); + } + + @Override + public synchronized int getWaitQueueLength(Condition condition) { + return parent.getWaitQueueLength(condition); + } + + @Override + public synchronized String toString() { + return parent.toString(); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java index 8f0f188b6..0f86e37c7 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java @@ -70,7 +70,6 @@ public class BukkitQueue_1_13 extends BukkitQueue_0> 6; - if (num_palette == 1) { - for (int i = 0; i < blockBitArrayEnd; i++) blockstates[i] = 0; - } else { - final BitArray4096 bitArray = new BitArray4096(blockstates, bitsPerEntry); - bitArray.fromRaw(blocksCopy); - } - - // set palette & data bits - final DataPaletteBlock dataPaletteBlocks = section.getBlocks(); - // private DataPalette h; - // protected DataBits a; - final long[] bits = Arrays.copyOfRange(blockstates, 0, blockBitArrayEnd); - final DataBits nmsBits = new DataBits(bitsPerEntry, 4096, bits); - final DataPalette palette; -// palette = new DataPaletteHash<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::d, GameProfileSerializer::a); - palette = new DataPaletteLinear<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::d); - - // set palette - for (int i = 0; i < num_palette; i++) { - final int ordinal = paletteToBlock[i]; - blockToPalette[ordinal] = Integer.MAX_VALUE; - final BlockState state = BlockTypes.states[ordinal]; - final IBlockData ibd = ((BlockMaterial_1_13) state.getMaterial()).getState(); - palette.a(ibd); - } - try { - fieldBits.set(dataPaletteBlocks, nmsBits); - fieldPalette.set(dataPaletteBlocks, palette); - fieldSize.set(dataPaletteBlocks, bitsPerEntry); - setCount(0, 4096 - air, section); - } catch (final IllegalAccessException | NoSuchFieldException e) { - throw new RuntimeException(e); - } - - return section; - } catch (final Throwable e){ - Arrays.fill(blockToPalette, Integer.MAX_VALUE); - throw e; + blocksCopy[i] = palette; } + + // BlockStates + int bitsPerEntry = MathMan.log2nlz(num_palette - 1); + if (Settings.IMP.PROTOCOL_SUPPORT_FIX || num_palette != 1) { + bitsPerEntry = Math.max(bitsPerEntry, 4); // Protocol support breaks <4 bits per entry + } else { + bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries + } + + final int blockBitArrayEnd = (bitsPerEntry * 4096) >> 6; + if (num_palette == 1) { + for (int i = 0; i < blockBitArrayEnd; i++) blockstates[i] = 0; + } else { + final BitArray4096 bitArray = new BitArray4096(blockstates, bitsPerEntry); + bitArray.fromRaw(blocksCopy); + } + + // set palette & data bits + final DataPaletteBlock dataPaletteBlocks = section.getBlocks(); + // private DataPalette h; + // protected DataBits a; + final long[] bits = Arrays.copyOfRange(blockstates, 0, blockBitArrayEnd); + final DataBits nmsBits = new DataBits(bitsPerEntry, 4096, bits); + final DataPalette palette; +// palette = new DataPaletteHash<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::d, GameProfileSerializer::a); + palette = new DataPaletteLinear<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::d); + + // set palette + for (int i = 0; i < num_palette; i++) { + final int ordinal = paletteToBlock[i]; + blockToPalette[ordinal] = Integer.MAX_VALUE; + final BlockState state = BlockTypes.states[ordinal]; + final IBlockData ibd = ((BlockMaterial_1_13) state.getMaterial()).getState(); + palette.a(ibd); + } + try { + fieldBits.set(dataPaletteBlocks, nmsBits); + fieldPalette.set(dataPaletteBlocks, palette); + fieldSize.set(dataPaletteBlocks, bitsPerEntry); + setCount(0, 4096 - air, section); + } catch (final IllegalAccessException | NoSuchFieldException e) { + throw new RuntimeException(e); + } + + return section; + } catch (final Throwable e){ + Arrays.fill(blockToPalette, Integer.MAX_VALUE); + throw e; } } 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 6b4820e0c..7dba8eb3e 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java @@ -1,6 +1,7 @@ package com.boydti.fawe; import com.boydti.fawe.beta.Trimable; +import com.boydti.fawe.config.Settings; import com.boydti.fawe.jnbt.anvil.BitArray4096; import com.boydti.fawe.object.collection.IterableThreadLocal; import com.boydti.fawe.util.MathMan; @@ -11,6 +12,12 @@ import com.sk89q.worldedit.world.block.BlockTypes; import java.lang.reflect.Field; import java.util.*; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; public class FaweCache implements Trimable { public static final char[] EMPTY_CHAR_4096 = new char[4096]; @@ -326,4 +333,16 @@ public class FaweCache implements Trimable { if (clazz == null) clazz = EndTag.class; return new ListTag(clazz, list); } + + /* + Thread stuff + */ + public static ThreadPoolExecutor newBlockingExecutor() { + int nThreads = Settings.IMP.QUEUE.PARALLEL_THREADS; + ArrayBlockingQueue queue = new ArrayBlockingQueue<>(nThreads); + return new ThreadPoolExecutor(nThreads, nThreads, + 0L, TimeUnit.MILLISECONDS, queue + , Executors.defaultThreadFactory(), + new ThreadPoolExecutor.CallerRunsPolicy()); + } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java index b0f8ac231..1d9809d42 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java @@ -13,12 +13,12 @@ public class CharFilterBlock implements FilterBlock { private char[] section; @Override - public void init(IQueueExtent queue) { + public final void init(IQueueExtent queue) { this.queue = queue; } @Override - public void init(int X, int Z, IGetBlocks chunk) { + public final void init(int X, int Z, IGetBlocks chunk) { this.chunk = (CharGetBlocks) chunk; this.X = X; this.Z = Z; @@ -26,68 +26,85 @@ public class CharFilterBlock implements FilterBlock { this.zz = Z << 4; } - public void init(char[] section, int layer) { - this.section = section; - this.layer = layer; - this.yy = layer << 4; + // local + private int layer, index, x, y, z, xx, yy, zz, X, Z; + + public final void filter(CharGetBlocks blocks, Filter filter) { + for (int layer = 0; layer < 16; layer++) { + if (!blocks.hasSection(layer)) continue; + char[] arr = blocks.sections[layer].get(blocks, layer); + + this.section = arr; + this.layer = layer; + this.yy = layer << 4; + + for (y = 0, index = 0; y < 16; y++) { + for (z = 0; z < 16; z++) { + for (x = 0; x < 16; x++, index++) { + filter.applyBlock(this); + } + } + } + } } - // local - public int layer, index, x, y, z, xx, yy, zz, X, Z; - @Override - public int getX() { + public final int getX() { return xx + x; } @Override - public int getY() { + public final int getY() { return yy + y; } @Override - public int getZ() { + public final int getZ() { return zz + z; } @Override - public int getLocalX() { + public final int getLocalX() { return x; } @Override - public int getLocalY() { + public final int getLocalY() { return y; } @Override - public int getLocalZ() { + public final int getLocalZ() { return z; } @Override - public int getChunkX() { + public final int getChunkX() { return X; } @Override - public int getChunkZ() { + public final int getChunkZ() { return Z; } - @Override - public int getOrdinal() { + public final char getOrdinalChar() { return section[index]; } @Override - public BlockState getState() { + public final int getOrdinal() { + return section[index]; + } + + @Override + public final BlockState getState() { int ordinal = section[index]; return BlockTypes.states[ordinal]; } @Override - public BaseBlock getBaseBlock() { + public final BaseBlock getBaseBlock() { BlockState state = getState(); BlockMaterial material = state.getMaterial(); if (material.hasContainer()) { @@ -98,11 +115,11 @@ public class CharFilterBlock implements FilterBlock { } @Override - public CompoundTag getTag() { + public final CompoundTag getTag() { return null; } - public BlockState getOrdinalBelow() { + public final BlockState getOrdinalBelow() { if (y > 0) { return states[section[index - 256]]; } @@ -114,7 +131,7 @@ public class CharFilterBlock implements FilterBlock { return BlockTypes.__RESERVED__.getDefaultState(); } - public BlockState getStateAbove() { + public final BlockState getStateAbove() { if (y < 16) { return states[section[index + 256]]; } @@ -126,7 +143,7 @@ public class CharFilterBlock implements FilterBlock { return BlockTypes.__RESERVED__.getDefaultState(); } - public BlockState getStateRelativeY(int y) { + public final BlockState getStateRelativeY(int y) { int newY = this.y + y; int layerAdd = newY >> 4; switch (layerAdd) { @@ -180,7 +197,7 @@ public class CharFilterBlock implements FilterBlock { return BlockTypes.__RESERVED__.getDefaultState(); } - public BlockState getStateRelative(final int x, final int y, final int z) { + public final BlockState getStateRelative(final int x, final int y, final int z) { int newX = this.x + x; if (newX >> 4 == 0) { int newZ = this.z + z; @@ -189,7 +206,7 @@ public class CharFilterBlock implements FilterBlock { int layerAdd = newY >> 4; switch (layerAdd) { case 0: - return states[section[this.index + ((y << 8) | (z << 4) | x)]]; + return states[section[this.index + ((y << 8) + (z << 4) + x)]]; case 1: case 2: case 3: @@ -207,7 +224,7 @@ public class CharFilterBlock implements FilterBlock { case 15: { int newLayer = layer + layerAdd; if (newLayer < 16) { - int index = this.index + (((y & 15) << 8) | (z << 4) | x); + int index = ((newY & 15) << 8) + (newZ << 4) + newX; return states[chunk.sections[newLayer].get(chunk, newLayer, index)]; } break; @@ -229,7 +246,7 @@ public class CharFilterBlock implements FilterBlock { case -15: { int newLayer = layer + layerAdd; if (newLayer >= 0) { - int index = this.index + (((y & 15) << 8) | (z << 4) | x); + int index = ((newY & 15) << 8) + (newZ << 4) + newX; return states[chunk.sections[newLayer].get(chunk, newLayer, index)]; } break; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java index dcd9fbf6c..eb6afbd84 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java @@ -5,11 +5,16 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.function.Supplier; + /** * Represents a chunk in the queue {@link IQueueExtent} * Used for getting and setting blocks / biomes / entities */ -public interface IChunk extends Trimable { +public interface IChunk> extends Trimable, Callable { /** * Initialize at the location * @param extent @@ -22,6 +27,8 @@ public interface IChunk extends Trimable { int getZ(); + + /** * If the chunk is a delegate, returns it's paren'ts root * @return root IChunk @@ -36,16 +43,33 @@ public interface IChunk extends Trimable { boolean isEmpty(); /** - * Apply the queued async changes to the world - * @return false if applySync needs to run + * Spend time optimizing for apply
+ * default behavior: do nothing */ - boolean applyAsync(); + default void optimize() { + + } /** - * Apply the queued sync changes to the world - * @return true + * Apply the queued changes to the world
+ * The future returned may return another future
+ * To ensure completion keep calling {@link Future#get()} on each result + * @return Futures */ - boolean applySync(); + T call(); + + /** + * Call and join + * @throws ExecutionException + * @throws InterruptedException + */ + default void join() throws ExecutionException, InterruptedException { + T future = call(); + while (future != null) { + future = future.get(); + } + return; + } /* set - queues a change */ boolean setBiome(int x, int y, int z, BiomeType biome); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java index 62786336f..1cb14e2af 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java @@ -5,6 +5,9 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + /** * Delegate for IChunk * @param parent class @@ -67,13 +70,13 @@ public interface IDelegateChunk extends IChunk { } @Override - default boolean applySync() { - return getParent().applySync(); + default Future call() { + return getParent().call(); } @Override - default boolean applyAsync() { - return getParent().applyAsync(); + default void join() throws ExecutionException, InterruptedException { + getParent().join(); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IGetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IGetBlocks.java index bdddaff22..b49a8bb79 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IGetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IGetBlocks.java @@ -21,4 +21,8 @@ public interface IGetBlocks extends IBlocks, Trimable { boolean trim(boolean aggressive); void filter(Filter filter, FilterBlock block); + + default void optimize() { + + } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java index 4e6c35a01..7725810e5 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java @@ -34,7 +34,7 @@ public interface IQueueExtent extends Flushable, Trimable { * @param chunk * @return result */ - Future submit(IChunk chunk); + > T submit(IChunk chunk); default boolean setBlock(final int x, final int y, final int z, final BlockStateHolder state) { final IChunk chunk = getCachedChunk(x >> 4, z >> 4); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java index f06a4fd6d..f7dfd1bd8 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java @@ -12,4 +12,8 @@ public interface ISetBlocks extends IBlocks { boolean setBlock(int x, int y, int z, BlockStateHolder holder); boolean isEmpty(); + + default void optimize() { + + } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java index a78bfddc9..972a2cd15 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java @@ -1,6 +1,6 @@ package com.boydti.fawe.beta.implementation; -import com.boydti.fawe.Fawe; +import com.boydti.fawe.FaweCache; import com.boydti.fawe.beta.Filter; import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.beta.IChunk; @@ -8,9 +8,9 @@ import com.boydti.fawe.beta.IQueueExtent; import com.boydti.fawe.beta.Trimable; import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.collection.IterableThreadLocal; -import com.boydti.fawe.util.MathMan; -import com.boydti.fawe.util.TaskManager; +import com.boydti.fawe.util.MemUtil; import com.boydti.fawe.wrappers.WorldWrapper; +import com.google.common.util.concurrent.Futures; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.World; @@ -20,32 +20,36 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutorService; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinTask; import java.util.concurrent.Future; +import java.util.concurrent.ThreadPoolExecutor; /** * Class which handles all the queues {@link IQueueExtent} */ public abstract class QueueHandler implements Trimable { - private Map> chunkCache = new HashMap<>(); + private ForkJoinPool forkJoinPoolPrimary = new ForkJoinPool(); + private ForkJoinPool forkJoinPoolSecondary = new ForkJoinPool(); + private ThreadPoolExecutor blockingExecutor = FaweCache.newBlockingExecutor(); + private ConcurrentLinkedQueue syncTasks = new ConcurrentLinkedQueue(); - private IterableThreadLocal pool = new IterableThreadLocal() { + private Map> chunkCache = new HashMap<>(); + private IterableThreadLocal queuePool = new IterableThreadLocal() { @Override public IQueueExtent init() { return create(); } }; - public Future submit(IChunk chunk) { - if (Fawe.isMainThread()) { - if (!chunk.applyAsync()) { - chunk.applySync(); - } - return null; + public > T submit(IChunk chunk) { + if (MemUtil.isMemoryFree()) { +// return (T) forkJoinPoolSecondary.submit(chunk); } - // TODO return future - return null; + return (T) blockingExecutor.submit(chunk); + } /** @@ -73,7 +77,7 @@ public abstract class QueueHandler implements Trimable { public abstract IQueueExtent create(); public IQueueExtent getQueue(World world) { - IQueueExtent queue = pool.get(); + IQueueExtent queue = queuePool.get(); queue.init(getOrCreate(world)); return queue; } @@ -103,62 +107,63 @@ public abstract class QueueHandler implements Trimable { final Iterator chunksIter = chunks.iterator(); // Get a pool, to operate on the chunks in parallel - final ForkJoinPool pool = TaskManager.IMP.getPublicForkJoinPool(); final int size = Math.min(chunks.size(), Settings.IMP.QUEUE.PARALLEL_THREADS); - final ForkJoinTask[] tasks = new ForkJoinTask[size]; - + ForkJoinTask[] tasks = new ForkJoinTask[size]; for (int i = 0; i < size; i++) { - tasks[i] = pool.submit(new Runnable() { + tasks[i] = forkJoinPoolPrimary.submit(new Runnable() { @Override public void run() { Filter newFilter = filter.fork(); // Create a chunk that we will reuse/reset for each operation IQueueExtent queue = getQueue(world); - FilterBlock block = null; + synchronized (queue) { + FilterBlock block = null; - while (true) { - // Get the next chunk pos - final BlockVector2 pos; - synchronized (chunksIter) { - if (!chunksIter.hasNext()) return; - pos = chunksIter.next(); - } - final int X = pos.getX(); - final int Z = pos.getZ(); - // TODO create full - IChunk chunk = queue.getCachedChunk(X, Z); - // Initialize - chunk.init(queue, X, Z); - try { - if (!newFilter.appliesChunk(X, Z)) { - continue; + while (true) { + // Get the next chunk pos + final BlockVector2 pos; + synchronized (chunksIter) { + if (!chunksIter.hasNext()) break; + pos = chunksIter.next(); } - chunk = newFilter.applyChunk(chunk); + final int X = pos.getX(); + final int Z = pos.getZ(); + IChunk chunk = queue.getCachedChunk(X, Z); + // Initialize + chunk.init(queue, X, Z); + try { + if (!newFilter.appliesChunk(X, Z)) { + continue; + } + chunk = newFilter.applyChunk(chunk); - if (chunk == null) continue; + if (chunk == null) continue; - if (block == null) block = queue.initFilterBlock(); - chunk.filter(newFilter, block); + if (block == null) block = queue.initFilterBlock(); + chunk.filter(newFilter, block); - newFilter.finishChunk(chunk); + newFilter.finishChunk(chunk); - queue.submit(chunk); - } finally - { - if (filter != newFilter) { - synchronized (filter) { - newFilter.join(filter); + queue.submit(chunk); + } finally { + if (filter != newFilter) { + synchronized (filter) { + newFilter.join(filter); + } } } } + queue.flush(); } } }); } - - // Join the tasks - for (final ForkJoinTask task : tasks) { - task.join(); + // Join filters + for (int i = 0; i < tasks.length; i++) { + ForkJoinTask task = tasks[i]; + if (task != null) { + task.quietlyJoin(); + } } } } \ No newline at end of file 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 1e0809a75..9da4c0f3e 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 @@ -5,17 +5,12 @@ import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.IQueueExtent; import com.boydti.fawe.beta.implementation.holder.ReferenceChunk; import com.boydti.fawe.config.Settings; -import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.MemUtil; -import com.boydti.fawe.util.SetQueue; -import com.boydti.fawe.util.TaskManager; +import com.google.common.util.concurrent.Futures; import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; -import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutionException; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.ForkJoinTask; import java.util.concurrent.Future; import static com.google.common.base.Preconditions.checkNotNull; @@ -29,6 +24,7 @@ import static com.google.common.base.Preconditions.checkNotNull; public abstract class SingleThreadQueueExtent implements IQueueExtent { private WorldChunkCache cache; private Thread currentThread; + private ConcurrentLinkedQueue submissions = new ConcurrentLinkedQueue<>(); /** * Safety check to ensure that the thread being used matches the one being initialized on @@ -66,7 +62,7 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { */ @Override public synchronized void init(final WorldChunkCache cache) { - if (cache != null) { + if (this.cache != null) { reset(); } currentThread = Thread.currentThread(); @@ -83,19 +79,17 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { private static final ConcurrentLinkedQueue CHUNK_POOL = new ConcurrentLinkedQueue<>(); @Override - public Future submit(final IChunk chunk) { + public > T submit(final IChunk chunk) { if (chunk.isEmpty()) { CHUNK_POOL.add(chunk); - return null; + return (T) (Future) Futures.immediateFuture(null); } + if (Fawe.isMainThread()) { - if (!chunk.applyAsync()) { - chunk.applySync(); - } - return null; + return chunk.call(); } - QueueHandler handler = Fawe.get().getQueueHandler(); - return handler.submit(chunk); + + return Fawe.get().getQueueHandler().submit(chunk); } @Override @@ -107,6 +101,13 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { lastPair = Long.MAX_VALUE; return chunks.isEmpty(); } + if (!submissions.isEmpty()) { + if (aggressive) { + pollSubmissions(0, aggressive); + } else { + pollSubmissions(Settings.IMP.QUEUE.PARALLEL_THREADS, aggressive); + } + } synchronized (this) { return currentThread == null; } @@ -121,7 +122,10 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { */ private IChunk poolOrCreate(final int X, final int Z) { IChunk next = CHUNK_POOL.poll(); - if (next == null) next = create(false); + if (next == null) { + System.out.println("Create"); + next = create(false); + } next.init(this, X, Z); return next; } @@ -145,10 +149,19 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { checkThread(); final int size = chunks.size(); - if (size > Settings.IMP.QUEUE.TARGET_SIZE || MemUtil.isMemoryLimited()) { - if (size > Settings.IMP.QUEUE.PARALLEL_THREADS * 2 + 16) { - chunk = chunks.removeFirst(); - submit(chunk); + boolean lowMem = MemUtil.isMemoryLimited(); + if (lowMem || size > Settings.IMP.QUEUE.TARGET_SIZE) { + chunk = chunks.removeFirst(); + Future future = submit(chunk); + if (future != null && !future.isDone()) { + int targetSize; + if (lowMem) { + targetSize = Settings.IMP.QUEUE.PARALLEL_THREADS; + } else { + targetSize = Settings.IMP.QUEUE.TARGET_SIZE; + } + pollSubmissions(targetSize, true); + submissions.add(future); } } chunk = poolOrCreate(X, Z); @@ -161,27 +174,59 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { return chunk; } + private void pollSubmissions(int targetSize, boolean aggressive) { + int overflow = submissions.size() - targetSize; + if (aggressive) { + for (int i = 0; i < overflow; i++) { + Future first = submissions.poll(); + try { + while ((first = (Future) first.get()) != null) ; + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + } + } else { + for (int i = 0; i < overflow; i++) { + Future next = submissions.peek(); + while (next != null) { + if (next.isDone()) { + try { + next = (Future) next.get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + } else { + return; + } + } + submissions.poll(); + } + } + } + @Override public synchronized void flush() { checkThread(); if (!chunks.isEmpty()) { - final Future[] tasks = new ForkJoinTask[chunks.size()]; - int i = 0; - for (final IChunk chunk : chunks.values()) { - tasks[i++] = submit(chunk); - } - chunks.clear(); - for (final Future task : tasks) { - if (task != null) { - try { - task.get(); - } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); - throw new RuntimeException(e); + if (MemUtil.isMemoryLimited()) { + for (IChunk chunk : chunks.values()) { + Future future = submit(chunk); + if (future != null && !future.isDone()) { + pollSubmissions(Settings.IMP.QUEUE.PARALLEL_THREADS, true); + submissions.add(future); + } + } + } else { + for (final IChunk chunk : chunks.values()) { + Future future = submit(chunk); + if (future != null && !future.isDone()) { + submissions.add(future); } } } + chunks.clear(); } + pollSubmissions(0, true); reset(); } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java index 1bed28997..fede5719c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java @@ -22,18 +22,7 @@ public abstract class CharGetBlocks extends CharBlocks implements IGetBlocks { @Override public void filter(Filter filter, FilterBlock block) { CharFilterBlock b = (CharFilterBlock) block; - for (int layer = 0; layer < 16; layer++) { - if (!hasSection(layer)) continue; - char[] arr = sections[layer].get(this, layer); - b.init(arr, layer); - for (b.y = 0, b.index = 0; b.y < 16; b.y++) { - for (b.z = 0; b.z < 16; b.z++) { - for (b.x = 0; b.x < 16; b.x++, b.index++) { - filter.applyBlock(b); - } - } - } - } + b.filter(this, filter); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java index efed7128a..7ff757113 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java @@ -1,10 +1,8 @@ package com.boydti.fawe.beta.implementation.holder; -import com.boydti.fawe.beta.CharFilterBlock; import com.boydti.fawe.beta.Filter; import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.beta.IQueueExtent; -import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks; import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.IGetBlocks; @@ -22,7 +20,7 @@ import java.util.function.Supplier; /** * Abstract IChunk class that implements basic get/set blocks */ -public abstract class ChunkHolder implements IChunk, Supplier { +public abstract class ChunkHolder implements IChunk, Supplier { private IGetBlocks get; private ISetBlocks set; private IBlockDelegate delegate; @@ -40,7 +38,7 @@ public abstract class ChunkHolder implements IChunk, Supplier { @Override public void filter(Filter filter, FilterBlock block) { block.init(X, Z, get); - IGetBlocks get = cachedGet(); + IGetBlocks get = getOrCreateGet(); get.filter(filter, block); } @@ -73,12 +71,12 @@ public abstract class ChunkHolder implements IChunk, Supplier { return set == null || set.isEmpty(); } - public final IGetBlocks cachedGet() { + public final IGetBlocks getOrCreateGet() { if (get == null) get = newGet(); return get; } - public final ISetBlocks cachedSet() { + public final ISetBlocks getOrCreateSet() { if (set == null) set = set(); return set; } @@ -95,6 +93,13 @@ public abstract class ChunkHolder implements IChunk, Supplier { return get(); } + @Override + public void optimize() { + if (set != null) { + set.optimize(); + } + } + @Override public void init(IQueueExtent extent, final int X, final int Z) { this.extent = extent; @@ -163,35 +168,35 @@ public abstract class ChunkHolder implements IChunk, Supplier { public static final IBlockDelegate NULL = new IBlockDelegate() { @Override public boolean setBiome(final ChunkHolder chunk, final int x, final int y, final int z, final BiomeType biome) { - chunk.cachedSet(); + chunk.getOrCreateSet(); chunk.delegate = SET; return chunk.setBiome(x, y, z, biome); } @Override public boolean setBlock(final ChunkHolder chunk, final int x, final int y, final int z, final BlockStateHolder block) { - chunk.cachedSet(); + chunk.getOrCreateSet(); chunk.delegate = SET; return chunk.setBlock(x, y, z, block); } @Override public BiomeType getBiome(final ChunkHolder chunk, final int x, final int z) { - chunk.cachedGet(); + chunk.getOrCreateGet(); chunk.delegate = GET; return chunk.getBiome(x, z); } @Override public BlockState getBlock(final ChunkHolder chunk, final int x, final int y, final int z) { - chunk.cachedGet(); + chunk.getOrCreateGet(); chunk.delegate = GET; return chunk.getBlock(x, y, z); } @Override public BaseBlock getFullBlock(final ChunkHolder chunk, final int x, final int y, final int z) { - chunk.cachedGet(); + chunk.getOrCreateGet(); chunk.delegate = GET; return chunk.getFullBlock(x, y, z); } @@ -200,14 +205,14 @@ public abstract class ChunkHolder implements IChunk, Supplier { public static final IBlockDelegate GET = new IBlockDelegate() { @Override public boolean setBiome(final ChunkHolder chunk, final int x, final int y, final int z, final BiomeType biome) { - chunk.cachedSet(); + chunk.getOrCreateSet(); chunk.delegate = BOTH; return chunk.setBiome(x, y, z, biome); } @Override public boolean setBlock(final ChunkHolder chunk, final int x, final int y, final int z, final BlockStateHolder block) { - chunk.cachedSet(); + chunk.getOrCreateSet(); chunk.delegate = BOTH; return chunk.setBlock(x, y, z, block); } @@ -241,21 +246,21 @@ public abstract class ChunkHolder implements IChunk, Supplier { @Override public BiomeType getBiome(final ChunkHolder chunk, final int x, final int z) { - chunk.cachedGet(); + chunk.getOrCreateGet(); chunk.delegate = BOTH; return chunk.getBiome(x, z); } @Override public BlockState getBlock(final ChunkHolder chunk, final int x, final int y, final int z) { - chunk.cachedGet(); + chunk.getOrCreateGet(); chunk.delegate = BOTH; return chunk.getBlock(x, y, z); } @Override public BaseBlock getFullBlock(final ChunkHolder chunk, final int x, final int y, final int z) { - chunk.cachedGet(); + chunk.getOrCreateGet(); chunk.delegate = BOTH; return chunk.getFullBlock(x, y, z); } 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 3fefa6ab9..695c730fb 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 @@ -281,7 +281,10 @@ public class RegionCommands extends MethodCommands { QueueHandler queueHandler = Fawe.get().getQueueHandler(); World world = player.getWorld(); CountFilter filter = new CountFilter(); + long start = System.currentTimeMillis(); queueHandler.apply(world, region, filter); + long diff = System.currentTimeMillis() - start; + System.out.println(diff); } @Command( diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockID.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockID.java index 82f5c2979..1e9c5afa4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockID.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockID.java @@ -3,570 +3,570 @@ package com.sk89q.worldedit.world.block; public class BlockID { // Used for switch statements on blocks public static final int __RESERVED__ = 0; - public static final int ACACIA_BUTTON = 1; - public static final int ACACIA_DOOR = 2; - public static final int ACACIA_FENCE = 3; - public static final int ACACIA_FENCE_GATE = 4; - public static final int ACACIA_LEAVES = 5; - public static final int ACACIA_LOG = 6; - public static final int ACACIA_PLANKS = 7; - public static final int ACACIA_PRESSURE_PLATE = 8; - public static final int ACACIA_SAPLING = 9; - public static final int ACACIA_SLAB = 10; - public static final int ACACIA_STAIRS = 11; - public static final int ACACIA_TRAPDOOR = 12; - public static final int ACACIA_WOOD = 13; - public static final int ACTIVATOR_RAIL = 14; - public static final int AIR = 15; - public static final int ALLIUM = 16; - public static final int ANDESITE = 17; - public static final int ANVIL = 18; - public static final int ATTACHED_MELON_STEM = 19; - public static final int ATTACHED_PUMPKIN_STEM = 20; - public static final int AZURE_BLUET = 21; - public static final int BARRIER = 22; - public static final int BEACON = 23; - public static final int BEDROCK = 24; - public static final int BEETROOTS = 25; - public static final int BIRCH_BUTTON = 26; - public static final int BIRCH_DOOR = 27; - public static final int BIRCH_FENCE = 28; - public static final int BIRCH_FENCE_GATE = 29; - public static final int BIRCH_LEAVES = 30; - public static final int BIRCH_LOG = 31; - public static final int BIRCH_PLANKS = 32; - public static final int BIRCH_PRESSURE_PLATE = 33; - public static final int BIRCH_SAPLING = 34; - public static final int BIRCH_SLAB = 35; - public static final int BIRCH_STAIRS = 36; - public static final int BIRCH_TRAPDOOR = 37; - public static final int BIRCH_WOOD = 38; - public static final int BLACK_BANNER = 39; - public static final int BLACK_BED = 40; - public static final int BLACK_CARPET = 41; - public static final int BLACK_CONCRETE = 42; - public static final int BLACK_CONCRETE_POWDER = 43; - public static final int BLACK_GLAZED_TERRACOTTA = 44; - public static final int BLACK_SHULKER_BOX = 45; - public static final int BLACK_STAINED_GLASS = 46; - public static final int BLACK_STAINED_GLASS_PANE = 47; - public static final int BLACK_TERRACOTTA = 48; - public static final int BLACK_WALL_BANNER = 49; - public static final int BLACK_WOOL = 50; - public static final int BLUE_BANNER = 51; - public static final int BLUE_BED = 52; - public static final int BLUE_CARPET = 53; - public static final int BLUE_CONCRETE = 54; - public static final int BLUE_CONCRETE_POWDER = 55; - public static final int BLUE_GLAZED_TERRACOTTA = 56; - public static final int BLUE_ICE = 57; - public static final int BLUE_ORCHID = 58; - public static final int BLUE_SHULKER_BOX = 59; - public static final int BLUE_STAINED_GLASS = 60; - public static final int BLUE_STAINED_GLASS_PANE = 61; - public static final int BLUE_TERRACOTTA = 62; - public static final int BLUE_WALL_BANNER = 63; - public static final int BLUE_WOOL = 64; - public static final int BONE_BLOCK = 65; - public static final int BOOKSHELF = 66; - public static final int BRAIN_CORAL = 67; - public static final int BRAIN_CORAL_BLOCK = 68; - public static final int BRAIN_CORAL_FAN = 69; - public static final int BRAIN_CORAL_WALL_FAN = 70; - public static final int BREWING_STAND = 71; - public static final int BRICK_SLAB = 72; - public static final int BRICK_STAIRS = 73; - public static final int BRICKS = 74; - public static final int BROWN_BANNER = 75; - public static final int BROWN_BED = 76; - public static final int BROWN_CARPET = 77; - public static final int BROWN_CONCRETE = 78; - public static final int BROWN_CONCRETE_POWDER = 79; - public static final int BROWN_GLAZED_TERRACOTTA = 80; - public static final int BROWN_MUSHROOM = 81; - public static final int BROWN_MUSHROOM_BLOCK = 82; - public static final int BROWN_SHULKER_BOX = 83; - public static final int BROWN_STAINED_GLASS = 84; - public static final int BROWN_STAINED_GLASS_PANE = 85; - public static final int BROWN_TERRACOTTA = 86; - public static final int BROWN_WALL_BANNER = 87; - public static final int BROWN_WOOL = 88; - public static final int BUBBLE_COLUMN = 89; - public static final int BUBBLE_CORAL = 90; - public static final int BUBBLE_CORAL_BLOCK = 91; - public static final int BUBBLE_CORAL_FAN = 92; - public static final int BUBBLE_CORAL_WALL_FAN = 93; - public static final int CACTUS = 94; - public static final int CAKE = 95; - public static final int CARROTS = 96; - public static final int CARVED_PUMPKIN = 97; - public static final int CAULDRON = 98; - public static final int CAVE_AIR = 99; - public static final int CHAIN_COMMAND_BLOCK = 100; - public static final int CHEST = 101; - public static final int CHIPPED_ANVIL = 102; - public static final int CHISELED_QUARTZ_BLOCK = 103; - public static final int CHISELED_RED_SANDSTONE = 104; - public static final int CHISELED_SANDSTONE = 105; - public static final int CHISELED_STONE_BRICKS = 106; - public static final int CHORUS_FLOWER = 107; - public static final int CHORUS_PLANT = 108; - public static final int CLAY = 109; - public static final int COAL_BLOCK = 110; - public static final int COAL_ORE = 111; - public static final int COARSE_DIRT = 112; - public static final int COBBLESTONE = 113; - public static final int COBBLESTONE_SLAB = 114; - public static final int COBBLESTONE_STAIRS = 115; - public static final int COBBLESTONE_WALL = 116; - public static final int COBWEB = 117; - public static final int COCOA = 118; - public static final int COMMAND_BLOCK = 119; - public static final int COMPARATOR = 120; - public static final int CONDUIT = 121; - public static final int CRACKED_STONE_BRICKS = 122; - public static final int CRAFTING_TABLE = 123; - public static final int CREEPER_HEAD = 124; - public static final int CREEPER_WALL_HEAD = 125; - public static final int CUT_RED_SANDSTONE = 126; - public static final int CUT_SANDSTONE = 127; - public static final int CYAN_BANNER = 128; - public static final int CYAN_BED = 129; - public static final int CYAN_CARPET = 130; - public static final int CYAN_CONCRETE = 131; - public static final int CYAN_CONCRETE_POWDER = 132; - public static final int CYAN_GLAZED_TERRACOTTA = 133; - public static final int CYAN_SHULKER_BOX = 134; - public static final int CYAN_STAINED_GLASS = 135; - public static final int CYAN_STAINED_GLASS_PANE = 136; - public static final int CYAN_TERRACOTTA = 137; - public static final int CYAN_WALL_BANNER = 138; - public static final int CYAN_WOOL = 139; - public static final int DAMAGED_ANVIL = 140; - public static final int DANDELION = 141; - public static final int DARK_OAK_BUTTON = 142; - public static final int DARK_OAK_DOOR = 143; - public static final int DARK_OAK_FENCE = 144; - public static final int DARK_OAK_FENCE_GATE = 145; - public static final int DARK_OAK_LEAVES = 146; - public static final int DARK_OAK_LOG = 147; - public static final int DARK_OAK_PLANKS = 148; - public static final int DARK_OAK_PRESSURE_PLATE = 149; - public static final int DARK_OAK_SAPLING = 150; - public static final int DARK_OAK_SLAB = 151; - public static final int DARK_OAK_STAIRS = 152; - public static final int DARK_OAK_TRAPDOOR = 153; - public static final int DARK_OAK_WOOD = 154; - public static final int DARK_PRISMARINE = 155; - public static final int DARK_PRISMARINE_SLAB = 156; - public static final int DARK_PRISMARINE_STAIRS = 157; - public static final int DAYLIGHT_DETECTOR = 158; - public static final int DEAD_BRAIN_CORAL = 159; - public static final int DEAD_BRAIN_CORAL_BLOCK = 160; - public static final int DEAD_BRAIN_CORAL_FAN = 161; - public static final int DEAD_BRAIN_CORAL_WALL_FAN = 162; - public static final int DEAD_BUBBLE_CORAL = 163; - public static final int DEAD_BUBBLE_CORAL_BLOCK = 164; - public static final int DEAD_BUBBLE_CORAL_FAN = 165; - public static final int DEAD_BUBBLE_CORAL_WALL_FAN = 166; - public static final int DEAD_BUSH = 167; - public static final int DEAD_FIRE_CORAL = 168; - public static final int DEAD_FIRE_CORAL_BLOCK = 169; - public static final int DEAD_FIRE_CORAL_FAN = 170; - public static final int DEAD_FIRE_CORAL_WALL_FAN = 171; - public static final int DEAD_HORN_CORAL = 172; - public static final int DEAD_HORN_CORAL_BLOCK = 173; - public static final int DEAD_HORN_CORAL_FAN = 174; - public static final int DEAD_HORN_CORAL_WALL_FAN = 175; - public static final int DEAD_TUBE_CORAL = 176; - public static final int DEAD_TUBE_CORAL_BLOCK = 177; - public static final int DEAD_TUBE_CORAL_FAN = 178; - public static final int DEAD_TUBE_CORAL_WALL_FAN = 179; - public static final int DETECTOR_RAIL = 180; - public static final int DIAMOND_BLOCK = 181; - public static final int DIAMOND_ORE = 182; - public static final int DIORITE = 183; - public static final int DIRT = 184; - public static final int DISPENSER = 185; - public static final int DRAGON_EGG = 186; - public static final int DRAGON_HEAD = 187; - public static final int DRAGON_WALL_HEAD = 188; - public static final int DRIED_KELP_BLOCK = 189; - public static final int DROPPER = 190; - public static final int EMERALD_BLOCK = 191; - public static final int EMERALD_ORE = 192; - public static final int ENCHANTING_TABLE = 193; - public static final int END_GATEWAY = 194; - public static final int END_PORTAL = 195; - public static final int END_PORTAL_FRAME = 196; - public static final int END_ROD = 197; - public static final int END_STONE = 198; - public static final int END_STONE_BRICKS = 199; - public static final int ENDER_CHEST = 200; - public static final int FARMLAND = 201; - public static final int FERN = 202; - public static final int FIRE = 203; - public static final int FIRE_CORAL = 204; - public static final int FIRE_CORAL_BLOCK = 205; - public static final int FIRE_CORAL_FAN = 206; - public static final int FIRE_CORAL_WALL_FAN = 207; - public static final int FLOWER_POT = 208; - public static final int FROSTED_ICE = 209; - public static final int FURNACE = 210; - public static final int GLASS = 211; - public static final int GLASS_PANE = 212; - public static final int GLOWSTONE = 213; - public static final int GOLD_BLOCK = 214; - public static final int GOLD_ORE = 215; - public static final int GRANITE = 216; - public static final int GRASS = 217; - public static final int GRASS_BLOCK = 218; - public static final int GRASS_PATH = 219; - public static final int GRAVEL = 220; - public static final int GRAY_BANNER = 221; - public static final int GRAY_BED = 222; - public static final int GRAY_CARPET = 223; - public static final int GRAY_CONCRETE = 224; - public static final int GRAY_CONCRETE_POWDER = 225; - public static final int GRAY_GLAZED_TERRACOTTA = 226; - public static final int GRAY_SHULKER_BOX = 227; - public static final int GRAY_STAINED_GLASS = 228; - public static final int GRAY_STAINED_GLASS_PANE = 229; - public static final int GRAY_TERRACOTTA = 230; - public static final int GRAY_WALL_BANNER = 231; - public static final int GRAY_WOOL = 232; - public static final int GREEN_BANNER = 233; - public static final int GREEN_BED = 234; - public static final int GREEN_CARPET = 235; - public static final int GREEN_CONCRETE = 236; - public static final int GREEN_CONCRETE_POWDER = 237; - public static final int GREEN_GLAZED_TERRACOTTA = 238; - public static final int GREEN_SHULKER_BOX = 239; - public static final int GREEN_STAINED_GLASS = 240; - public static final int GREEN_STAINED_GLASS_PANE = 241; - public static final int GREEN_TERRACOTTA = 242; - public static final int GREEN_WALL_BANNER = 243; - public static final int GREEN_WOOL = 244; - public static final int HAY_BLOCK = 245; - public static final int HEAVY_WEIGHTED_PRESSURE_PLATE = 246; - public static final int HOPPER = 247; - public static final int HORN_CORAL = 248; - public static final int HORN_CORAL_BLOCK = 249; - public static final int HORN_CORAL_FAN = 250; - public static final int HORN_CORAL_WALL_FAN = 251; - public static final int ICE = 252; - public static final int INFESTED_CHISELED_STONE_BRICKS = 253; - public static final int INFESTED_COBBLESTONE = 254; - public static final int INFESTED_CRACKED_STONE_BRICKS = 255; - public static final int INFESTED_MOSSY_STONE_BRICKS = 256; - public static final int INFESTED_STONE = 257; - public static final int INFESTED_STONE_BRICKS = 258; - public static final int IRON_BARS = 259; - public static final int IRON_BLOCK = 260; - public static final int IRON_DOOR = 261; - public static final int IRON_ORE = 262; - public static final int IRON_TRAPDOOR = 263; - public static final int JACK_O_LANTERN = 264; - public static final int JUKEBOX = 265; - public static final int JUNGLE_BUTTON = 266; - public static final int JUNGLE_DOOR = 267; - public static final int JUNGLE_FENCE = 268; - public static final int JUNGLE_FENCE_GATE = 269; - public static final int JUNGLE_LEAVES = 270; - public static final int JUNGLE_LOG = 271; - public static final int JUNGLE_PLANKS = 272; - public static final int JUNGLE_PRESSURE_PLATE = 273; - public static final int JUNGLE_SAPLING = 274; - public static final int JUNGLE_SLAB = 275; - public static final int JUNGLE_STAIRS = 276; - public static final int JUNGLE_TRAPDOOR = 277; - public static final int JUNGLE_WOOD = 278; - public static final int KELP = 279; - public static final int KELP_PLANT = 280; - public static final int LADDER = 281; - public static final int LAPIS_BLOCK = 282; - public static final int LAPIS_ORE = 283; - public static final int LARGE_FERN = 284; - public static final int LAVA = 285; - public static final int LEVER = 286; - public static final int LIGHT_BLUE_BANNER = 287; - public static final int LIGHT_BLUE_BED = 288; - public static final int LIGHT_BLUE_CARPET = 289; - public static final int LIGHT_BLUE_CONCRETE = 290; - public static final int LIGHT_BLUE_CONCRETE_POWDER = 291; - public static final int LIGHT_BLUE_GLAZED_TERRACOTTA = 292; - public static final int LIGHT_BLUE_SHULKER_BOX = 293; - public static final int LIGHT_BLUE_STAINED_GLASS = 294; - public static final int LIGHT_BLUE_STAINED_GLASS_PANE = 295; - public static final int LIGHT_BLUE_TERRACOTTA = 296; - public static final int LIGHT_BLUE_WALL_BANNER = 297; - public static final int LIGHT_BLUE_WOOL = 298; - public static final int LIGHT_GRAY_BANNER = 299; - public static final int LIGHT_GRAY_BED = 300; - public static final int LIGHT_GRAY_CARPET = 301; - public static final int LIGHT_GRAY_CONCRETE = 302; - public static final int LIGHT_GRAY_CONCRETE_POWDER = 303; - public static final int LIGHT_GRAY_GLAZED_TERRACOTTA = 304; - public static final int LIGHT_GRAY_SHULKER_BOX = 305; - public static final int LIGHT_GRAY_STAINED_GLASS = 306; - public static final int LIGHT_GRAY_STAINED_GLASS_PANE = 307; - public static final int LIGHT_GRAY_TERRACOTTA = 308; - public static final int LIGHT_GRAY_WALL_BANNER = 309; - public static final int LIGHT_GRAY_WOOL = 310; - public static final int LIGHT_WEIGHTED_PRESSURE_PLATE = 311; - public static final int LILAC = 312; - public static final int LILY_PAD = 313; - public static final int LIME_BANNER = 314; - public static final int LIME_BED = 315; - public static final int LIME_CARPET = 316; - public static final int LIME_CONCRETE = 317; - public static final int LIME_CONCRETE_POWDER = 318; - public static final int LIME_GLAZED_TERRACOTTA = 319; - public static final int LIME_SHULKER_BOX = 320; - public static final int LIME_STAINED_GLASS = 321; - public static final int LIME_STAINED_GLASS_PANE = 322; - public static final int LIME_TERRACOTTA = 323; - public static final int LIME_WALL_BANNER = 324; - public static final int LIME_WOOL = 325; - public static final int MAGENTA_BANNER = 326; - public static final int MAGENTA_BED = 327; - public static final int MAGENTA_CARPET = 328; - public static final int MAGENTA_CONCRETE = 329; - public static final int MAGENTA_CONCRETE_POWDER = 330; - public static final int MAGENTA_GLAZED_TERRACOTTA = 331; - public static final int MAGENTA_SHULKER_BOX = 332; - public static final int MAGENTA_STAINED_GLASS = 333; - public static final int MAGENTA_STAINED_GLASS_PANE = 334; - public static final int MAGENTA_TERRACOTTA = 335; - public static final int MAGENTA_WALL_BANNER = 336; - public static final int MAGENTA_WOOL = 337; - public static final int MAGMA_BLOCK = 338; - public static final int MELON = 339; - public static final int MELON_STEM = 340; - public static final int MOSSY_COBBLESTONE = 341; - public static final int MOSSY_COBBLESTONE_WALL = 342; - public static final int MOSSY_STONE_BRICKS = 343; - public static final int MOVING_PISTON = 344; - public static final int MUSHROOM_STEM = 345; - public static final int MYCELIUM = 346; - public static final int NETHER_BRICK_FENCE = 347; - public static final int NETHER_BRICK_SLAB = 348; - public static final int NETHER_BRICK_STAIRS = 349; - public static final int NETHER_BRICKS = 350; - public static final int NETHER_PORTAL = 351; - public static final int NETHER_QUARTZ_ORE = 352; - public static final int NETHER_WART = 353; - public static final int NETHER_WART_BLOCK = 354; - public static final int NETHERRACK = 355; - public static final int NOTE_BLOCK = 356; - public static final int OAK_BUTTON = 357; - public static final int OAK_DOOR = 358; - public static final int OAK_FENCE = 359; - public static final int OAK_FENCE_GATE = 360; - public static final int OAK_LEAVES = 361; - public static final int OAK_LOG = 362; - public static final int OAK_PLANKS = 363; - public static final int OAK_PRESSURE_PLATE = 364; - public static final int OAK_SAPLING = 365; - public static final int OAK_SLAB = 366; - public static final int OAK_STAIRS = 367; - public static final int OAK_TRAPDOOR = 368; - public static final int OAK_WOOD = 369; - public static final int OBSERVER = 370; - public static final int OBSIDIAN = 371; - public static final int ORANGE_BANNER = 372; - public static final int ORANGE_BED = 373; - public static final int ORANGE_CARPET = 374; - public static final int ORANGE_CONCRETE = 375; - public static final int ORANGE_CONCRETE_POWDER = 376; - public static final int ORANGE_GLAZED_TERRACOTTA = 377; - public static final int ORANGE_SHULKER_BOX = 378; - public static final int ORANGE_STAINED_GLASS = 379; - public static final int ORANGE_STAINED_GLASS_PANE = 380; - public static final int ORANGE_TERRACOTTA = 381; - public static final int ORANGE_TULIP = 382; - public static final int ORANGE_WALL_BANNER = 383; - public static final int ORANGE_WOOL = 384; - public static final int OXEYE_DAISY = 385; - public static final int PACKED_ICE = 386; - public static final int PEONY = 387; - public static final int PETRIFIED_OAK_SLAB = 388; - public static final int PINK_BANNER = 389; - public static final int PINK_BED = 390; - public static final int PINK_CARPET = 391; - public static final int PINK_CONCRETE = 392; - public static final int PINK_CONCRETE_POWDER = 393; - public static final int PINK_GLAZED_TERRACOTTA = 394; - public static final int PINK_SHULKER_BOX = 395; - public static final int PINK_STAINED_GLASS = 396; - public static final int PINK_STAINED_GLASS_PANE = 397; - public static final int PINK_TERRACOTTA = 398; - public static final int PINK_TULIP = 399; - public static final int PINK_WALL_BANNER = 400; - public static final int PINK_WOOL = 401; - public static final int PISTON = 402; - public static final int PISTON_HEAD = 403; - public static final int PLAYER_HEAD = 404; - public static final int PLAYER_WALL_HEAD = 405; - public static final int PODZOL = 406; - public static final int POLISHED_ANDESITE = 407; - public static final int POLISHED_DIORITE = 408; - public static final int POLISHED_GRANITE = 409; - public static final int POPPY = 410; - public static final int POTATOES = 411; - public static final int POTTED_ACACIA_SAPLING = 412; - public static final int POTTED_ALLIUM = 413; - public static final int POTTED_AZURE_BLUET = 414; - public static final int POTTED_BIRCH_SAPLING = 415; - public static final int POTTED_BLUE_ORCHID = 416; - public static final int POTTED_BROWN_MUSHROOM = 417; - public static final int POTTED_CACTUS = 418; - public static final int POTTED_DANDELION = 419; - public static final int POTTED_DARK_OAK_SAPLING = 420; - public static final int POTTED_DEAD_BUSH = 421; - public static final int POTTED_FERN = 422; - public static final int POTTED_JUNGLE_SAPLING = 423; - public static final int POTTED_OAK_SAPLING = 424; - public static final int POTTED_ORANGE_TULIP = 425; - public static final int POTTED_OXEYE_DAISY = 426; - public static final int POTTED_PINK_TULIP = 427; - public static final int POTTED_POPPY = 428; - public static final int POTTED_RED_MUSHROOM = 429; - public static final int POTTED_RED_TULIP = 430; - public static final int POTTED_SPRUCE_SAPLING = 431; - public static final int POTTED_WHITE_TULIP = 432; - public static final int POWERED_RAIL = 433; - public static final int PRISMARINE = 434; - public static final int PRISMARINE_BRICK_SLAB = 435; - public static final int PRISMARINE_BRICK_STAIRS = 436; - public static final int PRISMARINE_BRICKS = 437; - public static final int PRISMARINE_SLAB = 438; - public static final int PRISMARINE_STAIRS = 439; - public static final int PUMPKIN = 440; - public static final int PUMPKIN_STEM = 441; - public static final int PURPLE_BANNER = 442; - public static final int PURPLE_BED = 443; - public static final int PURPLE_CARPET = 444; - public static final int PURPLE_CONCRETE = 445; - public static final int PURPLE_CONCRETE_POWDER = 446; - public static final int PURPLE_GLAZED_TERRACOTTA = 447; - public static final int PURPLE_SHULKER_BOX = 448; - public static final int PURPLE_STAINED_GLASS = 449; - public static final int PURPLE_STAINED_GLASS_PANE = 450; - public static final int PURPLE_TERRACOTTA = 451; - public static final int PURPLE_WALL_BANNER = 452; - public static final int PURPLE_WOOL = 453; - public static final int PURPUR_BLOCK = 454; - public static final int PURPUR_PILLAR = 455; - public static final int PURPUR_SLAB = 456; - public static final int PURPUR_STAIRS = 457; - public static final int QUARTZ_BLOCK = 458; - public static final int QUARTZ_PILLAR = 459; - public static final int QUARTZ_SLAB = 460; - public static final int QUARTZ_STAIRS = 461; - public static final int RAIL = 462; - public static final int RED_BANNER = 463; - public static final int RED_BED = 464; - public static final int RED_CARPET = 465; - public static final int RED_CONCRETE = 466; - public static final int RED_CONCRETE_POWDER = 467; - public static final int RED_GLAZED_TERRACOTTA = 468; - public static final int RED_MUSHROOM = 469; - public static final int RED_MUSHROOM_BLOCK = 470; - public static final int RED_NETHER_BRICKS = 471; - public static final int RED_SAND = 472; - public static final int RED_SANDSTONE = 473; - public static final int RED_SANDSTONE_SLAB = 474; - public static final int RED_SANDSTONE_STAIRS = 475; - public static final int RED_SHULKER_BOX = 476; - public static final int RED_STAINED_GLASS = 477; - public static final int RED_STAINED_GLASS_PANE = 478; - public static final int RED_TERRACOTTA = 479; - public static final int RED_TULIP = 480; - public static final int RED_WALL_BANNER = 481; - public static final int RED_WOOL = 482; - public static final int REDSTONE_BLOCK = 483; - public static final int REDSTONE_LAMP = 484; - public static final int REDSTONE_ORE = 485; - public static final int REDSTONE_TORCH = 486; - public static final int REDSTONE_WALL_TORCH = 487; - public static final int REDSTONE_WIRE = 488; - public static final int REPEATER = 489; - public static final int REPEATING_COMMAND_BLOCK = 490; - public static final int ROSE_BUSH = 491; - public static final int SAND = 492; - public static final int SANDSTONE = 493; - public static final int SANDSTONE_SLAB = 494; - public static final int SANDSTONE_STAIRS = 495; - public static final int SEA_LANTERN = 496; - public static final int SEA_PICKLE = 497; - public static final int SEAGRASS = 498; - public static final int SHULKER_BOX = 499; - public static final int SIGN = 500; - public static final int SKELETON_SKULL = 501; - public static final int SKELETON_WALL_SKULL = 502; - public static final int SLIME_BLOCK = 503; - public static final int SMOOTH_QUARTZ = 504; - public static final int SMOOTH_RED_SANDSTONE = 505; - public static final int SMOOTH_SANDSTONE = 506; - public static final int SMOOTH_STONE = 507; - public static final int SNOW = 508; - public static final int SNOW_BLOCK = 509; - public static final int SOUL_SAND = 510; - public static final int SPAWNER = 511; - public static final int SPONGE = 512; - public static final int SPRUCE_BUTTON = 513; - public static final int SPRUCE_DOOR = 514; - public static final int SPRUCE_FENCE = 515; - public static final int SPRUCE_FENCE_GATE = 516; - public static final int SPRUCE_LEAVES = 517; - public static final int SPRUCE_LOG = 518; - public static final int SPRUCE_PLANKS = 519; - public static final int SPRUCE_PRESSURE_PLATE = 520; - public static final int SPRUCE_SAPLING = 521; - public static final int SPRUCE_SLAB = 522; - public static final int SPRUCE_STAIRS = 523; - public static final int SPRUCE_TRAPDOOR = 524; - public static final int SPRUCE_WOOD = 525; - public static final int STICKY_PISTON = 526; - public static final int STONE = 527; - public static final int STONE_BRICK_SLAB = 528; - public static final int STONE_BRICK_STAIRS = 529; - public static final int STONE_BRICKS = 530; - public static final int STONE_BUTTON = 531; - public static final int STONE_PRESSURE_PLATE = 532; - public static final int STONE_SLAB = 533; - public static final int STRIPPED_ACACIA_LOG = 534; - public static final int STRIPPED_ACACIA_WOOD = 535; - public static final int STRIPPED_BIRCH_LOG = 536; - public static final int STRIPPED_BIRCH_WOOD = 537; - public static final int STRIPPED_DARK_OAK_LOG = 538; - public static final int STRIPPED_DARK_OAK_WOOD = 539; - public static final int STRIPPED_JUNGLE_LOG = 540; - public static final int STRIPPED_JUNGLE_WOOD = 541; - public static final int STRIPPED_OAK_LOG = 542; - public static final int STRIPPED_OAK_WOOD = 543; - public static final int STRIPPED_SPRUCE_LOG = 544; - public static final int STRIPPED_SPRUCE_WOOD = 545; - public static final int STRUCTURE_BLOCK = 546; - public static final int STRUCTURE_VOID = 547; - public static final int SUGAR_CANE = 548; - public static final int SUNFLOWER = 549; - public static final int TALL_GRASS = 550; - public static final int TALL_SEAGRASS = 551; - public static final int TERRACOTTA = 552; - public static final int TNT = 553; - public static final int TORCH = 554; - public static final int TRAPPED_CHEST = 555; - public static final int TRIPWIRE = 556; - public static final int TRIPWIRE_HOOK = 557; - public static final int TUBE_CORAL = 558; - public static final int TUBE_CORAL_BLOCK = 559; - public static final int TUBE_CORAL_FAN = 560; - public static final int TUBE_CORAL_WALL_FAN = 561; - public static final int TURTLE_EGG = 562; - public static final int VINE = 563; - public static final int VOID_AIR = 564; + public static final int AIR = 1; + public static final int CAVE_AIR = 2; + public static final int VOID_AIR = 3; + public static final int ACACIA_BUTTON = 4; + public static final int ACACIA_DOOR = 5; + public static final int ACACIA_FENCE = 6; + public static final int ACACIA_FENCE_GATE = 7; + public static final int ACACIA_LEAVES = 8; + public static final int ACACIA_LOG = 9; + public static final int ACACIA_PLANKS = 10; + public static final int ACACIA_PRESSURE_PLATE = 11; + public static final int ACACIA_SAPLING = 12; + public static final int ACACIA_SLAB = 13; + public static final int ACACIA_STAIRS = 14; + public static final int ACACIA_TRAPDOOR = 15; + public static final int ACACIA_WOOD = 16; + public static final int ACTIVATOR_RAIL = 17; + public static final int ALLIUM = 18; + public static final int ANDESITE = 19; + public static final int ANVIL = 20; + public static final int ATTACHED_MELON_STEM = 21; + public static final int ATTACHED_PUMPKIN_STEM = 22; + public static final int AZURE_BLUET = 23; + public static final int BARRIER = 24; + public static final int BEACON = 25; + public static final int BEDROCK = 26; + public static final int BEETROOTS = 27; + public static final int BIRCH_BUTTON = 28; + public static final int BIRCH_DOOR = 29; + public static final int BIRCH_FENCE = 30; + public static final int BIRCH_FENCE_GATE = 31; + public static final int BIRCH_LEAVES = 32; + public static final int BIRCH_LOG = 33; + public static final int BIRCH_PLANKS = 34; + public static final int BIRCH_PRESSURE_PLATE = 35; + public static final int BIRCH_SAPLING = 36; + public static final int BIRCH_SLAB = 37; + public static final int BIRCH_STAIRS = 38; + public static final int BIRCH_TRAPDOOR = 39; + public static final int BIRCH_WOOD = 40; + public static final int BLACK_BANNER = 41; + public static final int BLACK_BED = 42; + public static final int BLACK_CARPET = 43; + public static final int BLACK_CONCRETE = 44; + public static final int BLACK_CONCRETE_POWDER = 45; + public static final int BLACK_GLAZED_TERRACOTTA = 46; + public static final int BLACK_SHULKER_BOX = 47; + public static final int BLACK_STAINED_GLASS = 48; + public static final int BLACK_STAINED_GLASS_PANE = 49; + public static final int BLACK_TERRACOTTA = 50; + public static final int BLACK_WALL_BANNER = 51; + public static final int BLACK_WOOL = 52; + public static final int BLUE_BANNER = 53; + public static final int BLUE_BED = 54; + public static final int BLUE_CARPET = 55; + public static final int BLUE_CONCRETE = 56; + public static final int BLUE_CONCRETE_POWDER = 57; + public static final int BLUE_GLAZED_TERRACOTTA = 58; + public static final int BLUE_ICE = 59; + public static final int BLUE_ORCHID = 60; + public static final int BLUE_SHULKER_BOX = 61; + public static final int BLUE_STAINED_GLASS = 62; + public static final int BLUE_STAINED_GLASS_PANE = 63; + public static final int BLUE_TERRACOTTA = 64; + public static final int BLUE_WALL_BANNER = 65; + public static final int BLUE_WOOL = 66; + public static final int BONE_BLOCK = 67; + public static final int BOOKSHELF = 68; + public static final int BRAIN_CORAL = 69; + public static final int BRAIN_CORAL_BLOCK = 70; + public static final int BRAIN_CORAL_FAN = 71; + public static final int BRAIN_CORAL_WALL_FAN = 72; + public static final int BREWING_STAND = 73; + public static final int BRICK_SLAB = 74; + public static final int BRICK_STAIRS = 75; + public static final int BRICKS = 76; + public static final int BROWN_BANNER = 77; + public static final int BROWN_BED = 78; + public static final int BROWN_CARPET = 79; + public static final int BROWN_CONCRETE = 80; + public static final int BROWN_CONCRETE_POWDER = 81; + public static final int BROWN_GLAZED_TERRACOTTA = 82; + public static final int BROWN_MUSHROOM = 83; + public static final int BROWN_MUSHROOM_BLOCK = 84; + public static final int BROWN_SHULKER_BOX = 85; + public static final int BROWN_STAINED_GLASS = 86; + public static final int BROWN_STAINED_GLASS_PANE = 87; + public static final int BROWN_TERRACOTTA = 88; + public static final int BROWN_WALL_BANNER = 89; + public static final int BROWN_WOOL = 90; + public static final int BUBBLE_COLUMN = 91; + public static final int BUBBLE_CORAL = 92; + public static final int BUBBLE_CORAL_BLOCK = 93; + public static final int BUBBLE_CORAL_FAN = 94; + public static final int BUBBLE_CORAL_WALL_FAN = 95; + public static final int CACTUS = 96; + public static final int CAKE = 97; + public static final int CARROTS = 98; + public static final int CARVED_PUMPKIN = 99; + public static final int CAULDRON = 100; + public static final int CHAIN_COMMAND_BLOCK = 101; + public static final int CHEST = 102; + public static final int CHIPPED_ANVIL = 103; + public static final int CHISELED_QUARTZ_BLOCK = 104; + public static final int CHISELED_RED_SANDSTONE = 105; + public static final int CHISELED_SANDSTONE = 106; + public static final int CHISELED_STONE_BRICKS = 107; + public static final int CHORUS_FLOWER = 108; + public static final int CHORUS_PLANT = 109; + public static final int CLAY = 110; + public static final int COAL_BLOCK = 111; + public static final int COAL_ORE = 112; + public static final int COARSE_DIRT = 113; + public static final int COBBLESTONE = 114; + public static final int COBBLESTONE_SLAB = 115; + public static final int COBBLESTONE_STAIRS = 116; + public static final int COBBLESTONE_WALL = 117; + public static final int COBWEB = 118; + public static final int COCOA = 119; + public static final int COMMAND_BLOCK = 120; + public static final int COMPARATOR = 121; + public static final int CONDUIT = 122; + public static final int CRACKED_STONE_BRICKS = 123; + public static final int CRAFTING_TABLE = 124; + public static final int CREEPER_HEAD = 125; + public static final int CREEPER_WALL_HEAD = 126; + public static final int CUT_RED_SANDSTONE = 127; + public static final int CUT_SANDSTONE = 128; + public static final int CYAN_BANNER = 129; + public static final int CYAN_BED = 130; + public static final int CYAN_CARPET = 131; + public static final int CYAN_CONCRETE = 132; + public static final int CYAN_CONCRETE_POWDER = 133; + public static final int CYAN_GLAZED_TERRACOTTA = 134; + public static final int CYAN_SHULKER_BOX = 135; + public static final int CYAN_STAINED_GLASS = 136; + public static final int CYAN_STAINED_GLASS_PANE = 137; + public static final int CYAN_TERRACOTTA = 138; + public static final int CYAN_WALL_BANNER = 139; + public static final int CYAN_WOOL = 140; + public static final int DAMAGED_ANVIL = 141; + public static final int DANDELION = 142; + public static final int DARK_OAK_BUTTON = 143; + public static final int DARK_OAK_DOOR = 144; + public static final int DARK_OAK_FENCE = 145; + public static final int DARK_OAK_FENCE_GATE = 146; + public static final int DARK_OAK_LEAVES = 147; + public static final int DARK_OAK_LOG = 148; + public static final int DARK_OAK_PLANKS = 149; + public static final int DARK_OAK_PRESSURE_PLATE = 150; + public static final int DARK_OAK_SAPLING = 151; + public static final int DARK_OAK_SLAB = 152; + public static final int DARK_OAK_STAIRS = 153; + public static final int DARK_OAK_TRAPDOOR = 154; + public static final int DARK_OAK_WOOD = 155; + public static final int DARK_PRISMARINE = 156; + public static final int DARK_PRISMARINE_SLAB = 157; + public static final int DARK_PRISMARINE_STAIRS = 158; + public static final int DAYLIGHT_DETECTOR = 159; + public static final int DEAD_BRAIN_CORAL = 160; + public static final int DEAD_BRAIN_CORAL_BLOCK = 161; + public static final int DEAD_BRAIN_CORAL_FAN = 162; + public static final int DEAD_BRAIN_CORAL_WALL_FAN = 163; + public static final int DEAD_BUBBLE_CORAL = 164; + public static final int DEAD_BUBBLE_CORAL_BLOCK = 165; + public static final int DEAD_BUBBLE_CORAL_FAN = 166; + public static final int DEAD_BUBBLE_CORAL_WALL_FAN = 167; + public static final int DEAD_BUSH = 168; + public static final int DEAD_FIRE_CORAL = 169; + public static final int DEAD_FIRE_CORAL_BLOCK = 170; + public static final int DEAD_FIRE_CORAL_FAN = 171; + public static final int DEAD_FIRE_CORAL_WALL_FAN = 172; + public static final int DEAD_HORN_CORAL = 173; + public static final int DEAD_HORN_CORAL_BLOCK = 174; + public static final int DEAD_HORN_CORAL_FAN = 175; + public static final int DEAD_HORN_CORAL_WALL_FAN = 176; + public static final int DEAD_TUBE_CORAL = 177; + public static final int DEAD_TUBE_CORAL_BLOCK = 178; + public static final int DEAD_TUBE_CORAL_FAN = 179; + public static final int DEAD_TUBE_CORAL_WALL_FAN = 180; + public static final int DETECTOR_RAIL = 181; + public static final int DIAMOND_BLOCK = 182; + public static final int DIAMOND_ORE = 183; + public static final int DIORITE = 184; + public static final int DIRT = 185; + public static final int DISPENSER = 186; + public static final int DRAGON_EGG = 187; + public static final int DRAGON_HEAD = 188; + public static final int DRAGON_WALL_HEAD = 189; + public static final int DRIED_KELP_BLOCK = 190; + public static final int DROPPER = 191; + public static final int EMERALD_BLOCK = 192; + public static final int EMERALD_ORE = 193; + public static final int ENCHANTING_TABLE = 194; + public static final int END_GATEWAY = 195; + public static final int END_PORTAL = 196; + public static final int END_PORTAL_FRAME = 197; + public static final int END_ROD = 198; + public static final int END_STONE = 199; + public static final int END_STONE_BRICKS = 200; + public static final int ENDER_CHEST = 201; + public static final int FARMLAND = 202; + public static final int FERN = 203; + public static final int FIRE = 204; + public static final int FIRE_CORAL = 205; + public static final int FIRE_CORAL_BLOCK = 206; + public static final int FIRE_CORAL_FAN = 207; + public static final int FIRE_CORAL_WALL_FAN = 208; + public static final int FLOWER_POT = 209; + public static final int FROSTED_ICE = 210; + public static final int FURNACE = 211; + public static final int GLASS = 212; + public static final int GLASS_PANE = 213; + public static final int GLOWSTONE = 214; + public static final int GOLD_BLOCK = 215; + public static final int GOLD_ORE = 216; + public static final int GRANITE = 217; + public static final int GRASS = 218; + public static final int GRASS_BLOCK = 219; + public static final int GRASS_PATH = 220; + public static final int GRAVEL = 221; + public static final int GRAY_BANNER = 222; + public static final int GRAY_BED = 223; + public static final int GRAY_CARPET = 224; + public static final int GRAY_CONCRETE = 225; + public static final int GRAY_CONCRETE_POWDER = 226; + public static final int GRAY_GLAZED_TERRACOTTA = 227; + public static final int GRAY_SHULKER_BOX = 228; + public static final int GRAY_STAINED_GLASS = 229; + public static final int GRAY_STAINED_GLASS_PANE = 230; + public static final int GRAY_TERRACOTTA = 231; + public static final int GRAY_WALL_BANNER = 232; + public static final int GRAY_WOOL = 233; + public static final int GREEN_BANNER = 234; + public static final int GREEN_BED = 235; + public static final int GREEN_CARPET = 236; + public static final int GREEN_CONCRETE = 237; + public static final int GREEN_CONCRETE_POWDER = 238; + public static final int GREEN_GLAZED_TERRACOTTA = 239; + public static final int GREEN_SHULKER_BOX = 240; + public static final int GREEN_STAINED_GLASS = 241; + public static final int GREEN_STAINED_GLASS_PANE = 242; + public static final int GREEN_TERRACOTTA = 243; + public static final int GREEN_WALL_BANNER = 244; + public static final int GREEN_WOOL = 245; + public static final int HAY_BLOCK = 246; + public static final int HEAVY_WEIGHTED_PRESSURE_PLATE = 247; + public static final int HOPPER = 248; + public static final int HORN_CORAL = 249; + public static final int HORN_CORAL_BLOCK = 250; + public static final int HORN_CORAL_FAN = 251; + public static final int HORN_CORAL_WALL_FAN = 252; + public static final int ICE = 253; + public static final int INFESTED_CHISELED_STONE_BRICKS = 254; + public static final int INFESTED_COBBLESTONE = 255; + public static final int INFESTED_CRACKED_STONE_BRICKS = 256; + public static final int INFESTED_MOSSY_STONE_BRICKS = 257; + public static final int INFESTED_STONE = 258; + public static final int INFESTED_STONE_BRICKS = 259; + public static final int IRON_BARS = 260; + public static final int IRON_BLOCK = 261; + public static final int IRON_DOOR = 262; + public static final int IRON_ORE = 263; + public static final int IRON_TRAPDOOR = 264; + public static final int JACK_O_LANTERN = 265; + public static final int JUKEBOX = 266; + public static final int JUNGLE_BUTTON = 267; + public static final int JUNGLE_DOOR = 268; + public static final int JUNGLE_FENCE = 269; + public static final int JUNGLE_FENCE_GATE = 270; + public static final int JUNGLE_LEAVES = 271; + public static final int JUNGLE_LOG = 272; + public static final int JUNGLE_PLANKS = 273; + public static final int JUNGLE_PRESSURE_PLATE = 274; + public static final int JUNGLE_SAPLING = 275; + public static final int JUNGLE_SLAB = 276; + public static final int JUNGLE_STAIRS = 277; + public static final int JUNGLE_TRAPDOOR = 278; + public static final int JUNGLE_WOOD = 279; + public static final int KELP = 280; + public static final int KELP_PLANT = 281; + public static final int LADDER = 282; + public static final int LAPIS_BLOCK = 283; + public static final int LAPIS_ORE = 284; + public static final int LARGE_FERN = 285; + public static final int LAVA = 286; + public static final int LEVER = 287; + public static final int LIGHT_BLUE_BANNER = 288; + public static final int LIGHT_BLUE_BED = 289; + public static final int LIGHT_BLUE_CARPET = 290; + public static final int LIGHT_BLUE_CONCRETE = 291; + public static final int LIGHT_BLUE_CONCRETE_POWDER = 292; + public static final int LIGHT_BLUE_GLAZED_TERRACOTTA = 293; + public static final int LIGHT_BLUE_SHULKER_BOX = 294; + public static final int LIGHT_BLUE_STAINED_GLASS = 295; + public static final int LIGHT_BLUE_STAINED_GLASS_PANE = 296; + public static final int LIGHT_BLUE_TERRACOTTA = 297; + public static final int LIGHT_BLUE_WALL_BANNER = 298; + public static final int LIGHT_BLUE_WOOL = 299; + public static final int LIGHT_GRAY_BANNER = 300; + public static final int LIGHT_GRAY_BED = 301; + public static final int LIGHT_GRAY_CARPET = 302; + public static final int LIGHT_GRAY_CONCRETE = 303; + public static final int LIGHT_GRAY_CONCRETE_POWDER = 304; + public static final int LIGHT_GRAY_GLAZED_TERRACOTTA = 305; + public static final int LIGHT_GRAY_SHULKER_BOX = 306; + public static final int LIGHT_GRAY_STAINED_GLASS = 307; + public static final int LIGHT_GRAY_STAINED_GLASS_PANE = 308; + public static final int LIGHT_GRAY_TERRACOTTA = 309; + public static final int LIGHT_GRAY_WALL_BANNER = 310; + public static final int LIGHT_GRAY_WOOL = 311; + public static final int LIGHT_WEIGHTED_PRESSURE_PLATE = 312; + public static final int LILAC = 313; + public static final int LILY_PAD = 314; + public static final int LIME_BANNER = 315; + public static final int LIME_BED = 316; + public static final int LIME_CARPET = 317; + public static final int LIME_CONCRETE = 318; + public static final int LIME_CONCRETE_POWDER = 319; + public static final int LIME_GLAZED_TERRACOTTA = 320; + public static final int LIME_SHULKER_BOX = 321; + public static final int LIME_STAINED_GLASS = 322; + public static final int LIME_STAINED_GLASS_PANE = 323; + public static final int LIME_TERRACOTTA = 324; + public static final int LIME_WALL_BANNER = 325; + public static final int LIME_WOOL = 326; + public static final int MAGENTA_BANNER = 327; + public static final int MAGENTA_BED = 328; + public static final int MAGENTA_CARPET = 329; + public static final int MAGENTA_CONCRETE = 330; + public static final int MAGENTA_CONCRETE_POWDER = 331; + public static final int MAGENTA_GLAZED_TERRACOTTA = 332; + public static final int MAGENTA_SHULKER_BOX = 333; + public static final int MAGENTA_STAINED_GLASS = 334; + public static final int MAGENTA_STAINED_GLASS_PANE = 335; + public static final int MAGENTA_TERRACOTTA = 336; + public static final int MAGENTA_WALL_BANNER = 337; + public static final int MAGENTA_WOOL = 338; + public static final int MAGMA_BLOCK = 339; + public static final int MELON = 340; + public static final int MELON_STEM = 341; + public static final int MOSSY_COBBLESTONE = 342; + public static final int MOSSY_COBBLESTONE_WALL = 343; + public static final int MOSSY_STONE_BRICKS = 344; + public static final int MOVING_PISTON = 345; + public static final int MUSHROOM_STEM = 346; + public static final int MYCELIUM = 347; + public static final int NETHER_BRICK_FENCE = 348; + public static final int NETHER_BRICK_SLAB = 349; + public static final int NETHER_BRICK_STAIRS = 350; + public static final int NETHER_BRICKS = 351; + public static final int NETHER_PORTAL = 352; + public static final int NETHER_QUARTZ_ORE = 353; + public static final int NETHER_WART = 354; + public static final int NETHER_WART_BLOCK = 355; + public static final int NETHERRACK = 356; + public static final int NOTE_BLOCK = 357; + public static final int OAK_BUTTON = 358; + public static final int OAK_DOOR = 359; + public static final int OAK_FENCE = 360; + public static final int OAK_FENCE_GATE = 361; + public static final int OAK_LEAVES = 362; + public static final int OAK_LOG = 363; + public static final int OAK_PLANKS = 364; + public static final int OAK_PRESSURE_PLATE = 365; + public static final int OAK_SAPLING = 366; + public static final int OAK_SLAB = 367; + public static final int OAK_STAIRS = 368; + public static final int OAK_TRAPDOOR = 369; + public static final int OAK_WOOD = 370; + public static final int OBSERVER = 371; + public static final int OBSIDIAN = 372; + public static final int ORANGE_BANNER = 373; + public static final int ORANGE_BED = 374; + public static final int ORANGE_CARPET = 375; + public static final int ORANGE_CONCRETE = 376; + public static final int ORANGE_CONCRETE_POWDER = 377; + public static final int ORANGE_GLAZED_TERRACOTTA = 378; + public static final int ORANGE_SHULKER_BOX = 379; + public static final int ORANGE_STAINED_GLASS = 380; + public static final int ORANGE_STAINED_GLASS_PANE = 381; + public static final int ORANGE_TERRACOTTA = 382; + public static final int ORANGE_TULIP = 383; + public static final int ORANGE_WALL_BANNER = 384; + public static final int ORANGE_WOOL = 385; + public static final int OXEYE_DAISY = 386; + public static final int PACKED_ICE = 387; + public static final int PEONY = 388; + public static final int PETRIFIED_OAK_SLAB = 389; + public static final int PINK_BANNER = 390; + public static final int PINK_BED = 391; + public static final int PINK_CARPET = 392; + public static final int PINK_CONCRETE = 393; + public static final int PINK_CONCRETE_POWDER = 394; + public static final int PINK_GLAZED_TERRACOTTA = 395; + public static final int PINK_SHULKER_BOX = 396; + public static final int PINK_STAINED_GLASS = 397; + public static final int PINK_STAINED_GLASS_PANE = 398; + public static final int PINK_TERRACOTTA = 399; + public static final int PINK_TULIP = 400; + public static final int PINK_WALL_BANNER = 401; + public static final int PINK_WOOL = 402; + public static final int PISTON = 403; + public static final int PISTON_HEAD = 404; + public static final int PLAYER_HEAD = 405; + public static final int PLAYER_WALL_HEAD = 406; + public static final int PODZOL = 407; + public static final int POLISHED_ANDESITE = 408; + public static final int POLISHED_DIORITE = 409; + public static final int POLISHED_GRANITE = 410; + public static final int POPPY = 411; + public static final int POTATOES = 412; + public static final int POTTED_ACACIA_SAPLING = 413; + public static final int POTTED_ALLIUM = 414; + public static final int POTTED_AZURE_BLUET = 415; + public static final int POTTED_BIRCH_SAPLING = 416; + public static final int POTTED_BLUE_ORCHID = 417; + public static final int POTTED_BROWN_MUSHROOM = 418; + public static final int POTTED_CACTUS = 419; + public static final int POTTED_DANDELION = 420; + public static final int POTTED_DARK_OAK_SAPLING = 421; + public static final int POTTED_DEAD_BUSH = 422; + public static final int POTTED_FERN = 423; + public static final int POTTED_JUNGLE_SAPLING = 424; + public static final int POTTED_OAK_SAPLING = 425; + public static final int POTTED_ORANGE_TULIP = 426; + public static final int POTTED_OXEYE_DAISY = 427; + public static final int POTTED_PINK_TULIP = 428; + public static final int POTTED_POPPY = 429; + public static final int POTTED_RED_MUSHROOM = 430; + public static final int POTTED_RED_TULIP = 431; + public static final int POTTED_SPRUCE_SAPLING = 432; + public static final int POTTED_WHITE_TULIP = 433; + public static final int POWERED_RAIL = 434; + public static final int PRISMARINE = 435; + public static final int PRISMARINE_BRICK_SLAB = 436; + public static final int PRISMARINE_BRICK_STAIRS = 437; + public static final int PRISMARINE_BRICKS = 438; + public static final int PRISMARINE_SLAB = 439; + public static final int PRISMARINE_STAIRS = 440; + public static final int PUMPKIN = 441; + public static final int PUMPKIN_STEM = 442; + public static final int PURPLE_BANNER = 443; + public static final int PURPLE_BED = 444; + public static final int PURPLE_CARPET = 445; + public static final int PURPLE_CONCRETE = 446; + public static final int PURPLE_CONCRETE_POWDER = 447; + public static final int PURPLE_GLAZED_TERRACOTTA = 448; + public static final int PURPLE_SHULKER_BOX = 449; + public static final int PURPLE_STAINED_GLASS = 450; + public static final int PURPLE_STAINED_GLASS_PANE = 451; + public static final int PURPLE_TERRACOTTA = 452; + public static final int PURPLE_WALL_BANNER = 453; + public static final int PURPLE_WOOL = 454; + public static final int PURPUR_BLOCK = 455; + public static final int PURPUR_PILLAR = 456; + public static final int PURPUR_SLAB = 457; + public static final int PURPUR_STAIRS = 458; + public static final int QUARTZ_BLOCK = 459; + public static final int QUARTZ_PILLAR = 460; + public static final int QUARTZ_SLAB = 461; + public static final int QUARTZ_STAIRS = 462; + public static final int RAIL = 463; + public static final int RED_BANNER = 464; + public static final int RED_BED = 465; + public static final int RED_CARPET = 466; + public static final int RED_CONCRETE = 467; + public static final int RED_CONCRETE_POWDER = 468; + public static final int RED_GLAZED_TERRACOTTA = 469; + public static final int RED_MUSHROOM = 470; + public static final int RED_MUSHROOM_BLOCK = 471; + public static final int RED_NETHER_BRICKS = 472; + public static final int RED_SAND = 473; + public static final int RED_SANDSTONE = 474; + public static final int RED_SANDSTONE_SLAB = 475; + public static final int RED_SANDSTONE_STAIRS = 476; + public static final int RED_SHULKER_BOX = 477; + public static final int RED_STAINED_GLASS = 478; + public static final int RED_STAINED_GLASS_PANE = 479; + public static final int RED_TERRACOTTA = 480; + public static final int RED_TULIP = 481; + public static final int RED_WALL_BANNER = 482; + public static final int RED_WOOL = 483; + public static final int REDSTONE_BLOCK = 484; + public static final int REDSTONE_LAMP = 485; + public static final int REDSTONE_ORE = 486; + public static final int REDSTONE_TORCH = 487; + public static final int REDSTONE_WALL_TORCH = 488; + public static final int REDSTONE_WIRE = 489; + public static final int REPEATER = 490; + public static final int REPEATING_COMMAND_BLOCK = 491; + public static final int ROSE_BUSH = 492; + public static final int SAND = 493; + public static final int SANDSTONE = 494; + public static final int SANDSTONE_SLAB = 495; + public static final int SANDSTONE_STAIRS = 496; + public static final int SEA_LANTERN = 497; + public static final int SEA_PICKLE = 498; + public static final int SEAGRASS = 499; + public static final int SHULKER_BOX = 500; + public static final int SIGN = 501; + public static final int SKELETON_SKULL = 502; + public static final int SKELETON_WALL_SKULL = 503; + public static final int SLIME_BLOCK = 504; + public static final int SMOOTH_QUARTZ = 505; + public static final int SMOOTH_RED_SANDSTONE = 506; + public static final int SMOOTH_SANDSTONE = 507; + public static final int SMOOTH_STONE = 508; + public static final int SNOW = 509; + public static final int SNOW_BLOCK = 510; + public static final int SOUL_SAND = 511; + public static final int SPAWNER = 512; + public static final int SPONGE = 513; + public static final int SPRUCE_BUTTON = 514; + public static final int SPRUCE_DOOR = 515; + public static final int SPRUCE_FENCE = 516; + public static final int SPRUCE_FENCE_GATE = 517; + public static final int SPRUCE_LEAVES = 518; + public static final int SPRUCE_LOG = 519; + public static final int SPRUCE_PLANKS = 520; + public static final int SPRUCE_PRESSURE_PLATE = 521; + public static final int SPRUCE_SAPLING = 522; + public static final int SPRUCE_SLAB = 523; + public static final int SPRUCE_STAIRS = 524; + public static final int SPRUCE_TRAPDOOR = 525; + public static final int SPRUCE_WOOD = 526; + public static final int STICKY_PISTON = 527; + public static final int STONE = 528; + public static final int STONE_BRICK_SLAB = 529; + public static final int STONE_BRICK_STAIRS = 530; + public static final int STONE_BRICKS = 531; + public static final int STONE_BUTTON = 532; + public static final int STONE_PRESSURE_PLATE = 533; + public static final int STONE_SLAB = 534; + public static final int STRIPPED_ACACIA_LOG = 535; + public static final int STRIPPED_ACACIA_WOOD = 536; + public static final int STRIPPED_BIRCH_LOG = 537; + public static final int STRIPPED_BIRCH_WOOD = 538; + public static final int STRIPPED_DARK_OAK_LOG = 539; + public static final int STRIPPED_DARK_OAK_WOOD = 540; + public static final int STRIPPED_JUNGLE_LOG = 541; + public static final int STRIPPED_JUNGLE_WOOD = 542; + public static final int STRIPPED_OAK_LOG = 543; + public static final int STRIPPED_OAK_WOOD = 544; + public static final int STRIPPED_SPRUCE_LOG = 545; + public static final int STRIPPED_SPRUCE_WOOD = 546; + public static final int STRUCTURE_BLOCK = 547; + public static final int STRUCTURE_VOID = 548; + public static final int SUGAR_CANE = 549; + public static final int SUNFLOWER = 550; + public static final int TALL_GRASS = 551; + public static final int TALL_SEAGRASS = 552; + public static final int TERRACOTTA = 553; + public static final int TNT = 554; + public static final int TORCH = 555; + public static final int TRAPPED_CHEST = 556; + public static final int TRIPWIRE = 557; + public static final int TRIPWIRE_HOOK = 558; + public static final int TUBE_CORAL = 559; + public static final int TUBE_CORAL_BLOCK = 560; + public static final int TUBE_CORAL_FAN = 561; + public static final int TUBE_CORAL_WALL_FAN = 562; + public static final int TURTLE_EGG = 563; + public static final int VINE = 564; public static final int WALL_SIGN = 565; public static final int WALL_TORCH = 566; public static final int WATER = 567; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java index a157b2cbe..7d2c77a73 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java @@ -62,6 +62,10 @@ import java.util.stream.Stream; public final class BlockTypes { // Doesn't really matter what the hardcoded values are, as FAWE will update it on load @Nullable public static final BlockType __RESERVED__ = null; + @Nullable public static final BlockType AIR = null; + @Nullable public static final BlockType CAVE_AIR = null; + @Nullable public static final BlockType VOID_AIR = null; + @Nullable public static final BlockType ACACIA_BUTTON = null; @Nullable public static final BlockType ACACIA_DOOR = null; @Nullable public static final BlockType ACACIA_FENCE = null; @@ -76,7 +80,6 @@ public final class BlockTypes { @Nullable public static final BlockType ACACIA_TRAPDOOR = null; @Nullable public static final BlockType ACACIA_WOOD = null; @Nullable public static final BlockType ACTIVATOR_RAIL = null; - @Nullable public static final BlockType AIR = null; @Nullable public static final BlockType ALLIUM = null; @Nullable public static final BlockType ANDESITE = null; @Nullable public static final BlockType ANVIL = null; @@ -160,7 +163,6 @@ public final class BlockTypes { @Nullable public static final BlockType CARROTS = null; @Nullable public static final BlockType CARVED_PUMPKIN = null; @Nullable public static final BlockType CAULDRON = null; - @Nullable public static final BlockType CAVE_AIR = null; @Nullable public static final BlockType CHAIN_COMMAND_BLOCK = null; @Nullable public static final BlockType CHEST = null; @Nullable public static final BlockType CHIPPED_ANVIL = null; @@ -625,7 +627,6 @@ public final class BlockTypes { @Nullable public static final BlockType TUBE_CORAL_WALL_FAN = null; @Nullable public static final BlockType TURTLE_EGG = null; @Nullable public static final BlockType VINE = null; - @Nullable public static final BlockType VOID_AIR = null; @Nullable public static final BlockType WALL_SIGN = null; @Nullable public static final BlockType WALL_TORCH = null; @Nullable public static final BlockType WATER = null; From f96760b36c9f1ed358bb87bb3005a7aa9cf6c7c0 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Thu, 2 May 2019 02:01:41 +1000 Subject: [PATCH 08/54] block set test --- .../fawe/bukkit/beta/BukkitChunkHolder.java | 23 ++++++++++++++++++- .../boydti/fawe/bukkit/beta/BukkitQueue.java | 4 ++-- .../worldedit/command/RegionCommands.java | 20 ++++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java index 61d872767..27ba85f7b 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java @@ -1,10 +1,15 @@ package com.boydti.fawe.bukkit.beta; import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.IGetBlocks; import com.boydti.fawe.beta.IQueueExtent; import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks; import com.boydti.fawe.beta.implementation.holder.ChunkHolder; +import com.google.common.util.concurrent.Futures; +import net.minecraft.server.v1_13_R2.Chunk; +import net.minecraft.server.v1_13_R2.ChunkSection; +import org.bukkit.World; import java.util.concurrent.Future; @@ -25,6 +30,20 @@ public class BukkitChunkHolder> extends ChunkHolder { BukkitQueue extent = (BukkitQueue) getExtent(); BukkitGetBlocks get = (BukkitGetBlocks) getOrCreateGet(); CharSetBlocks set = (CharSetBlocks) getOrCreateSet(); + int X = getX(); + int Z = getZ(); + + Chunk currentNmsChunk = extent.ensureLoaded(X, Z); + ChunkSection[] sections = currentNmsChunk.getSections(); + World world = extent.getBukkitWorld(); + boolean hasSky = world.getEnvironment() == World.Environment.NORMAL; + + for (int layer = 0; layer < 16; layer++) { + if (!set.hasSection(layer)) continue; + char[] arr = set.blocks[layer]; + ChunkSection newSection = extent.newChunkSection(layer, hasSky, arr); + sections[layer] = newSection; + } @@ -48,8 +67,10 @@ public class BukkitChunkHolder> extends ChunkHolder { */ - throw new UnsupportedOperationException("Not implemented"); +// throw new UnsupportedOperationException("Not implemented"); // return true; + return null; +// return (T) (Future) Futures.immediateFuture(null); } @Override diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java index 5c869bc29..f63dfd327 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java @@ -160,8 +160,8 @@ public class BukkitQueue extends SimpleCharQueueExtent { NMS conversion */ - public static ChunkSection newChunkSection(final int y2, final boolean flag, final char[] blocks) { - ChunkSection section = new ChunkSection(y2 << 4, flag); + public static ChunkSection newChunkSection(final int layer, final boolean flag, final char[] blocks) { + ChunkSection section = new ChunkSection(layer << 4, flag); if (blocks == null) { return section; } 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 695c730fb..d02d2dd03 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 @@ -287,6 +287,26 @@ public class RegionCommands extends MethodCommands { System.out.println(diff); } + @Command( + aliases = {"db2"}, + usage = "", + desc = "db2", + help = "db2" + ) + public void db2(Player player, @Selection Region region) throws WorldEditException { + QueueHandler queueHandler = Fawe.get().getQueueHandler(); + World world = player.getWorld(); + IQueueExtent queue = queueHandler.getQueue(world); + BlockState block = BlockTypes.STONE.getDefaultState(); + long start = System.currentTimeMillis(); + for (BlockVector3 p : region) { + queue.setBlock(p.getX(), p.getY(), p.getZ(), block); + } + queue.flush(); + long diff = System.currentTimeMillis() - start; + System.out.println(diff); + } + @Command( aliases = {"/curve", "/spline"}, usage = " [thickness]", From adb2c37a02a3a002b76769011739f150f3fd6e63 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Thu, 2 May 2019 04:19:15 +1000 Subject: [PATCH 09/54] set blocks --- .../fawe/bukkit/beta/BukkitChunkHolder.java | 80 ++++++++-- .../fawe/bukkit/beta/BukkitGetBlocks.java | 139 ++++++++++-------- .../boydti/fawe/bukkit/beta/BukkitQueue.java | 50 +++++++ .../boydti/fawe/bukkit/beta/DelegateLock.java | 14 +- .../SingleThreadQueueExtent.java | 5 +- .../implementation/blocks/CharBlocks.java | 4 + .../java/net/jpountz/util/UnsafeUtils.java | 4 + 7 files changed, 221 insertions(+), 75 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java index 27ba85f7b..4dc63bf9f 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java @@ -7,11 +7,14 @@ import com.boydti.fawe.beta.IQueueExtent; import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks; import com.boydti.fawe.beta.implementation.holder.ChunkHolder; import com.google.common.util.concurrent.Futures; +import net.jpountz.util.UnsafeUtils; import net.minecraft.server.v1_13_R2.Chunk; import net.minecraft.server.v1_13_R2.ChunkSection; import org.bukkit.World; +import java.util.Arrays; import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicReferenceArray; public class BukkitChunkHolder> extends ChunkHolder { @Override @@ -33,20 +36,73 @@ public class BukkitChunkHolder> extends ChunkHolder { int X = getX(); int Z = getZ(); - Chunk currentNmsChunk = extent.ensureLoaded(X, Z); - ChunkSection[] sections = currentNmsChunk.getSections(); - World world = extent.getBukkitWorld(); - boolean hasSky = world.getEnvironment() == World.Environment.NORMAL; + Chunk nmsChunk = extent.ensureLoaded(X, Z); + try { + synchronized (nmsChunk) { + ChunkSection[] sections = nmsChunk.getSections(); + World world = extent.getBukkitWorld(); + boolean hasSky = world.getEnvironment() == World.Environment.NORMAL; - for (int layer = 0; layer < 16; layer++) { - if (!set.hasSection(layer)) continue; - char[] arr = set.blocks[layer]; - ChunkSection newSection = extent.newChunkSection(layer, hasSky, arr); - sections[layer] = newSection; + for (int layer = 0; layer < 16; layer++) { + if (!set.hasSection(layer)) continue; + char[] setArr = set.blocks[layer]; + ChunkSection newSection; + ChunkSection existingSection = sections[layer]; + if (existingSection == null) { + newSection = extent.newChunkSection(layer, hasSky, setArr); + if (BukkitQueue.setSectionAtomic(sections, null, newSection, layer)) { + continue; + } else { + existingSection = sections[layer]; + if (existingSection == null) { + System.out.println("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer); + continue; + } + } + } + DelegateLock lock = BukkitQueue.applyLock(existingSection); + synchronized (lock) { + if (lock.isLocked()) { + lock.lock(); + lock.unlock(); + } + synchronized (get) { + ChunkSection getSection; + if (get.nmsChunk != nmsChunk) { + get.nmsChunk = nmsChunk; + get.sections = null; + get.reset(); + System.out.println("chunk doesn't match"); + } else { + getSection = get.getSections()[layer]; + if (getSection != existingSection) { + get.sections[layer] = existingSection; + get.reset(); + System.out.println("Section doesn't match"); + } else if (lock.isModified()) { + System.out.println("lock is outdated"); + get.reset(layer); + } + } + char[] getArr = get.load(layer); + for (int i = 0; i < 4096; i++) { + char value = setArr[i]; + if (value != 0) { + getArr[i] = value; + } + } + newSection = extent.newChunkSection(layer, hasSky, getArr); + if (!BukkitQueue.setSectionAtomic(sections, existingSection, newSection, layer)) { + System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer); + continue; + } + } + } + } + } + } finally { + extent.returnToPool(this); } - - - /* - getBlocks diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java index d1d8d135e..e0f2328c6 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java @@ -62,85 +62,97 @@ public class BukkitGetBlocks extends CharGetBlocks { if (data == null || data == FaweCache.EMPTY_CHAR_4096) { data = new char[4096]; } + DelegateLock lock = BukkitQueue.applyLock(section); + synchronized (lock) { + if (lock.isLocked()) { + lock.lock(); + lock.unlock(); + } + lock.setModified(false); + // Efficiently convert ChunkSection to raw data + try { + final DataPaletteBlock blocks = section.getBlocks(); + final DataBits bits = (DataBits) BukkitQueue_1_13.fieldBits.get(blocks); + final DataPalette palette = (DataPalette) BukkitQueue_1_13.fieldPalette.get(blocks); + final int bitsPerEntry = bits.c(); - // Efficiently convert ChunkSection to raw data - try { - final DataPaletteBlock blocks = section.getBlocks(); - final DataBits bits = (DataBits) BukkitQueue_1_13.fieldBits.get(blocks); - final DataPalette palette = (DataPalette) BukkitQueue_1_13.fieldPalette.get(blocks); - final int bitsPerEntry = bits.c(); + final long[] blockStates = bits.a(); + new BitArray4096(blockStates, bitsPerEntry).toRaw(data); - final long[] blockStates = bits.a(); - new BitArray4096(blockStates, bitsPerEntry).toRaw(data); + int num_palette; + if (palette instanceof DataPaletteLinear) { + num_palette = ((DataPaletteLinear) palette).b(); + } else if (palette instanceof DataPaletteHash) { + num_palette = ((DataPaletteHash) palette).b(); + } else { + num_palette = 0; + int[] paletteToBlockInts = FaweCache.PALETTE_TO_BLOCK.get(); + char[] paletteToBlockChars = FaweCache.PALETTE_TO_BLOCK_CHAR.get(); + try { + for (int i = 0; i < 4096; i++) { + char paletteVal = data[i]; + char ordinal = paletteToBlockChars[paletteVal]; + if (ordinal == Character.MAX_VALUE) { + paletteToBlockInts[num_palette++] = paletteVal; + IBlockData ibd = palette.a(data[i]); + if (ibd == null) { + ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar(); + } else { + ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToChar(ibd); + } + paletteToBlockChars[paletteVal] = ordinal; + } + data[i] = ordinal; + } + } finally { + for (int i = 0; i < num_palette; i++) { + int paletteVal = paletteToBlockInts[i]; + paletteToBlockChars[paletteVal] = Character.MAX_VALUE; + } + } + return data; + } - int num_palette; - if (palette instanceof DataPaletteLinear) { - num_palette = ((DataPaletteLinear) palette).b(); - } else if (palette instanceof DataPaletteHash) { - num_palette = ((DataPaletteHash) palette).b(); - } else { - num_palette = 0; - int[] paletteToBlockInts = FaweCache.PALETTE_TO_BLOCK.get(); char[] paletteToBlockChars = FaweCache.PALETTE_TO_BLOCK_CHAR.get(); try { + for (int i = 0; i < num_palette; i++) { + IBlockData ibd = palette.a(i); + char ordinal; + if (ibd == null) { + ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar(); + System.out.println("Invalid palette"); + } else { + ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToChar(ibd); + } + paletteToBlockChars[i] = ordinal; + } for (int i = 0; i < 4096; i++) { char paletteVal = data[i]; - char ordinal = paletteToBlockChars[paletteVal]; - if (ordinal == Character.MAX_VALUE) { - paletteToBlockInts[num_palette++] = paletteVal; - IBlockData ibd = palette.a(data[i]); - if (ibd == null) { - ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar(); - } else { - ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToChar(ibd); - } - paletteToBlockChars[paletteVal] = ordinal; - } - data[i] = ordinal; + data[i] = paletteToBlockChars[paletteVal]; } } finally { for (int i = 0; i < num_palette; i++) { - int paletteVal = paletteToBlockInts[i]; - paletteToBlockChars[paletteVal] = Character.MAX_VALUE; + paletteToBlockChars[i] = Character.MAX_VALUE; } } - return data; + } catch (IllegalAccessException e) { + e.printStackTrace(); + throw new RuntimeException(e); } - - char[] paletteToBlockChars = FaweCache.PALETTE_TO_BLOCK_CHAR.get(); - try { - for (int i = 0; i < num_palette; i++) { - IBlockData ibd = palette.a(i); - char ordinal; - if (ibd == null) { - ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar(); - System.out.println("Invalid palette"); - } else { - ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToChar(ibd); - } - paletteToBlockChars[i] = ordinal; - } - for (int i = 0; i < 4096; i++) { - char paletteVal = data[i]; - data[i] = paletteToBlockChars[paletteVal]; - } - } finally { - for (int i = 0; i < num_palette; i++) { - paletteToBlockChars[i] = Character.MAX_VALUE; - } - } - } catch (IllegalAccessException e) { - e.printStackTrace(); - throw new RuntimeException(e); + return data; } - return data; } public ChunkSection[] getSections() { ChunkSection[] tmp = sections; if (tmp == null) { - Chunk chunk = getChunk(); - sections = tmp = chunk.getSections(); + synchronized (this) { + tmp = sections; + if (tmp == null) { + Chunk chunk = getChunk(); + sections = tmp = chunk.getSections().clone(); + } + } } return tmp; } @@ -148,7 +160,12 @@ public class BukkitGetBlocks extends CharGetBlocks { public Chunk getChunk() { Chunk tmp = nmsChunk; if (tmp == null) { - nmsChunk = tmp = BukkitQueue.ensureLoaded(nmsWorld, X, Z); + synchronized (this) { + tmp = nmsChunk; + if (tmp == null) { + nmsChunk = tmp = BukkitQueue.ensureLoaded(nmsWorld, X, Z); + } + } } return tmp; } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java index f63dfd327..c7803c6c2 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java @@ -17,6 +17,7 @@ import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BlockID; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; +import net.jpountz.util.UnsafeUtils; import net.minecraft.server.v1_13_R2.Block; import net.minecraft.server.v1_13_R2.Chunk; import net.minecraft.server.v1_13_R2.ChunkCoordIntPair; @@ -34,9 +35,13 @@ import org.bukkit.craftbukkit.v1_13_R2.CraftChunk; import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.concurrent.locks.ReentrantLock; + +import sun.misc.Unsafe; import static com.google.common.base.Preconditions.checkNotNull; @@ -99,6 +104,11 @@ public class BukkitQueue extends SimpleCharQueueExtent { public final static Field fieldTickingBlockCount; public final static Field fieldNonEmptyBlockCount; + private static final int CHUNKSECTION_BASE; + private static final int CHUNKSECTION_SHIFT; + + private static final Field fieldLock; + static { try { fieldSize = DataPaletteBlock.class.getDeclaredField("i"); @@ -114,6 +124,20 @@ public class BukkitQueue extends SimpleCharQueueExtent { fieldTickingBlockCount.setAccessible(true); fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount"); fieldNonEmptyBlockCount.setAccessible(true); + + fieldLock = DataPaletteBlock.class.getDeclaredField("j"); + fieldLock.setAccessible(true); + Field modifiersField = Field.class.getDeclaredField("modifiers"); + int modifiers = modifiersField.getInt(fieldLock); + modifiers &= ~Modifier.FINAL; + modifiersField.setInt(fieldLock, modifiers); + + Unsafe unsafe = UnsafeUtils.getUNSAFE(); + CHUNKSECTION_BASE = unsafe.arrayBaseOffset(ChunkSection[].class); + int scale = unsafe.arrayIndexScale(ChunkSection[].class); + if ((scale & (scale - 1)) != 0) + throw new Error("data type scale not a power of two"); + CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale); } catch (RuntimeException e) { throw e; } catch (Throwable rethrow) { @@ -122,6 +146,32 @@ public class BukkitQueue extends SimpleCharQueueExtent { } } + public static boolean setSectionAtomic(ChunkSection[] sections, ChunkSection expected, ChunkSection value, int layer) { + long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE; + if (layer >= 0 && layer < sections.length) { + return UnsafeUtils.getUNSAFE().compareAndSwapObject(sections, offset, expected, value); + } + return false; + } + + public static DelegateLock applyLock(ChunkSection section) { + try { + synchronized (section) { + DataPaletteBlock blocks = section.getBlocks(); + ReentrantLock currentLock = (ReentrantLock) fieldLock.get(blocks); + if (currentLock instanceof DelegateLock) { + return (DelegateLock) currentLock; + } + DelegateLock newLock = new DelegateLock(currentLock); + fieldLock.set(blocks, newLock); + return newLock; + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + private static boolean PAPER = true; public Chunk ensureLoaded(int X, int Z) { diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/DelegateLock.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/DelegateLock.java index 59bfccd3b..20f94166c 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/DelegateLock.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/DelegateLock.java @@ -13,6 +13,14 @@ public class DelegateLock extends ReentrantLock { this.parent = parent; } + public boolean isModified() { + return modified; + } + + public void setModified(boolean modified) { + this.modified = modified; + } + @Override public void lock() { modified = true; @@ -35,12 +43,16 @@ public class DelegateLock extends ReentrantLock { } @Override - public synchronized void unlock() { + public void unlock() { modified = true; parent.unlock(); this.notifyAll(); } + public ReentrantLock getParent() { + return parent; + } + @Override public synchronized Condition newCondition() { return parent.newCondition(); 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 9da4c0f3e..4f57656be 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 @@ -78,6 +78,10 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { // Pool discarded chunks for reuse (can safely be cleared by another thread) private static final ConcurrentLinkedQueue CHUNK_POOL = new ConcurrentLinkedQueue<>(); + public void returnToPool(IChunk chunk) { + CHUNK_POOL.add(chunk); + } + @Override public > T submit(final IChunk chunk) { if (chunk.isEmpty()) { @@ -123,7 +127,6 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { private IChunk poolOrCreate(final int X, final int Z) { IChunk next = CHUNK_POOL.poll(); if (next == null) { - System.out.println("Create"); next = create(false); } next.init(this, X, Z); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java index c348f8d18..7005b5ed1 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java @@ -30,6 +30,10 @@ public class CharBlocks implements IBlocks { for (int i = 0; i < 16; i++) sections[i] = NULL; } + public void reset(int layer) { + sections[layer] = NULL; + } + protected char[] load(int layer) { return new char[4096]; } diff --git a/worldedit-core/src/main/java/net/jpountz/util/UnsafeUtils.java b/worldedit-core/src/main/java/net/jpountz/util/UnsafeUtils.java index dbb24ccb5..665616011 100644 --- a/worldedit-core/src/main/java/net/jpountz/util/UnsafeUtils.java +++ b/worldedit-core/src/main/java/net/jpountz/util/UnsafeUtils.java @@ -144,4 +144,8 @@ public enum UnsafeUtils { public static void writeShort(short[] dest, int destOff, int value) { UNSAFE.putShort(dest, SHORT_ARRAY_OFFSET + SHORT_ARRAY_SCALE * destOff, (short) value); } + + public static Unsafe getUNSAFE() { + return UNSAFE; + } } From 18e6c09fdd95aabafa342d3520282795ec7373f9 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Thu, 2 May 2019 04:30:32 +1000 Subject: [PATCH 10/54] use paper writeLock --- .../boydti/fawe/bukkit/beta/BukkitQueue.java | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java index c7803c6c2..18660c6e6 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java @@ -125,12 +125,20 @@ public class BukkitQueue extends SimpleCharQueueExtent { fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount"); fieldNonEmptyBlockCount.setAccessible(true); - fieldLock = DataPaletteBlock.class.getDeclaredField("j"); - fieldLock.setAccessible(true); - Field modifiersField = Field.class.getDeclaredField("modifiers"); - int modifiers = modifiersField.getInt(fieldLock); - modifiers &= ~Modifier.FINAL; - modifiersField.setInt(fieldLock, modifiers); + { + Field tmp = null; + try { + tmp = DataPaletteBlock.class.getDeclaredField("j"); + } catch (NoSuchFieldException paper) { + tmp = DataPaletteBlock.class.getDeclaredField("writeLock"); + } + fieldLock = tmp; + fieldLock.setAccessible(true); + Field modifiersField = Field.class.getDeclaredField("modifiers"); + int modifiers = modifiersField.getInt(fieldLock); + int newModifiers = modifiers & (~Modifier.FINAL); + if (newModifiers != modifiers) modifiersField.setInt(fieldLock, newModifiers); + } Unsafe unsafe = UnsafeUtils.getUNSAFE(); CHUNKSECTION_BASE = unsafe.arrayBaseOffset(ChunkSection[].class); From 4619fd2b496a31ec9957208bcd1df6b5ef86963e Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Thu, 2 May 2019 05:02:11 +1000 Subject: [PATCH 11/54] Reuse get array after apply --- .../fawe/bukkit/beta/BukkitChunkHolder.java | 25 +++++++-- .../fawe/bukkit/beta/BukkitGetBlocks.java | 5 +- .../boydti/fawe/bukkit/beta/BukkitQueue.java | 9 ++-- .../boydti/fawe/bukkit/beta/DelegateLock.java | 53 +++++++++++++++---- 4 files changed, 71 insertions(+), 21 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java index 4dc63bf9f..956d874a1 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java @@ -28,6 +28,23 @@ public class BukkitChunkHolder> extends ChunkHolder { return new BukkitGetBlocks(extent.getNmsWorld(), getX(), getZ()); } + private void updateGet(BukkitGetBlocks get, Chunk nmsChunk, ChunkSection[] sections, ChunkSection section, char[] arr, int layer) { + synchronized (get) { + if (get.nmsChunk != nmsChunk) { + get.nmsChunk = nmsChunk; + get.sections = sections.clone(); + get.reset(); + } + if (get.sections == null) { + get.sections = sections; + } + if (get.sections[layer] != section) { + get.sections[layer] = section; + } + get.blocks[layer] = arr; + } + } + @Override public T call() { BukkitQueue extent = (BukkitQueue) getExtent(); @@ -51,6 +68,7 @@ public class BukkitChunkHolder> extends ChunkHolder { if (existingSection == null) { newSection = extent.newChunkSection(layer, hasSky, setArr); if (BukkitQueue.setSectionAtomic(sections, null, newSection, layer)) { + updateGet(get, nmsChunk, sections, newSection, setArr, layer); continue; } else { existingSection = sections[layer]; @@ -62,10 +80,7 @@ public class BukkitChunkHolder> extends ChunkHolder { } DelegateLock lock = BukkitQueue.applyLock(existingSection); synchronized (lock) { - if (lock.isLocked()) { - lock.lock(); - lock.unlock(); - } + lock.untilFree(); synchronized (get) { ChunkSection getSection; if (get.nmsChunk != nmsChunk) { @@ -95,6 +110,8 @@ public class BukkitChunkHolder> extends ChunkHolder { if (!BukkitQueue.setSectionAtomic(sections, existingSection, newSection, layer)) { System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer); continue; + } else { + updateGet(get, nmsChunk, sections, newSection, setArr, layer); } } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java index e0f2328c6..958f5037d 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java @@ -64,10 +64,7 @@ public class BukkitGetBlocks extends CharGetBlocks { } DelegateLock lock = BukkitQueue.applyLock(section); synchronized (lock) { - if (lock.isLocked()) { - lock.lock(); - lock.unlock(); - } + lock.untilFree(); lock.setModified(false); // Efficiently convert ChunkSection to raw data try { diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java index 18660c6e6..70971042c 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java @@ -39,7 +39,9 @@ import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import sun.misc.Unsafe; @@ -135,6 +137,7 @@ public class BukkitQueue extends SimpleCharQueueExtent { fieldLock = tmp; fieldLock.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); int modifiers = modifiersField.getInt(fieldLock); int newModifiers = modifiers & (~Modifier.FINAL); if (newModifiers != modifiers) modifiersField.setInt(fieldLock, newModifiers); @@ -154,7 +157,7 @@ public class BukkitQueue extends SimpleCharQueueExtent { } } - public static boolean setSectionAtomic(ChunkSection[] sections, ChunkSection expected, ChunkSection value, int layer) { + protected static boolean setSectionAtomic(ChunkSection[] sections, ChunkSection expected, ChunkSection value, int layer) { long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE; if (layer >= 0 && layer < sections.length) { return UnsafeUtils.getUNSAFE().compareAndSwapObject(sections, offset, expected, value); @@ -162,11 +165,11 @@ public class BukkitQueue extends SimpleCharQueueExtent { return false; } - public static DelegateLock applyLock(ChunkSection section) { + protected static DelegateLock applyLock(ChunkSection section) { try { synchronized (section) { DataPaletteBlock blocks = section.getBlocks(); - ReentrantLock currentLock = (ReentrantLock) fieldLock.get(blocks); + Lock currentLock = (Lock) fieldLock.get(blocks); if (currentLock instanceof DelegateLock) { return (DelegateLock) currentLock; } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/DelegateLock.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/DelegateLock.java index 20f94166c..6d79d967e 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/DelegateLock.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/DelegateLock.java @@ -1,16 +1,27 @@ package com.boydti.fawe.bukkit.beta; +import org.apache.commons.lang.mutable.MutableInt; + import java.util.Collection; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.LongAdder; import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class DelegateLock extends ReentrantLock { - private final ReentrantLock parent; + private final Lock parent; private volatile boolean modified; + private final AtomicInteger count; - public DelegateLock(ReentrantLock parent) { + public DelegateLock(Lock parent) { this.parent = parent; + if (!(parent instanceof ReentrantLock)) { + count = new AtomicInteger(); + } else { + count = null; + } } public boolean isModified() { @@ -22,9 +33,12 @@ public class DelegateLock extends ReentrantLock { } @Override - public void lock() { + public synchronized void lock() { modified = true; parent.lock(); + if (count != null) { + count.incrementAndGet(); + } } @Override @@ -46,10 +60,14 @@ public class DelegateLock extends ReentrantLock { public void unlock() { modified = true; parent.unlock(); - this.notifyAll(); + if (count != null) { + if (count.getAndDecrement() <= 0) { + count.incrementAndGet(); + } + } } - public ReentrantLock getParent() { + public Lock getParent() { return parent; } @@ -60,27 +78,42 @@ public class DelegateLock extends ReentrantLock { @Override public synchronized int getHoldCount() { - return parent.getHoldCount(); + throw new UnsupportedOperationException(); } @Override public synchronized boolean isHeldByCurrentThread() { - return parent.isHeldByCurrentThread(); + throw new UnsupportedOperationException(); } @Override public synchronized boolean isLocked() { - return parent.isLocked(); + if (parent instanceof ReentrantLock) { + return ((ReentrantLock) parent).isLocked(); + } + return count.get() > 0; + } + + public void untilFree() { + if (parent instanceof ReentrantLock) { + ReentrantLock rl = (ReentrantLock) parent; + if (rl.isLocked()) { + rl.lock(); + rl.unlock(); + } + return; + } + while (count.get() > 0); } @Override public synchronized boolean hasWaiters(Condition condition) { - return parent.hasWaiters(condition); + throw new UnsupportedOperationException(); } @Override public synchronized int getWaitQueueLength(Condition condition) { - return parent.getWaitQueueLength(condition); + throw new UnsupportedOperationException(); } @Override From ad52e01e9f236bd193efa3d5f79a4add65e239b0 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Thu, 2 May 2019 05:19:25 +1000 Subject: [PATCH 12/54] update players --- .../fawe/bukkit/beta/BukkitChunkHolder.java | 15 ++++- .../boydti/fawe/bukkit/beta/BukkitQueue.java | 55 +++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java index 956d874a1..39361de84 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java @@ -54,6 +54,7 @@ public class BukkitChunkHolder> extends ChunkHolder { int Z = getZ(); Chunk nmsChunk = extent.ensureLoaded(X, Z); + int bitMask = 0; try { synchronized (nmsChunk) { ChunkSection[] sections = nmsChunk.getSections(); @@ -62,6 +63,9 @@ public class BukkitChunkHolder> extends ChunkHolder { for (int layer = 0; layer < 16; layer++) { if (!set.hasSection(layer)) continue; + + bitMask |= 1 << layer; + char[] setArr = set.blocks[layer]; ChunkSection newSection; ChunkSection existingSection = sections[layer]; @@ -84,10 +88,10 @@ public class BukkitChunkHolder> extends ChunkHolder { synchronized (get) { ChunkSection getSection; if (get.nmsChunk != nmsChunk) { + if (get.nmsChunk != null) System.out.println("chunk doesn't match"); get.nmsChunk = nmsChunk; get.sections = null; get.reset(); - System.out.println("chunk doesn't match"); } else { getSection = get.getSections()[layer]; if (getSection != existingSection) { @@ -118,6 +122,15 @@ public class BukkitChunkHolder> extends ChunkHolder { } } } finally { + if (bitMask != 0) { + // Set Modified + nmsChunk.f(true); + nmsChunk.mustSave = true; + nmsChunk.markDirty(); + // send to player + extent.sendChunk(X, Z, bitMask); + } + extent.returnToPool(this); } /* diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java index 70971042c..debf5283c 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java @@ -29,6 +29,8 @@ import net.minecraft.server.v1_13_R2.DataPaletteBlock; import net.minecraft.server.v1_13_R2.DataPaletteLinear; import net.minecraft.server.v1_13_R2.GameProfileSerializer; import net.minecraft.server.v1_13_R2.IBlockData; +import net.minecraft.server.v1_13_R2.PlayerChunk; +import net.minecraft.server.v1_13_R2.PlayerChunkMap; import net.minecraft.server.v1_13_R2.WorldServer; import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_13_R2.CraftChunk; @@ -42,6 +44,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.Supplier; import sun.misc.Unsafe; @@ -106,6 +109,9 @@ public class BukkitQueue extends SimpleCharQueueExtent { public final static Field fieldTickingBlockCount; public final static Field fieldNonEmptyBlockCount; + private final static Field fieldDirtyCount; + private final static Field fieldDirtyBits; + private static final int CHUNKSECTION_BASE; private static final int CHUNKSECTION_SHIFT; @@ -127,6 +133,11 @@ public class BukkitQueue extends SimpleCharQueueExtent { fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount"); fieldNonEmptyBlockCount.setAccessible(true); + fieldDirtyCount = PlayerChunk.class.getDeclaredField("dirtyCount"); + fieldDirtyCount.setAccessible(true); + fieldDirtyBits = PlayerChunk.class.getDeclaredField("h"); + fieldDirtyBits.setAccessible(true); + { Field tmp = null; try { @@ -217,6 +228,50 @@ public class BukkitQueue extends SimpleCharQueueExtent { return TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(X, Z)); } + private PlayerChunk getPlayerChunk(final int cx, final int cz) { + final PlayerChunkMap chunkMap = nmsWorld.getPlayerChunkMap(); + final PlayerChunk playerChunk = chunkMap.getChunk(cx, cz); + if (playerChunk == null) { + return null; + } + if (playerChunk.players.isEmpty()) { + return null; + } + return playerChunk; + } + + public boolean sendChunk(final int X, final int Z, final int mask) { + PlayerChunk playerChunk = getPlayerChunk(X, Z); + if (playerChunk == null) { + return false; + } + if (playerChunk.e()) { + TaskManager.IMP.sync(new Supplier() { + @Override + public Object get() { + try { + int dirtyBits = fieldDirtyBits.getInt(playerChunk); + if (dirtyBits == 0) { + nmsWorld.getPlayerChunkMap().a(playerChunk); + } + if (mask == 0) { + dirtyBits = 65535; + } else { + dirtyBits |= mask; + } + + fieldDirtyBits.set(playerChunk, dirtyBits); + fieldDirtyCount.set(playerChunk, 64); + } catch (final IllegalAccessException e) { + e.printStackTrace(); + } + return null; + } + }); + } + return true; + } + /* NMS conversion */ From 8dcc005ec14b63b70ec1e0aefd2bbf72cb05bb86 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Thu, 2 May 2019 18:27:33 +1000 Subject: [PATCH 13/54] tile/biome/entity set --- .../fawe/bukkit/beta/BukkitChunkHolder.java | 357 +++++++++++++----- .../fawe/bukkit/beta/BukkitGetBlocks.java | 5 +- .../java/com/boydti/fawe/beta/ISetBlocks.java | 10 + .../beta/implementation/QueueHandler.java | 30 +- .../implementation/blocks/CharSetBlocks.java | 37 +- .../worldedit/command/RegionCommands.java | 4 +- 6 files changed, 351 insertions(+), 92 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java index 39361de84..95d67c85b 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java @@ -1,18 +1,51 @@ package com.boydti.fawe.bukkit.beta; +import com.boydti.fawe.Fawe; import com.boydti.fawe.beta.Filter; import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.IGetBlocks; import com.boydti.fawe.beta.IQueueExtent; +import com.boydti.fawe.beta.implementation.QueueHandler; import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks; import com.boydti.fawe.beta.implementation.holder.ChunkHolder; +import com.boydti.fawe.bukkit.v0.BukkitQueue_0; +import com.boydti.fawe.bukkit.v1_13.BukkitQueue_1_13; +import com.boydti.fawe.util.ReflectionUtils; import com.google.common.util.concurrent.Futures; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.LongTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.world.biome.BiomeType; import net.jpountz.util.UnsafeUtils; +import net.minecraft.server.v1_13_R2.BiomeBase; +import net.minecraft.server.v1_13_R2.BlockPosition; import net.minecraft.server.v1_13_R2.Chunk; import net.minecraft.server.v1_13_R2.ChunkSection; +import net.minecraft.server.v1_13_R2.Entity; +import net.minecraft.server.v1_13_R2.EntityTypes; +import net.minecraft.server.v1_13_R2.MinecraftKey; +import net.minecraft.server.v1_13_R2.NBTTagCompound; +import net.minecraft.server.v1_13_R2.NBTTagInt; +import net.minecraft.server.v1_13_R2.TileEntity; import org.bukkit.World; +import org.bukkit.block.Biome; +import org.bukkit.craftbukkit.v1_13_R2.block.CraftBlock; +import org.bukkit.event.entity.CreatureSpawnEvent; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Callable; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicReferenceArray; @@ -54,109 +87,263 @@ public class BukkitChunkHolder> extends ChunkHolder { int Z = getZ(); Chunk nmsChunk = extent.ensureLoaded(X, Z); + + // Remove existing tiles + { + Map tiles = nmsChunk.getTileEntities(); + if (!tiles.isEmpty()) { + final Iterator> iterator = tiles.entrySet().iterator(); + while (iterator.hasNext()) { + final Map.Entry entry = iterator.next(); + final BlockPosition pos = entry.getKey(); + final int lx = pos.getX() & 15; + final int ly = pos.getY(); + final int lz = pos.getZ() & 15; + final int layer = ly >> 4; + final char[] array = set.blocks[layer]; + if (array == null) { + continue; + } + final int index = (((ly & 0xF) << 8) | (lz << 4) | lx); + if (array[index] != 0) { + TileEntity tile = entry.getValue(); + tile.z(); + tile.invalidateBlockCache(); + } + } + } + } + + int bitMask = 0; - try { - synchronized (nmsChunk) { - ChunkSection[] sections = nmsChunk.getSections(); - World world = extent.getBukkitWorld(); - boolean hasSky = world.getEnvironment() == World.Environment.NORMAL; + synchronized (nmsChunk) { + ChunkSection[] sections = nmsChunk.getSections(); + World world = extent.getBukkitWorld(); + boolean hasSky = world.getEnvironment() == World.Environment.NORMAL; - for (int layer = 0; layer < 16; layer++) { - if (!set.hasSection(layer)) continue; + for (int layer = 0; layer < 16; layer++) { + if (!set.hasSection(layer)) continue; - bitMask |= 1 << layer; + bitMask |= 1 << layer; - char[] setArr = set.blocks[layer]; - ChunkSection newSection; - ChunkSection existingSection = sections[layer]; - if (existingSection == null) { - newSection = extent.newChunkSection(layer, hasSky, setArr); - if (BukkitQueue.setSectionAtomic(sections, null, newSection, layer)) { - updateGet(get, nmsChunk, sections, newSection, setArr, layer); + char[] setArr = set.blocks[layer]; + ChunkSection newSection; + ChunkSection existingSection = sections[layer]; + if (existingSection == null) { + newSection = extent.newChunkSection(layer, hasSky, setArr); + if (BukkitQueue.setSectionAtomic(sections, null, newSection, layer)) { + updateGet(get, nmsChunk, sections, newSection, setArr, layer); + continue; + } else { + existingSection = sections[layer]; + if (existingSection == null) { + System.out.println("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer); continue; - } else { - existingSection = sections[layer]; - if (existingSection == null) { - System.out.println("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer); - continue; - } } } - DelegateLock lock = BukkitQueue.applyLock(existingSection); - synchronized (lock) { - lock.untilFree(); - synchronized (get) { - ChunkSection getSection; - if (get.nmsChunk != nmsChunk) { - if (get.nmsChunk != null) System.out.println("chunk doesn't match"); - get.nmsChunk = nmsChunk; - get.sections = null; + } + DelegateLock lock = BukkitQueue.applyLock(existingSection); + synchronized (lock) { + lock.untilFree(); + synchronized (get) { + ChunkSection getSection; + if (get.nmsChunk != nmsChunk) { + if (get.nmsChunk != null) System.out.println("chunk doesn't match"); + get.nmsChunk = nmsChunk; + get.sections = null; + get.reset(); + } else { + getSection = get.getSections()[layer]; + if (getSection != existingSection) { + get.sections[layer] = existingSection; get.reset(); - } else { - getSection = get.getSections()[layer]; - if (getSection != existingSection) { - get.sections[layer] = existingSection; - get.reset(); - System.out.println("Section doesn't match"); - } else if (lock.isModified()) { - System.out.println("lock is outdated"); - get.reset(layer); - } + System.out.println("Section doesn't match"); + } else if (lock.isModified()) { + System.out.println("lock is outdated"); + get.reset(layer); } - char[] getArr = get.load(layer); - for (int i = 0; i < 4096; i++) { - char value = setArr[i]; - if (value != 0) { - getArr[i] = value; - } - } - newSection = extent.newChunkSection(layer, hasSky, getArr); - if (!BukkitQueue.setSectionAtomic(sections, existingSection, newSection, layer)) { - System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer); - continue; - } else { - updateGet(get, nmsChunk, sections, newSection, setArr, layer); + } + char[] getArr = get.load(layer); + for (int i = 0; i < 4096; i++) { + char value = setArr[i]; + if (value != 0) { + getArr[i] = value; } } + newSection = extent.newChunkSection(layer, hasSky, getArr); + if (!BukkitQueue.setSectionAtomic(sections, existingSection, newSection, layer)) { + System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer); + continue; + } else { + updateGet(get, nmsChunk, sections, newSection, setArr, layer); + } } } } - } finally { - if (bitMask != 0) { - // Set Modified - nmsChunk.f(true); - nmsChunk.mustSave = true; - nmsChunk.markDirty(); - // send to player - extent.sendChunk(X, Z, bitMask); + + // Biomes + if (set.biomes != null) { + // set biomes + final BiomeBase[] currentBiomes = nmsChunk.getBiomeIndex(); + for (int i = 0; i < set.biomes.length; i++) { + final BiomeType biome = set.biomes[i]; + if (biome != null) { + final Biome craftBiome = BukkitAdapter.adapt(biome); + currentBiomes[i] = CraftBlock.biomeToBiomeBase(craftBiome); + } + } } - extent.returnToPool(this); + Runnable[] syncTasks = null; + + net.minecraft.server.v1_13_R2.World nmsWorld = nmsChunk.getWorld(); + int bx = X << 4; + int bz = Z << 4; + + if (set.entityRemoves != null && !set.entityRemoves.isEmpty()) { + if (syncTasks == null) syncTasks = new Runnable[3]; + + HashSet entsToRemove = set.entityRemoves; + + syncTasks[2] = new Runnable() { + @Override + public void run() { + final List[] entities = nmsChunk.getEntitySlices(); + + for (int i = 0; i < entities.length; i++) { + final Collection ents = entities[i]; + if (!ents.isEmpty()) { + final Iterator iter = ents.iterator(); + while (iter.hasNext()) { + final Entity entity = iter.next(); + if (entsToRemove.contains(entity.getUniqueID())) { + iter.remove(); + entity.b(false); + entity.die(); + entity.valid = false; + } + } + } + } + } + }; + } + + if (set.entities != null && !set.entities.isEmpty()) { + if (syncTasks == null) syncTasks = new Runnable[2]; + + HashSet entitiesToSpawn = set.entities; + + syncTasks[1] = new Runnable() { + @Override + public void run() { + for (final CompoundTag nativeTag : entitiesToSpawn) { + final Map entityTagMap = ReflectionUtils.getMap(nativeTag.getValue()); + final StringTag idTag = (StringTag) entityTagMap.get("Id"); + final ListTag posTag = (ListTag) entityTagMap.get("Pos"); + final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); + if (idTag == null || posTag == null || rotTag == null) { + Fawe.debug("Unknown entity tag: " + nativeTag); + continue; + } + final double x = posTag.getDouble(0); + final double y = posTag.getDouble(1); + final double z = posTag.getDouble(2); + final float yaw = rotTag.getFloat(0); + final float pitch = rotTag.getFloat(1); + final String id = idTag.getValue(); + final Entity entity = EntityTypes.a(nmsWorld, new MinecraftKey(id)); + if (entity != null) { + final UUID uuid = entity.getUniqueID(); + entityTagMap.put("UUIDMost", new LongTag(uuid.getMostSignificantBits())); + entityTagMap.put("UUIDLeast", new LongTag(uuid.getLeastSignificantBits())); + if (nativeTag != null) { + final NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_13.fromNative(nativeTag); + for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + tag.remove(name); + } + entity.f(tag); + } + entity.setLocation(x, y, z, yaw, pitch); + nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM); + } + } + } + }; + + } + + // set tiles + if (set.tiles != null && !set.tiles.isEmpty()) { + if (syncTasks == null) syncTasks = new Runnable[1]; + + HashMap tiles = set.tiles; + syncTasks[0] = new Runnable() { + @Override + public void run() { + for (final Map.Entry entry : tiles.entrySet()) { + final CompoundTag nativeTag = entry.getValue(); + final short blockHash = entry.getKey(); + final int x = (blockHash >> 12 & 0xF) + bx; + final int y = (blockHash & 0xFF); + final int z = (blockHash >> 8 & 0xF) + bz; + final BlockPosition pos = new BlockPosition(x, y, z); + synchronized (BukkitQueue_0.class) { + TileEntity tileEntity = nmsWorld.getTileEntity(pos); + if (tileEntity == null || tileEntity.x()) { + nmsWorld.n(pos); + tileEntity = nmsWorld.getTileEntity(pos); + } + if (tileEntity != null) { + final NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_13.fromNative(nativeTag); + tag.set("x", new NBTTagInt(x)); + tag.set("y", new NBTTagInt(y)); + tag.set("z", new NBTTagInt(z)); + tileEntity.load(tag); + } + } + } + } + }; + } + + int finalMask = bitMask; + Runnable callback = () -> { + if (finalMask != 0) { + // Set Modified + nmsChunk.f(true); + nmsChunk.mustSave = true; + nmsChunk.markDirty(); + // send to player + extent.sendChunk(X, Z, finalMask); + } + + extent.returnToPool(BukkitChunkHolder.this); + }; + if (syncTasks != null) { + QueueHandler queueHandler = Fawe.get().getQueueHandler(); + Runnable[] finalSyncTasks = syncTasks; + + // Chain the sync tasks and the callback + Callable chain = new Callable() { + @Override + public Future call() { + // Run the sync tasks + for (int i = 1; i < finalSyncTasks.length; i++) { + Runnable task = finalSyncTasks[i]; + if (task != null) { + task.run(); + } + } + return queueHandler.async(callback, null); + } + }; + return (T) queueHandler.sync(chain); + } else { + callback.run(); + } } - /* - - - getBlocks - - set ChunkSection lock with a tracking lock - - synchronize on chunk object (so no other FAWE thread updates it at the same time) - - verify cached section is same object as NMS chunk section - otherwise, fetch the new section, set the tracking lock and reconstruct the getBlocks array - - Merge raw getBlocks and setBlocks array - - Construct the ChunkSection - - In parallel on the main thread - - if the tracking lock has had no updates and the cached ChunkSection == the NMS chunk section - - Otherwise, reconstruct the ChunkSection (TODO: Benchmark if this is a performance concern) - - swap in the new ChunkSection - - Update tile entities/entities (if necessary) - - Merge the biome array (if necessary) - - set chunk status to needs relighting - - mark as dirty - - */ - -// throw new UnsupportedOperationException("Not implemented"); -// return true; return null; -// return (T) (Future) Futures.immediateFuture(null); } @Override diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java index 958f5037d..2f114780c 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java @@ -53,7 +53,7 @@ public class BukkitGetBlocks extends CharGetBlocks { } @Override - public char[] load(int layer, char[] data) { + public synchronized char[] load(int layer, char[] data) { ChunkSection section = getSections()[layer]; // Section is null, return empty array if (section == null) { @@ -126,6 +126,9 @@ public class BukkitGetBlocks extends CharGetBlocks { for (int i = 0; i < 4096; i++) { char paletteVal = data[i]; data[i] = paletteToBlockChars[paletteVal]; + if (data[i] == Character.MAX_VALUE) { + System.out.println("Invalid " + paletteVal + " | " + num_palette); + } } } finally { for (int i = 0; i < num_palette; i++) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java index f7dfd1bd8..51fcd9dc9 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java @@ -1,8 +1,12 @@ package com.boydti.fawe.beta; +import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockStateHolder; +import java.util.HashSet; +import java.util.UUID; + /** * Interface for setting blocks */ @@ -13,6 +17,12 @@ public interface ISetBlocks extends IBlocks { boolean isEmpty(); + void setTile(int x, int y, int z, CompoundTag tile); + + void setEntity(CompoundTag tag); + + void removeEntity(UUID uuid); + default void optimize() { } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java index 972a2cd15..a6e589f88 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java @@ -20,11 +20,13 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; +import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinTask; import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; import java.util.concurrent.ThreadPoolExecutor; /** @@ -34,7 +36,7 @@ public abstract class QueueHandler implements Trimable { private ForkJoinPool forkJoinPoolPrimary = new ForkJoinPool(); private ForkJoinPool forkJoinPoolSecondary = new ForkJoinPool(); private ThreadPoolExecutor blockingExecutor = FaweCache.newBlockingExecutor(); - private ConcurrentLinkedQueue syncTasks = new ConcurrentLinkedQueue(); + private ConcurrentLinkedQueue syncTasks = new ConcurrentLinkedQueue(); private Map> chunkCache = new HashMap<>(); private IterableThreadLocal queuePool = new IterableThreadLocal() { @@ -44,6 +46,32 @@ public abstract class QueueHandler implements Trimable { } }; + public Future async(Runnable run, T value) { + return forkJoinPoolSecondary.submit(run, value); + } + + public Future async(Callable call) { + return forkJoinPoolSecondary.submit(call); + } + + public Future sync(Runnable run, T value) { + FutureTask result = new FutureTask<>(run, value); + syncTasks.add(result); + return result; + } + + public Future sync(Runnable run) { + FutureTask result = new FutureTask<>(run, null); + syncTasks.add(result); + return result; + } + + public Future sync(Callable call) { + FutureTask result = new FutureTask<>(call); + syncTasks.add(result); + return result; + } + public > T submit(IChunk chunk) { if (MemUtil.isMemoryFree()) { // return (T) forkJoinPoolSecondary.submit(chunk); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java index 9be7c4391..d962d5f86 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java @@ -1,6 +1,7 @@ package com.boydti.fawe.beta.implementation.blocks; import com.boydti.fawe.beta.ISetBlocks; +import com.boydti.fawe.util.MathMan; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -10,10 +11,10 @@ import java.util.HashSet; import java.util.UUID; public class CharSetBlocks extends CharBlocks implements ISetBlocks { - private BiomeType[] biomes; - private HashMap tiles; - private HashSet entities; - private HashSet entityRemoves; + public BiomeType[] biomes; + public HashMap tiles; + public HashSet entities; + public HashSet entityRemoves; @Override public boolean setBiome(int x, int y, int z, BiomeType biome) { @@ -30,6 +31,31 @@ public class CharSetBlocks extends CharBlocks implements ISetBlocks { return true; } + @Override + public void setTile(int x, int y, int z, CompoundTag tile) { + if (tiles == null) { + tiles = new HashMap<>(); + } + short pair = MathMan.tripleBlockCoord(x, y, z); + tiles.put(pair, tile); + } + + @Override + public void setEntity(CompoundTag tag) { + if (entities == null) { + entities = new HashSet<>(); + } + entities.add(tag); + } + + @Override + public void removeEntity(UUID uuid) { + if (entityRemoves == null) { + entityRemoves = new HashSet<>(); + } + entityRemoves.add(uuid); + } + @Override public boolean isEmpty() { if (biomes != null) return false; @@ -44,6 +70,9 @@ public class CharSetBlocks extends CharBlocks implements ISetBlocks { @Override public void reset() { biomes = null; + tiles = null; + entities = null; + entityRemoves = null; super.reset(); } } \ No newline at end of file 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 d02d2dd03..8a5da394a 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 @@ -302,9 +302,11 @@ public class RegionCommands extends MethodCommands { for (BlockVector3 p : region) { queue.setBlock(p.getX(), p.getY(), p.getZ(), block); } + long start2 = System.currentTimeMillis(); queue.flush(); long diff = System.currentTimeMillis() - start; - System.out.println(diff); + long diff2 = System.currentTimeMillis() - start2; + System.out.println(diff + " | " + diff2); } @Command( From f5944fbcaf4fe197542b198d8f6bf8ffc97bb243 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Fri, 3 May 2019 00:45:03 +1000 Subject: [PATCH 14/54] filter set --- .../com/boydti/fawe/bukkit/FaweBukkit.java | 6 + .../adapter/v1_13_1/Spigot_v1_13_R2.java | 10 +- .../fawe/bukkit/beta/BukkitChunkHolder.java | 484 +++++++++--------- .../fawe/bukkit/beta/BukkitGetBlocks.java | 42 +- .../com/boydti/fawe/beta/CharFilterBlock.java | 167 ++++-- .../com/boydti/fawe/beta/ChunkFuture.java | 6 +- .../java/com/boydti/fawe/beta/Filter.java | 2 +- .../com/boydti/fawe/beta/FilterBlock.java | 15 +- .../com/boydti/fawe/beta/IDelegateChunk.java | 6 +- .../fawe/beta/IDelegateQueueExtent.java | 12 +- .../java/com/boydti/fawe/beta/IGetBlocks.java | 2 - .../com/boydti/fawe/beta/IQueueExtent.java | 2 +- .../beta/{test => filters}/CountFilter.java | 22 +- .../boydti/fawe/beta/filters/SetFilter.java | 18 + .../beta/implementation/QueueHandler.java | 87 ++-- .../implementation/SimpleCharQueueExtent.java | 4 +- .../SingleThreadQueueExtent.java | 41 +- .../implementation/blocks/CharBlocks.java | 42 +- .../implementation/blocks/CharGetBlocks.java | 8 +- .../implementation/blocks/CharSetBlocks.java | 12 +- .../implementation/blocks/FullCharBlocks.java | 4 +- .../implementation/holder/ChunkHolder.java | 19 +- .../implementation/holder/FinalizedChunk.java | 2 +- .../implementation/holder/ReferenceChunk.java | 2 +- .../fawe/object/brush/InspectBrush.java | 1 - .../worldedit/command/RegionCommands.java | 81 ++- 26 files changed, 617 insertions(+), 480 deletions(-) rename worldedit-core/src/main/java/com/boydti/fawe/beta/{test => filters}/CountFilter.java (66%) create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/filters/SetFilter.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 eb872c73a..913d0f0bb 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 @@ -56,6 +56,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.world.ChunkUnloadEvent; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; @@ -147,6 +148,11 @@ public class FaweBukkit implements IFawe, Listener { }); } + @EventHandler + public static void onChunkUnload(ChunkUnloadEvent event) { + event.setCancelled(true); + } + @Override public QueueHandler getQueueHandler() { return new BukkitQueueHandler(); diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/Spigot_v1_13_R2.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/Spigot_v1_13_R2.java index 9c9f341d5..2adc9d3ad 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/Spigot_v1_13_R2.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/Spigot_v1_13_R2.java @@ -94,7 +94,7 @@ public final class Spigot_v1_13_R2 extends CachedBukkitAdapter implements Bukkit public char[] idbToStateOrdinal; - private boolean init() { + private synchronized boolean init() { if (idbToStateOrdinal != null) return false; idbToStateOrdinal = new char[Block.REGISTRY_ID.a()]; // size for (int i = 0; i < idbToStateOrdinal.length; i++) { @@ -527,8 +527,8 @@ public final class Spigot_v1_13_R2 extends CachedBukkitAdapter implements Bukkit int id = Block.REGISTRY_ID.getId(ibd); return idbToStateOrdinal[id]; } catch (NullPointerException e) { - if (init()) return adaptToInt(ibd); - throw e; + init(); + return adaptToInt(ibd); } } @@ -537,8 +537,8 @@ public final class Spigot_v1_13_R2 extends CachedBukkitAdapter implements Bukkit int id = Block.REGISTRY_ID.getId(ibd); return idbToStateOrdinal[id]; } catch (NullPointerException e) { - if (init()) return adaptToChar(ibd); - throw e; + init(); + return adaptToChar(ibd); } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java index 95d67c85b..0eec7fbf7 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java @@ -20,6 +20,7 @@ import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.internal.Constants; import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockTypes; import net.jpountz.util.UnsafeUtils; import net.minecraft.server.v1_13_R2.BiomeBase; import net.minecraft.server.v1_13_R2.BlockPosition; @@ -69,7 +70,7 @@ public class BukkitChunkHolder> extends ChunkHolder { get.reset(); } if (get.sections == null) { - get.sections = sections; + get.sections = sections.clone(); } if (get.sections[layer] != section) { get.sections[layer] = section; @@ -79,271 +80,274 @@ public class BukkitChunkHolder> extends ChunkHolder { } @Override - public T call() { - BukkitQueue extent = (BukkitQueue) getExtent(); - BukkitGetBlocks get = (BukkitGetBlocks) getOrCreateGet(); - CharSetBlocks set = (CharSetBlocks) getOrCreateSet(); - int X = getX(); - int Z = getZ(); + public synchronized T call() { + try { + int X = getX(); + int Z = getZ(); + BukkitQueue extent = (BukkitQueue) getExtent(); + BukkitGetBlocks get = (BukkitGetBlocks) getOrCreateGet(); + CharSetBlocks set = (CharSetBlocks) getOrCreateSet(); - Chunk nmsChunk = extent.ensureLoaded(X, Z); + Chunk nmsChunk = extent.ensureLoaded(X, Z); - // Remove existing tiles - { - Map tiles = nmsChunk.getTileEntities(); - if (!tiles.isEmpty()) { - final Iterator> iterator = tiles.entrySet().iterator(); - while (iterator.hasNext()) { - final Map.Entry entry = iterator.next(); - final BlockPosition pos = entry.getKey(); - final int lx = pos.getX() & 15; - final int ly = pos.getY(); - final int lz = pos.getZ() & 15; - final int layer = ly >> 4; - final char[] array = set.blocks[layer]; - if (array == null) { - continue; - } - final int index = (((ly & 0xF) << 8) | (lz << 4) | lx); - if (array[index] != 0) { - TileEntity tile = entry.getValue(); - tile.z(); - tile.invalidateBlockCache(); + // Remove existing tiles + { + Map tiles = nmsChunk.getTileEntities(); + if (!tiles.isEmpty()) { + final Iterator> iterator = tiles.entrySet().iterator(); + while (iterator.hasNext()) { + final Map.Entry entry = iterator.next(); + final BlockPosition pos = entry.getKey(); + final int lx = pos.getX() & 15; + final int ly = pos.getY(); + final int lz = pos.getZ() & 15; + final int layer = ly >> 4; + final char[] array = set.blocks[layer]; + if (array == null) { + continue; + } + final int index = (((ly & 0xF) << 8) | (lz << 4) | lx); + if (array[index] != 0) { + TileEntity tile = entry.getValue(); + tile.z(); + tile.invalidateBlockCache(); + } } } } - } - int bitMask = 0; - synchronized (nmsChunk) { - ChunkSection[] sections = nmsChunk.getSections(); - World world = extent.getBukkitWorld(); - boolean hasSky = world.getEnvironment() == World.Environment.NORMAL; + int bitMask = 0; + synchronized (nmsChunk) { + ChunkSection[] sections = nmsChunk.getSections(); + World world = extent.getBukkitWorld(); + boolean hasSky = world.getEnvironment() == World.Environment.NORMAL; - for (int layer = 0; layer < 16; layer++) { - if (!set.hasSection(layer)) continue; + for (int layer = 0; layer < 16; layer++) { + if (!set.hasSection(layer)) continue; - bitMask |= 1 << layer; + bitMask |= 1 << layer; - char[] setArr = set.blocks[layer]; - ChunkSection newSection; - ChunkSection existingSection = sections[layer]; - if (existingSection == null) { - newSection = extent.newChunkSection(layer, hasSky, setArr); - if (BukkitQueue.setSectionAtomic(sections, null, newSection, layer)) { - updateGet(get, nmsChunk, sections, newSection, setArr, layer); - continue; - } else { - existingSection = sections[layer]; - if (existingSection == null) { - System.out.println("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer); - continue; - } - } - } - DelegateLock lock = BukkitQueue.applyLock(existingSection); - synchronized (lock) { - lock.untilFree(); - synchronized (get) { - ChunkSection getSection; - if (get.nmsChunk != nmsChunk) { - if (get.nmsChunk != null) System.out.println("chunk doesn't match"); - get.nmsChunk = nmsChunk; - get.sections = null; - get.reset(); - } else { - getSection = get.getSections()[layer]; - if (getSection != existingSection) { - get.sections[layer] = existingSection; - get.reset(); - System.out.println("Section doesn't match"); - } else if (lock.isModified()) { - System.out.println("lock is outdated"); - get.reset(layer); - } - } - char[] getArr = get.load(layer); - for (int i = 0; i < 4096; i++) { - char value = setArr[i]; - if (value != 0) { - getArr[i] = value; - } - } - newSection = extent.newChunkSection(layer, hasSky, getArr); - if (!BukkitQueue.setSectionAtomic(sections, existingSection, newSection, layer)) { - System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer); - continue; - } else { + char[] setArr = set.blocks[layer]; + ChunkSection newSection; + ChunkSection existingSection = sections[layer]; + if (existingSection == null) { + newSection = extent.newChunkSection(layer, hasSky, setArr); + if (BukkitQueue.setSectionAtomic(sections, null, newSection, layer)) { updateGet(get, nmsChunk, sections, newSection, setArr, layer); - } - } - } - } - - // Biomes - if (set.biomes != null) { - // set biomes - final BiomeBase[] currentBiomes = nmsChunk.getBiomeIndex(); - for (int i = 0; i < set.biomes.length; i++) { - final BiomeType biome = set.biomes[i]; - if (biome != null) { - final Biome craftBiome = BukkitAdapter.adapt(biome); - currentBiomes[i] = CraftBlock.biomeToBiomeBase(craftBiome); - } - } - } - - Runnable[] syncTasks = null; - - net.minecraft.server.v1_13_R2.World nmsWorld = nmsChunk.getWorld(); - int bx = X << 4; - int bz = Z << 4; - - if (set.entityRemoves != null && !set.entityRemoves.isEmpty()) { - if (syncTasks == null) syncTasks = new Runnable[3]; - - HashSet entsToRemove = set.entityRemoves; - - syncTasks[2] = new Runnable() { - @Override - public void run() { - final List[] entities = nmsChunk.getEntitySlices(); - - for (int i = 0; i < entities.length; i++) { - final Collection ents = entities[i]; - if (!ents.isEmpty()) { - final Iterator iter = ents.iterator(); - while (iter.hasNext()) { - final Entity entity = iter.next(); - if (entsToRemove.contains(entity.getUniqueID())) { - iter.remove(); - entity.b(false); - entity.die(); - entity.valid = false; - } - } - } - } - } - }; - } - - if (set.entities != null && !set.entities.isEmpty()) { - if (syncTasks == null) syncTasks = new Runnable[2]; - - HashSet entitiesToSpawn = set.entities; - - syncTasks[1] = new Runnable() { - @Override - public void run() { - for (final CompoundTag nativeTag : entitiesToSpawn) { - final Map entityTagMap = ReflectionUtils.getMap(nativeTag.getValue()); - final StringTag idTag = (StringTag) entityTagMap.get("Id"); - final ListTag posTag = (ListTag) entityTagMap.get("Pos"); - final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); - if (idTag == null || posTag == null || rotTag == null) { - Fawe.debug("Unknown entity tag: " + nativeTag); + continue; + } else { + existingSection = sections[layer]; + if (existingSection == null) { + System.out.println("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer); continue; } - final double x = posTag.getDouble(0); - final double y = posTag.getDouble(1); - final double z = posTag.getDouble(2); - final float yaw = rotTag.getFloat(0); - final float pitch = rotTag.getFloat(1); - final String id = idTag.getValue(); - final Entity entity = EntityTypes.a(nmsWorld, new MinecraftKey(id)); - if (entity != null) { - final UUID uuid = entity.getUniqueID(); - entityTagMap.put("UUIDMost", new LongTag(uuid.getMostSignificantBits())); - entityTagMap.put("UUIDLeast", new LongTag(uuid.getLeastSignificantBits())); - if (nativeTag != null) { - final NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_13.fromNative(nativeTag); - for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - entity.f(tag); + } + } + DelegateLock lock = BukkitQueue.applyLock(existingSection); + synchronized (get) { + synchronized (lock) { + lock.untilFree(); + + ChunkSection getSection; + if (get.nmsChunk != nmsChunk) { + get.nmsChunk = nmsChunk; + get.sections = null; + get.reset(); + } else { + getSection = get.getSections()[layer]; + if (getSection != existingSection) { + get.sections[layer] = existingSection; + get.reset(); + } else if (lock.isModified()) { + get.reset(layer); } - entity.setLocation(x, y, z, yaw, pitch); - nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM); + } + char[] getArr = get.load(layer); + for (int i = 0; i < 4096; i++) { + char value = setArr[i]; + if (value != 0) { + getArr[i] = value; + } + } + newSection = extent.newChunkSection(layer, hasSky, getArr); + if (!BukkitQueue.setSectionAtomic(sections, existingSection, newSection, layer)) { + System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer); + continue; + } else { + updateGet(get, nmsChunk, sections, newSection, setArr, layer); } } } - }; - - } - - // set tiles - if (set.tiles != null && !set.tiles.isEmpty()) { - if (syncTasks == null) syncTasks = new Runnable[1]; - - HashMap tiles = set.tiles; - syncTasks[0] = new Runnable() { - @Override - public void run() { - for (final Map.Entry entry : tiles.entrySet()) { - final CompoundTag nativeTag = entry.getValue(); - final short blockHash = entry.getKey(); - final int x = (blockHash >> 12 & 0xF) + bx; - final int y = (blockHash & 0xFF); - final int z = (blockHash >> 8 & 0xF) + bz; - final BlockPosition pos = new BlockPosition(x, y, z); - synchronized (BukkitQueue_0.class) { - TileEntity tileEntity = nmsWorld.getTileEntity(pos); - if (tileEntity == null || tileEntity.x()) { - nmsWorld.n(pos); - tileEntity = nmsWorld.getTileEntity(pos); - } - if (tileEntity != null) { - final NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_13.fromNative(nativeTag); - tag.set("x", new NBTTagInt(x)); - tag.set("y", new NBTTagInt(y)); - tag.set("z", new NBTTagInt(z)); - tileEntity.load(tag); - } - } - } - } - }; - } - - int finalMask = bitMask; - Runnable callback = () -> { - if (finalMask != 0) { - // Set Modified - nmsChunk.f(true); - nmsChunk.mustSave = true; - nmsChunk.markDirty(); - // send to player - extent.sendChunk(X, Z, finalMask); } - extent.returnToPool(BukkitChunkHolder.this); - }; - if (syncTasks != null) { - QueueHandler queueHandler = Fawe.get().getQueueHandler(); - Runnable[] finalSyncTasks = syncTasks; + // Biomes + if (set.biomes != null) { + // set biomes + final BiomeBase[] currentBiomes = nmsChunk.getBiomeIndex(); + for (int i = 0; i < set.biomes.length; i++) { + final BiomeType biome = set.biomes[i]; + if (biome != null) { + final Biome craftBiome = BukkitAdapter.adapt(biome); + currentBiomes[i] = CraftBlock.biomeToBiomeBase(craftBiome); + } + } + } - // Chain the sync tasks and the callback - Callable chain = new Callable() { - @Override - public Future call() { - // Run the sync tasks - for (int i = 1; i < finalSyncTasks.length; i++) { - Runnable task = finalSyncTasks[i]; - if (task != null) { - task.run(); + Runnable[] syncTasks = null; + + net.minecraft.server.v1_13_R2.World nmsWorld = nmsChunk.getWorld(); + int bx = X << 4; + int bz = Z << 4; + + if (set.entityRemoves != null && !set.entityRemoves.isEmpty()) { + if (syncTasks == null) syncTasks = new Runnable[3]; + + HashSet entsToRemove = set.entityRemoves; + + syncTasks[2] = new Runnable() { + @Override + public void run() { + final List[] entities = nmsChunk.getEntitySlices(); + + for (int i = 0; i < entities.length; i++) { + final Collection ents = entities[i]; + if (!ents.isEmpty()) { + final Iterator iter = ents.iterator(); + while (iter.hasNext()) { + final Entity entity = iter.next(); + if (entsToRemove.contains(entity.getUniqueID())) { + iter.remove(); + entity.b(false); + entity.die(); + entity.valid = false; + } + } + } } } - return queueHandler.async(callback, null); + }; + } + + if (set.entities != null && !set.entities.isEmpty()) { + if (syncTasks == null) syncTasks = new Runnable[2]; + + HashSet entitiesToSpawn = set.entities; + + syncTasks[1] = new Runnable() { + @Override + public void run() { + for (final CompoundTag nativeTag : entitiesToSpawn) { + final Map entityTagMap = ReflectionUtils.getMap(nativeTag.getValue()); + final StringTag idTag = (StringTag) entityTagMap.get("Id"); + final ListTag posTag = (ListTag) entityTagMap.get("Pos"); + final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); + if (idTag == null || posTag == null || rotTag == null) { + Fawe.debug("Unknown entity tag: " + nativeTag); + continue; + } + final double x = posTag.getDouble(0); + final double y = posTag.getDouble(1); + final double z = posTag.getDouble(2); + final float yaw = rotTag.getFloat(0); + final float pitch = rotTag.getFloat(1); + final String id = idTag.getValue(); + final Entity entity = EntityTypes.a(nmsWorld, new MinecraftKey(id)); + if (entity != null) { + final UUID uuid = entity.getUniqueID(); + entityTagMap.put("UUIDMost", new LongTag(uuid.getMostSignificantBits())); + entityTagMap.put("UUIDLeast", new LongTag(uuid.getLeastSignificantBits())); + if (nativeTag != null) { + final NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_13.fromNative(nativeTag); + for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + tag.remove(name); + } + entity.f(tag); + } + entity.setLocation(x, y, z, yaw, pitch); + nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM); + } + } + } + }; + + } + + // set tiles + if (set.tiles != null && !set.tiles.isEmpty()) { + if (syncTasks == null) syncTasks = new Runnable[1]; + + HashMap tiles = set.tiles; + syncTasks[0] = new Runnable() { + @Override + public void run() { + for (final Map.Entry entry : tiles.entrySet()) { + final CompoundTag nativeTag = entry.getValue(); + final short blockHash = entry.getKey(); + final int x = (blockHash >> 12 & 0xF) + bx; + final int y = (blockHash & 0xFF); + final int z = (blockHash >> 8 & 0xF) + bz; + final BlockPosition pos = new BlockPosition(x, y, z); + synchronized (BukkitQueue_0.class) { + TileEntity tileEntity = nmsWorld.getTileEntity(pos); + if (tileEntity == null || tileEntity.x()) { + nmsWorld.n(pos); + tileEntity = nmsWorld.getTileEntity(pos); + } + if (tileEntity != null) { + final NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_13.fromNative(nativeTag); + tag.set("x", new NBTTagInt(x)); + tag.set("y", new NBTTagInt(y)); + tag.set("z", new NBTTagInt(z)); + tileEntity.load(tag); + } + } + } + } + }; + } + + int finalMask = bitMask; + Runnable callback = () -> { + if (finalMask != 0) { + // Set Modified + nmsChunk.f(true); + nmsChunk.mustSave = true; + nmsChunk.markDirty(); + // send to player + extent.sendChunk(X, Z, finalMask); } + + extent.returnToPool(BukkitChunkHolder.this); }; - return (T) queueHandler.sync(chain); - } else { - callback.run(); + if (syncTasks != null) { + QueueHandler queueHandler = Fawe.get().getQueueHandler(); + Runnable[] finalSyncTasks = syncTasks; + + // Chain the sync tasks and the callback + Callable chain = new Callable() { + @Override + public Future call() { + // Run the sync tasks + for (int i = 1; i < finalSyncTasks.length; i++) { + Runnable task = finalSyncTasks[i]; + if (task != null) { + task.run(); + } + } + return queueHandler.async(callback, null); + } + }; + return (T) (Future) queueHandler.sync(chain); + } else { + callback.run(); + } } + return null; + } catch (Throwable e) { + e.printStackTrace(); + return null; } - return null; } @Override diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java index 2f114780c..1fdd4ce85 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java @@ -21,6 +21,8 @@ import net.minecraft.server.v1_13_R2.DataPaletteLinear; import net.minecraft.server.v1_13_R2.IBlockData; import net.minecraft.server.v1_13_R2.World; +import java.util.Arrays; + import static com.boydti.fawe.bukkit.v0.BukkitQueue_0.getAdapter; public class BukkitGetBlocks extends CharGetBlocks { @@ -29,7 +31,7 @@ public class BukkitGetBlocks extends CharGetBlocks { public World nmsWorld; public int X, Z; - public BukkitGetBlocks(World nmsWorld, int X, int Z) {/*d*/ + public BukkitGetBlocks(World nmsWorld, int X, int Z) { this.nmsWorld = nmsWorld; this.X = X; this.Z = Z; @@ -71,9 +73,10 @@ public class BukkitGetBlocks extends CharGetBlocks { final DataPaletteBlock blocks = section.getBlocks(); final DataBits bits = (DataBits) BukkitQueue_1_13.fieldBits.get(blocks); final DataPalette palette = (DataPalette) BukkitQueue_1_13.fieldPalette.get(blocks); - final int bitsPerEntry = bits.c(); + final int bitsPerEntry = bits.c(); final long[] blockStates = bits.a(); + new BitArray4096(blockStates, bitsPerEntry).toRaw(data); int num_palette; @@ -112,23 +115,20 @@ public class BukkitGetBlocks extends CharGetBlocks { char[] paletteToBlockChars = FaweCache.PALETTE_TO_BLOCK_CHAR.get(); try { - for (int i = 0; i < num_palette; i++) { - IBlockData ibd = palette.a(i); - char ordinal; - if (ibd == null) { - ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar(); - System.out.println("Invalid palette"); - } else { - ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToChar(ibd); + final int size = num_palette; + if (size != 1) { + for (int i = 0; i < size; i++) { + char ordinal = ordinal(palette.a(i)); + paletteToBlockChars[i] = ordinal; } - paletteToBlockChars[i] = ordinal; - } - for (int i = 0; i < 4096; i++) { - char paletteVal = data[i]; - data[i] = paletteToBlockChars[paletteVal]; - if (data[i] == Character.MAX_VALUE) { - System.out.println("Invalid " + paletteVal + " | " + num_palette); + for (int i = 0; i < 4096; i++) { + char paletteVal = data[i]; + char val = paletteToBlockChars[paletteVal]; + data[i] = val; } + } else { + char ordinal = ordinal(palette.a(0)); + Arrays.fill(data, ordinal); } } finally { for (int i = 0; i < num_palette; i++) { @@ -143,6 +143,14 @@ public class BukkitGetBlocks extends CharGetBlocks { } } + private final char ordinal(IBlockData ibd) { + if (ibd == null) { + return BlockTypes.AIR.getDefaultState().getOrdinalChar(); + } else { + return ((Spigot_v1_13_R2) getAdapter()).adaptToChar(ibd); + } + } + public ChunkSection[] getSections() { ChunkSection[] tmp = sections; if (tmp == null) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java index 1d9809d42..6db6b7c7d 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java @@ -1,40 +1,58 @@ package com.boydti.fawe.beta; import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; +import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.registry.BlockMaterial; + +import javax.annotation.Nullable; + import static com.sk89q.worldedit.world.block.BlockTypes.states; public class CharFilterBlock implements FilterBlock { private IQueueExtent queue; - private CharGetBlocks chunk; - private char[] section; + private CharGetBlocks get; + private CharSetBlocks set; - @Override - public final void init(IQueueExtent queue) { - this.queue = queue; - } - - @Override - public final void init(int X, int Z, IGetBlocks chunk) { - this.chunk = (CharGetBlocks) chunk; - this.X = X; - this.Z = Z; - this.xx = X << 4; - this.zz = Z << 4; - } + private char[] getArr; + private @Nullable char[] setArr; + private SetDelegate delegate; // local private int layer, index, x, y, z, xx, yy, zz, X, Z; - public final void filter(CharGetBlocks blocks, Filter filter) { - for (int layer = 0; layer < 16; layer++) { - if (!blocks.hasSection(layer)) continue; - char[] arr = blocks.sections[layer].get(blocks, layer); + @Override + public final FilterBlock init(final IQueueExtent queue) { + this.queue = queue; + return this; + } - this.section = arr; + @Override + public final FilterBlock init(final int X, final int Z, final IGetBlocks chunk) { + this.get = (CharGetBlocks) chunk; + this.X = X; + this.Z = Z; + this.xx = X << 4; + this.zz = Z << 4; + return this; + } + + public final void filter(final IGetBlocks iget, final ISetBlocks iset, final Filter filter) { + final CharSetBlocks set = (CharSetBlocks) iset; + final CharGetBlocks get = (CharGetBlocks) iget; + for (int layer = 0; layer < 16; layer++) { + if (!get.hasSection(layer)) continue; + this.set = set; + getArr = get.sections[layer].get(get, layer); + if (set.hasSection(layer)) { + setArr = set.blocks[layer]; + delegate = FULL; + } else { + delegate = NULL; + setArr = null; + } this.layer = layer; this.yy = layer << 4; @@ -48,6 +66,25 @@ public class CharFilterBlock implements FilterBlock { } } + @Override + public void setOrdinal(final int ordinal) { + delegate.set(this, (char) ordinal); + } + + @Override + public void setState(final BlockState state) { + delegate.set(this, state.getOrdinalChar()); + } + + @Override + public void setFullBlock(final BaseBlock block) { + delegate.set(this, block.getOrdinalChar()); + final CompoundTag nbt = block.getNbtData(); + if (nbt != null) { // TODO optimize check via ImmutableBaseBlock + set.setTile(x, yy + y, z, nbt); + } + } + @Override public final int getX() { return xx + x; @@ -89,26 +126,26 @@ public class CharFilterBlock implements FilterBlock { } public final char getOrdinalChar() { - return section[index]; + return getArr[index]; } @Override public final int getOrdinal() { - return section[index]; + return getArr[index]; } @Override public final BlockState getState() { - int ordinal = section[index]; + final int ordinal = getArr[index]; return BlockTypes.states[ordinal]; } @Override public final BaseBlock getBaseBlock() { - BlockState state = getState(); - BlockMaterial material = state.getMaterial(); + final BlockState state = getState(); + final BlockMaterial material = state.getMaterial(); if (material.hasContainer()) { - CompoundTag tag = chunk.getTag(x, y + (layer << 4), z); + final CompoundTag tag = get.getTag(x, y + (layer << 4), z); return state.toBaseBlock(tag); } return state.toBaseBlock(); @@ -121,11 +158,11 @@ public class CharFilterBlock implements FilterBlock { public final BlockState getOrdinalBelow() { if (y > 0) { - return states[section[index - 256]]; + return states[getArr[index - 256]]; } if (layer > 0) { final int newLayer = layer - 1; - final CharGetBlocks chunk = this.chunk; + final CharGetBlocks chunk = this.get; return states[chunk.sections[newLayer].get(chunk, newLayer, index + 3840)]; } return BlockTypes.__RESERVED__.getDefaultState(); @@ -133,22 +170,22 @@ public class CharFilterBlock implements FilterBlock { public final BlockState getStateAbove() { if (y < 16) { - return states[section[index + 256]]; + return states[getArr[index + 256]]; } if (layer < 16) { final int newLayer = layer + 1; - final CharGetBlocks chunk = this.chunk; + final CharGetBlocks chunk = this.get; return states[chunk.sections[newLayer].get(chunk, newLayer, index - 3840)]; } return BlockTypes.__RESERVED__.getDefaultState(); } - public final BlockState getStateRelativeY(int y) { - int newY = this.y + y; - int layerAdd = newY >> 4; + public final BlockState getStateRelativeY(final int y) { + final int newY = this.y + y; + final int layerAdd = newY >> 4; switch (layerAdd) { case 0: - return states[section[this.index + (y << 8)]]; + return states[getArr[this.index + (y << 8)]]; case 1: case 2: case 3: @@ -164,10 +201,10 @@ public class CharFilterBlock implements FilterBlock { case 13: case 14: case 15: { - int newLayer = layer + layerAdd; + final int newLayer = layer + layerAdd; if (newLayer < 16) { - int index = this.index + ((y & 15) << 8); - return states[chunk.sections[newLayer].get(chunk, newLayer, index)]; + final int index = this.index + ((y & 15) << 8); + return states[get.sections[newLayer].get(get, newLayer, index)]; } break; } @@ -186,10 +223,10 @@ public class CharFilterBlock implements FilterBlock { case -13: case -14: case -15: { - int newLayer = layer + layerAdd; + final int newLayer = layer + layerAdd; if (newLayer >= 0) { - int index = this.index + ((y & 15) << 8); - return states[chunk.sections[newLayer].get(chunk, newLayer, index)]; + final int index = this.index + ((y & 15) << 8); + return states[get.sections[newLayer].get(get, newLayer, index)]; } break; } @@ -198,15 +235,15 @@ public class CharFilterBlock implements FilterBlock { } public final BlockState getStateRelative(final int x, final int y, final int z) { - int newX = this.x + x; + final int newX = this.x + x; if (newX >> 4 == 0) { - int newZ = this.z + z; + final int newZ = this.z + z; if (newZ >> 4 == 0) { - int newY = this.y + y; - int layerAdd = newY >> 4; + final int newY = this.y + y; + final int layerAdd = newY >> 4; switch (layerAdd) { case 0: - return states[section[this.index + ((y << 8) + (z << 4) + x)]]; + return states[getArr[this.index + ((y << 8) + (z << 4) + x)]]; case 1: case 2: case 3: @@ -222,10 +259,10 @@ public class CharFilterBlock implements FilterBlock { case 13: case 14: case 15: { - int newLayer = layer + layerAdd; + final int newLayer = layer + layerAdd; if (newLayer < 16) { - int index = ((newY & 15) << 8) + (newZ << 4) + newX; - return states[chunk.sections[newLayer].get(chunk, newLayer, index)]; + final int index = ((newY & 15) << 8) + (newZ << 4) + newX; + return states[get.sections[newLayer].get(get, newLayer, index)]; } break; } @@ -244,10 +281,10 @@ public class CharFilterBlock implements FilterBlock { case -13: case -14: case -15: { - int newLayer = layer + layerAdd; + final int newLayer = layer + layerAdd; if (newLayer >= 0) { - int index = ((newY & 15) << 8) + (newZ << 4) + newX; - return states[chunk.sections[newLayer].get(chunk, newLayer, index)]; + final int index = ((newY & 15) << 8) + (newZ << 4) + newX; + return states[get.sections[newLayer].get(get, newLayer, index)]; } break; } @@ -257,10 +294,36 @@ public class CharFilterBlock implements FilterBlock { } // queue.get // TODO return normal get block - int newY = this.y + y + yy; + final int newY = this.y + y + yy; if (newY >= 0 && newY <= 256) { return queue.getBlock(xx + newX, newY, this.zz + this.z + z); } return BlockTypes.__RESERVED__.getDefaultState(); } + + /* + Set delegate + */ + private SetDelegate initSet() { + setArr = set.sections[layer].get(set, layer); + return delegate = FULL; + } + + private interface SetDelegate { + void set(CharFilterBlock block, char value); + } + + private static final SetDelegate NULL = new SetDelegate() { + @Override + public void set(final CharFilterBlock block, final char value) { + block.initSet().set(block, value); + } + }; + + private static final SetDelegate FULL = new SetDelegate() { + @Override + public final void set(final CharFilterBlock block, final char value) { + block.setArr[block.index] = value; + } + }; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFuture.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFuture.java index 68721cd82..264eb4509 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFuture.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFuture.java @@ -10,7 +10,7 @@ public class ChunkFuture implements Future { private volatile boolean cancelled; private volatile boolean done; - public ChunkFuture(IChunk chunk) { + public ChunkFuture(final IChunk chunk) { this.chunk = chunk; } @@ -19,7 +19,7 @@ public class ChunkFuture implements Future { } @Override - public boolean cancel(boolean mayInterruptIfRunning) { + public boolean cancel(final boolean mayInterruptIfRunning) { cancelled = true; if (done) return false; return true; @@ -46,7 +46,7 @@ public class ChunkFuture implements Future { } @Override - public Void get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + public Void get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { synchronized (chunk) { if (!done) { this.wait(unit.toMillis(timeout)); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java index fe3adaea9..01a49bdc7 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java @@ -57,7 +57,7 @@ public interface Filter { return this; } - default void join(Filter parent) { + default void join(final Filter parent) { } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java index 79fb85799..ac6cd3312 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java @@ -1,14 +1,23 @@ package com.boydti.fawe.beta; import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; +import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; public interface FilterBlock { - void init(IQueueExtent queue); + FilterBlock init(IQueueExtent queue); - void init(int X, int Z, IGetBlocks chunk); + FilterBlock init(int X, int Z, IGetBlocks chunk); + + void filter(IGetBlocks get, ISetBlocks set, Filter filter); + + void setOrdinal(int ordinal); + + void setState(BlockState state); + + void setFullBlock(BaseBlock block); int getOrdinal(); @@ -26,7 +35,7 @@ public interface FilterBlock { return getStateRelative(0, 1, 0); } - default BlockState getStateRelativeY(int y) { + default BlockState getStateRelativeY(final int y) { return getStateRelative(0, y, 0); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java index 1cb14e2af..8d57af1be 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java @@ -65,7 +65,7 @@ public interface IDelegateChunk extends IChunk { @Override - default boolean trim(boolean aggressive) { + default boolean trim(final boolean aggressive) { return getParent().trim(aggressive); } @@ -80,7 +80,7 @@ public interface IDelegateChunk extends IChunk { } @Override - default void filter(Filter filter, FilterBlock mutable) { + default void filter(final Filter filter, final FilterBlock mutable) { getParent().filter(filter, mutable); } @@ -100,7 +100,7 @@ public interface IDelegateChunk extends IChunk { } @Override - default void set(Filter filter) { + default void set(final Filter filter) { getParent().set(filter); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateQueueExtent.java index c11146ce3..f05a1b2e5 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateQueueExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateQueueExtent.java @@ -11,27 +11,27 @@ public interface IDelegateQueueExtent extends IQueueExtent { IQueueExtent getParent(); @Override - default void init(WorldChunkCache cache) { + default void init(final WorldChunkCache cache) { getParent().init(cache); } @Override - default IChunk getCachedChunk(int X, int Z) { + default IChunk getCachedChunk(final int X, final int Z) { return getParent().getCachedChunk(X, Z); } @Override - default Future submit(IChunk chunk) { + default Future submit(final IChunk chunk) { return getParent().submit(chunk); } @Override - default IChunk create(boolean full) { + default IChunk create(final boolean full) { return getParent().create(full); } @Override - default IChunk wrap(IChunk root) { + default IChunk wrap(final IChunk root) { return getParent().wrap(root); } @@ -41,7 +41,7 @@ public interface IDelegateQueueExtent extends IQueueExtent { } @Override - default boolean trim(boolean aggressive) { + default boolean trim(final boolean aggressive) { return getParent().trim(aggressive); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IGetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IGetBlocks.java index b49a8bb79..b865e1f91 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IGetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IGetBlocks.java @@ -20,8 +20,6 @@ public interface IGetBlocks extends IBlocks, Trimable { @Override boolean trim(boolean aggressive); - void filter(Filter filter, FilterBlock block); - default void optimize() { } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java index 7725810e5..a19e7ea8c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java @@ -70,7 +70,7 @@ public interface IQueueExtent extends Flushable, Trimable { * @param root * @return wrapped chunk */ - default IChunk wrap(IChunk root) { + default IChunk wrap(final IChunk root) { return root; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/test/CountFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/CountFilter.java similarity index 66% rename from worldedit-core/src/main/java/com/boydti/fawe/beta/test/CountFilter.java rename to worldedit-core/src/main/java/com/boydti/fawe/beta/filters/CountFilter.java index 9117391f2..052519cd7 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/test/CountFilter.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/CountFilter.java @@ -1,4 +1,4 @@ -package com.boydti.fawe.beta.test; +package com.boydti.fawe.beta.filters; import com.boydti.fawe.beta.Filter; import com.boydti.fawe.beta.FilterBlock; @@ -13,17 +13,17 @@ import java.util.Collections; import java.util.List; public class CountFilter implements Filter { - private int[] counter = new int[BlockTypes.states.length]; + private final int[] counter = new int[BlockTypes.states.length]; @Override - public void applyBlock(FilterBlock block) { + public void applyBlock(final FilterBlock block) { counter[block.getOrdinal()]++; } public List> getDistribution() { - List> distribution = new ArrayList<>(); + final List> distribution = new ArrayList<>(); for (int i = 0; i < counter.length; i++) { - int count = counter[i]; + final int count = counter[i]; if (count != 0) { distribution.add(new Countable<>(BlockTypes.states[i], count)); } @@ -32,10 +32,10 @@ public class CountFilter implements Filter { return distribution; } - public void print(Actor actor, long size) { - for (Countable c : getDistribution()) { - String name = c.getID().toString(); - String str = String.format("%-7s (%.3f%%) %s", + public void print(final Actor actor, final long size) { + for (final Countable c : getDistribution()) { + final String name = c.getID().toString(); + final String str = String.format("%-7s (%.3f%%) %s", String.valueOf(c.getAmount()), c.getAmount() / (double) size * 100, name); @@ -49,8 +49,8 @@ public class CountFilter implements Filter { } @Override - public void join(Filter parent) { - CountFilter other = (CountFilter) parent; + public void join(final Filter parent) { + final CountFilter other = (CountFilter) parent; for (int i = 0; i < counter.length; i++) { other.counter[i] += this.counter[i]; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/SetFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/SetFilter.java new file mode 100644 index 000000000..04048d04d --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/SetFilter.java @@ -0,0 +1,18 @@ +package com.boydti.fawe.beta.filters; + +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.FilterBlock; +import com.sk89q.worldedit.world.block.BlockState; + +public class SetFilter implements Filter { + private final BlockState state; + + public SetFilter(final BlockState state) { + this.state = state; + } + + @Override + public void applyBlock(final FilterBlock block) { + block.setState(state); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java index a6e589f88..4cfe41121 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java @@ -1,5 +1,6 @@ package com.boydti.fawe.beta.implementation; +import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; import com.boydti.fawe.beta.Filter; import com.boydti.fawe.beta.FilterBlock; @@ -9,6 +10,7 @@ import com.boydti.fawe.beta.Trimable; import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.collection.IterableThreadLocal; import com.boydti.fawe.util.MemUtil; +import com.boydti.fawe.util.TaskManager; import com.boydti.fawe.wrappers.WorldWrapper; import com.google.common.util.concurrent.Futures; import com.sk89q.worldedit.math.BlockVector2; @@ -32,7 +34,7 @@ import java.util.concurrent.ThreadPoolExecutor; /** * Class which handles all the queues {@link IQueueExtent} */ -public abstract class QueueHandler implements Trimable { +public abstract class QueueHandler implements Trimable, Runnable { private ForkJoinPool forkJoinPoolPrimary = new ForkJoinPool(); private ForkJoinPool forkJoinPoolSecondary = new ForkJoinPool(); private ThreadPoolExecutor blockingExecutor = FaweCache.newBlockingExecutor(); @@ -46,38 +48,52 @@ public abstract class QueueHandler implements Trimable { } }; - public Future async(Runnable run, T value) { + public QueueHandler() { + TaskManager.IMP.repeat(this, 1); + } + + @Override + public void run() { + if (!Fawe.isMainThread()) { + throw new IllegalStateException("Not main thread"); + } + while (!syncTasks.isEmpty()) { + final FutureTask task = syncTasks.poll(); + if (task != null) task.run(); + } + } + + public Future async(final Runnable run, final T value) { return forkJoinPoolSecondary.submit(run, value); } - public Future async(Callable call) { + public Future async(final Callable call) { return forkJoinPoolSecondary.submit(call); } - public Future sync(Runnable run, T value) { - FutureTask result = new FutureTask<>(run, value); + public Future sync(final Runnable run, final T value) { + final FutureTask result = new FutureTask<>(run, value); syncTasks.add(result); return result; } - public Future sync(Runnable run) { - FutureTask result = new FutureTask<>(run, null); + public Future sync(final Runnable run) { + final FutureTask result = new FutureTask<>(run, null); syncTasks.add(result); return result; } - public Future sync(Callable call) { - FutureTask result = new FutureTask<>(call); + public Future sync(final Callable call) { + final FutureTask result = new FutureTask<>(call); syncTasks.add(result); return result; } - public > T submit(IChunk chunk) { + public > T submit(final IChunk chunk) { if (MemUtil.isMemoryFree()) { // return (T) forkJoinPoolSecondary.submit(chunk); } return (T) blockingExecutor.submit(chunk); - } /** @@ -104,8 +120,8 @@ public abstract class QueueHandler implements Trimable { public abstract IQueueExtent create(); - public IQueueExtent getQueue(World world) { - IQueueExtent queue = queuePool.get(); + public IQueueExtent getQueue(final World world) { + final IQueueExtent queue = queuePool.get(); queue.init(getOrCreate(world)); return queue; } @@ -136,30 +152,31 @@ public abstract class QueueHandler implements Trimable { // Get a pool, to operate on the chunks in parallel final int size = Math.min(chunks.size(), Settings.IMP.QUEUE.PARALLEL_THREADS); - ForkJoinTask[] tasks = new ForkJoinTask[size]; + final ForkJoinTask[] tasks = new ForkJoinTask[size]; for (int i = 0; i < size; i++) { tasks[i] = forkJoinPoolPrimary.submit(new Runnable() { @Override public void run() { - Filter newFilter = filter.fork(); + final Filter newFilter = filter.fork(); // Create a chunk that we will reuse/reset for each operation - IQueueExtent queue = getQueue(world); + final IQueueExtent queue = getQueue(world); synchronized (queue) { FilterBlock block = null; - while (true) { - // Get the next chunk pos - final BlockVector2 pos; - synchronized (chunksIter) { - if (!chunksIter.hasNext()) break; - pos = chunksIter.next(); - } - final int X = pos.getX(); - final int Z = pos.getZ(); - IChunk chunk = queue.getCachedChunk(X, Z); - // Initialize - chunk.init(queue, X, Z); - try { + try { + while (true) { + // Get the next chunk pos + final int X, Z; + synchronized (chunksIter) { + if (!chunksIter.hasNext()) break; + final BlockVector2 pos = chunksIter.next(); + X = pos.getX(); + Z = pos.getZ(); + } + IChunk chunk = queue.getCachedChunk(X, Z); + // Initialize + chunk.init(queue, X, Z); + if (!newFilter.appliesChunk(X, Z)) { continue; } @@ -173,11 +190,11 @@ public abstract class QueueHandler implements Trimable { newFilter.finishChunk(chunk); queue.submit(chunk); - } finally { - if (filter != newFilter) { - synchronized (filter) { - newFilter.join(filter); - } + } + } finally { + if (filter != newFilter) { + synchronized (filter) { + newFilter.join(filter); } } } @@ -188,7 +205,7 @@ public abstract class QueueHandler implements Trimable { } // Join filters for (int i = 0; i < tasks.length; i++) { - ForkJoinTask task = tasks[i]; + final ForkJoinTask task = tasks[i]; if (task != null) { task.quietlyJoin(); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java index f6419164e..af1bce4b1 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java @@ -6,8 +6,8 @@ import com.boydti.fawe.beta.FilterBlock; public abstract class SimpleCharQueueExtent extends SingleThreadQueueExtent { @Override public FilterBlock initFilterBlock() { - CharFilterBlock filter = new CharFilterBlock(); - filter.init(this); + FilterBlock filter = new CharFilterBlock(); + filter = filter.init(this); return filter; } } 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 4f57656be..661868e8f 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 @@ -5,6 +5,7 @@ import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.IQueueExtent; import com.boydti.fawe.beta.implementation.holder.ReferenceChunk; import com.boydti.fawe.config.Settings; +import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.MemUtil; import com.google.common.util.concurrent.Futures; import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; @@ -78,12 +79,28 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { // Pool discarded chunks for reuse (can safely be cleared by another thread) private static final ConcurrentLinkedQueue CHUNK_POOL = new ConcurrentLinkedQueue<>(); - public void returnToPool(IChunk chunk) { + public void returnToPool(final IChunk chunk) { CHUNK_POOL.add(chunk); } @Override public > T submit(final IChunk chunk) { + if (lastChunk == chunk) { + lastPair = Long.MAX_VALUE; + lastChunk = null; + } + final long index = MathMan.pairInt(chunk.getX(), chunk.getZ()); + chunks.remove(index, chunk); + return submitUnchecked(chunk); + } + + /** + * Submit without first checking that it has been removed from the chunk map + * @param chunk + * @param + * @return + */ + private > T submitUnchecked(final IChunk chunk) { if (chunk.isEmpty()) { CHUNK_POOL.add(chunk); return (T) (Future) Futures.immediateFuture(null); @@ -97,7 +114,7 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { } @Override - public synchronized boolean trim(boolean aggressive) { + public synchronized boolean trim(final boolean aggressive) { // TODO trim individial chunk sections CHUNK_POOL.clear(); if (Thread.currentThread() == currentThread) { @@ -152,12 +169,12 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { checkThread(); final int size = chunks.size(); - boolean lowMem = MemUtil.isMemoryLimited(); + final boolean lowMem = MemUtil.isMemoryLimited(); if (lowMem || size > Settings.IMP.QUEUE.TARGET_SIZE) { chunk = chunks.removeFirst(); - Future future = submit(chunk); + final Future future = submitUnchecked(chunk); if (future != null && !future.isDone()) { - int targetSize; + final int targetSize; if (lowMem) { targetSize = Settings.IMP.QUEUE.PARALLEL_THREADS; } else { @@ -177,14 +194,14 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { return chunk; } - private void pollSubmissions(int targetSize, boolean aggressive) { - int overflow = submissions.size() - targetSize; + private void pollSubmissions(final int targetSize, final boolean aggressive) { + final int overflow = submissions.size() - targetSize; if (aggressive) { for (int i = 0; i < overflow; i++) { Future first = submissions.poll(); try { while ((first = (Future) first.get()) != null) ; - } catch (InterruptedException | ExecutionException e) { + } catch (final InterruptedException | ExecutionException e) { e.printStackTrace(); } } @@ -195,7 +212,7 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { if (next.isDone()) { try { next = (Future) next.get(); - } catch (InterruptedException | ExecutionException e) { + } catch (final InterruptedException | ExecutionException e) { e.printStackTrace(); } } else { @@ -212,8 +229,8 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { checkThread(); if (!chunks.isEmpty()) { if (MemUtil.isMemoryLimited()) { - for (IChunk chunk : chunks.values()) { - Future future = submit(chunk); + for (final IChunk chunk : chunks.values()) { + final Future future = submitUnchecked(chunk); if (future != null && !future.isDone()) { pollSubmissions(Settings.IMP.QUEUE.PARALLEL_THREADS, true); submissions.add(future); @@ -221,7 +238,7 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { } } else { for (final IChunk chunk : chunks.values()) { - Future future = submit(chunk); + final Future future = submitUnchecked(chunk); if (future != null && !future.isDone()) { submissions.add(future); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java index 7005b5ed1..66cb7b74a 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java @@ -13,7 +13,7 @@ public class CharBlocks implements IBlocks { } @Override - public boolean trim(boolean aggressive) { + public boolean trim(final boolean aggressive) { boolean result = true; for (int i = 0; i < 16; i++) { if (sections[i] == NULL) { @@ -30,34 +30,42 @@ public class CharBlocks implements IBlocks { for (int i = 0; i < 16; i++) sections[i] = NULL; } - public void reset(int layer) { + public void reset(final int layer) { sections[layer] = NULL; } - protected char[] load(int layer) { + public char[] load(final int layer) { return new char[4096]; } - protected char[] load(int layer, char[] data) { + public char[] load(final int layer, final char[] data) { for (int i = 0; i < 4096; i++) data[i] = 0; return data; } @Override - public boolean hasSection(int layer) { + public boolean hasSection(final int layer) { return sections[layer] == FULL; } - public char get(int x, int y, int z) { - int layer = y >> 4; - int index = ((y & 15) << 8) | (z << 4) | (x & 15); + public char get(final int x, final int y, final int z) { + final int layer = y >> 4; + final int index = ((y & 15) << 8) | (z << 4) | (x & 15); return sections[layer].get(this, layer, index); } - public char set(int x, int y, int z, char value) { - int layer = y >> 4; - int index = ((y & 15) << 8) | (z << 4) | (x & 15); - return sections[layer].set(this, layer, index, value); + public void set(final int x, final int y, final int z, final char value) { + final int layer = y >> 4; + final int index = ((y & 15) << 8) | (z << 4) | (x & 15); + set(layer, index, value); + } + + public final char get(final int layer, final int index) { + return sections[layer].get(this, layer, index); + } + + public final void set(final int layer, final int index, final char value) { + sections[layer].set(this, layer, index, value); } /* @@ -67,18 +75,18 @@ public class CharBlocks implements IBlocks { public static abstract class Section { public abstract char[] get(CharBlocks blocks, int layer); - public final char get(CharBlocks blocks, int layer, int index) { + public final char get(final CharBlocks blocks, final int layer, final int index) { return get(blocks, layer)[index]; } - public final char set(CharBlocks blocks, int layer, int index, char value) { - return get(blocks, layer)[index] = value; + public final void set(final CharBlocks blocks, final int layer, final int index, final char value) { + get(blocks, layer)[index] = value; } } public static final Section NULL = new Section() { @Override - public final char[] get(CharBlocks blocks, int layer) { + public final char[] get(final CharBlocks blocks, final int layer) { blocks.sections[layer] = FULL; char[] arr = blocks.blocks[layer]; if (arr == null) { @@ -92,7 +100,7 @@ public class CharBlocks implements IBlocks { public static final Section FULL = new Section() { @Override - public final char[] get(CharBlocks blocks, int layer) { + public final char[] get(final CharBlocks blocks, final int layer) { return blocks.blocks[layer]; } }; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java index fede5719c..fe5a0286e 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java @@ -20,13 +20,7 @@ public abstract class CharGetBlocks extends CharBlocks implements IGetBlocks { } @Override - public void filter(Filter filter, FilterBlock block) { - CharFilterBlock b = (CharFilterBlock) block; - b.filter(this, filter); - } - - @Override - public boolean trim(boolean aggressive) { + public boolean trim(final boolean aggressive) { for (int i = 0; i < 16; i++) { sections[i] = NULL; blocks[i] = null; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java index d962d5f86..3fc218961 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java @@ -17,7 +17,7 @@ public class CharSetBlocks extends CharBlocks implements ISetBlocks { public HashSet entityRemoves; @Override - public boolean setBiome(int x, int y, int z, BiomeType biome) { + public boolean setBiome(final int x, final int y, final int z, final BiomeType biome) { if (biomes == null) { biomes = new BiomeType[256]; } @@ -26,22 +26,22 @@ public class CharSetBlocks extends CharBlocks implements ISetBlocks { } @Override - public boolean setBlock(int x, int y, int z, BlockStateHolder holder) { + public boolean setBlock(final int x, final int y, final int z, final BlockStateHolder holder) { set(x, y, z, holder.getOrdinalChar()); return true; } @Override - public void setTile(int x, int y, int z, CompoundTag tile) { + public void setTile(final int x, final int y, final int z, final CompoundTag tile) { if (tiles == null) { tiles = new HashMap<>(); } - short pair = MathMan.tripleBlockCoord(x, y, z); + final short pair = MathMan.tripleBlockCoord(x, y, z); tiles.put(pair, tile); } @Override - public void setEntity(CompoundTag tag) { + public void setEntity(final CompoundTag tag) { if (entities == null) { entities = new HashSet<>(); } @@ -49,7 +49,7 @@ public class CharSetBlocks extends CharBlocks implements ISetBlocks { } @Override - public void removeEntity(UUID uuid) { + public void removeEntity(final UUID uuid) { if (entityRemoves == null) { entityRemoves = new HashSet<>(); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/FullCharBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/FullCharBlocks.java index 9d0732d11..bbe4bfec2 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/FullCharBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/FullCharBlocks.java @@ -8,7 +8,7 @@ public class FullCharBlocks implements IBlocks { public final char[] blocks = new char[65536]; @Override - public boolean hasSection(int layer) { + public boolean hasSection(final int layer) { return false; } @@ -18,7 +18,7 @@ public class FullCharBlocks implements IBlocks { } @Override - public boolean trim(boolean aggressive) { + public boolean trim(final boolean aggressive) { return false; } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java index 7ff757113..153e162bd 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java @@ -31,21 +31,22 @@ public abstract class ChunkHolder implements IChunk, Supplier { this.delegate = NULL; } - public ChunkHolder(IBlockDelegate delegate) { + public ChunkHolder(final IBlockDelegate delegate) { this.delegate = delegate; } @Override - public void filter(Filter filter, FilterBlock block) { - block.init(X, Z, get); - IGetBlocks get = getOrCreateGet(); - get.filter(filter, block); + public void filter(final Filter filter, FilterBlock block) { + final IGetBlocks get = getOrCreateGet(); + final ISetBlocks set = getOrCreateSet(); + block = block.init(X, Z, get); + block.filter(get, set, filter); } @Override - public boolean trim(boolean aggressive) { + public boolean trim(final boolean aggressive) { if (set != null) { - boolean result = set.trim(aggressive); + final boolean result = set.trim(aggressive); if (result) { delegate = NULL; get = null; @@ -87,7 +88,7 @@ public abstract class ChunkHolder implements IChunk, Supplier { private IGetBlocks newGet() { if (extent instanceof SingleThreadQueueExtent) { - WorldChunkCache cache = ((SingleThreadQueueExtent) extent).getCache(); + final WorldChunkCache cache = ((SingleThreadQueueExtent) extent).getCache(); return cache.get(MathMan.pairInt(X, Z), this); } return get(); @@ -101,7 +102,7 @@ public abstract class ChunkHolder implements IChunk, Supplier { } @Override - public void init(IQueueExtent extent, final int X, final int Z) { + public void init(final IQueueExtent extent, final int X, final int Z) { this.extent = extent; this.X = X; this.Z = Z; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/FinalizedChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/FinalizedChunk.java index 527bcf5ce..ca599ae94 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/FinalizedChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/FinalizedChunk.java @@ -10,7 +10,7 @@ import com.boydti.fawe.beta.IChunk; public class FinalizedChunk extends DelegateChunk { private final IQueueExtent queueExtent; - public FinalizedChunk(final IChunk parent, IQueueExtent queueExtent) { + public FinalizedChunk(final IChunk parent, final IQueueExtent queueExtent) { super(parent); this.queueExtent = queueExtent; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ReferenceChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ReferenceChunk.java index 6ef9b01a1..cb88a839e 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ReferenceChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ReferenceChunk.java @@ -14,7 +14,7 @@ import java.lang.ref.Reference; public abstract class ReferenceChunk implements IDelegateChunk { private final Reference ref; - public ReferenceChunk(final IChunk parent, IQueueExtent queueExtent) { + public ReferenceChunk(final IChunk parent, final IQueueExtent queueExtent) { this.ref = toRef(new FinalizedChunk(parent, queueExtent)); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/InspectBrush.java b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/InspectBrush.java index 785ab43af..ed34c3e60 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/InspectBrush.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/InspectBrush.java @@ -49,7 +49,6 @@ public class InspectBrush extends BrushTool implements DoubleActionTraceTool { } public Vector3 getTarget(Player player, boolean adjacent) { - Location target = null; int range = this.range > -1 ? getRange() : MAX_RANGE; if (adjacent) { Location face = player.getBlockTraceFace(range, true); 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 8a5da394a..9b9939ede 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 @@ -22,9 +22,9 @@ package com.sk89q.worldedit.command; import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweAPI; import com.boydti.fawe.beta.IQueueExtent; +import com.boydti.fawe.beta.filters.SetFilter; import com.boydti.fawe.beta.implementation.QueueHandler; -import com.boydti.fawe.beta.implementation.WorldChunkCache; -import com.boydti.fawe.beta.test.CountFilter; +import com.boydti.fawe.beta.filters.CountFilter; import com.boydti.fawe.config.BBC; import com.boydti.fawe.example.NMSMappedFaweQueue; import com.boydti.fawe.object.FaweLimit; @@ -48,7 +48,6 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.function.GroundFunction; import com.sk89q.worldedit.function.generator.FloraGenerator; -import com.sk89q.worldedit.function.generator.ForestGenerator; import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.NoiseFilter2D; @@ -66,7 +65,6 @@ import com.sk89q.worldedit.math.convolution.HeightMap; import com.sk89q.worldedit.math.convolution.HeightMapFilter; import com.sk89q.worldedit.math.noise.RandomNoise; import com.sk89q.worldedit.regions.*; -import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.util.command.binding.Range; @@ -79,12 +77,12 @@ import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.biome.Biomes; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.registry.BiomeRegistry; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -116,6 +114,41 @@ public class RegionCommands extends MethodCommands { this.worldEdit = worldEdit; } + + @Command( + aliases = {"debugtest"}, + usage = "", + desc = "debugtest", + help = "debugtest" + ) + public void debugtest(Player player, @Selection Region region) throws WorldEditException { + QueueHandler queueHandler = Fawe.get().getQueueHandler(); + World world = player.getWorld(); + CountFilter filter = new CountFilter(); + long start = System.currentTimeMillis(); + queueHandler.apply(world, region, filter); + long diff = System.currentTimeMillis() - start; + System.out.println(diff); + } + + @Command( + aliases = {"db2"}, + usage = "", + desc = "db2", + help = "db2" + ) + public void db2(Player player, @Selection Region region, String blockStr) throws WorldEditException { + QueueHandler queueHandler = Fawe.get().getQueueHandler(); + World world = player.getWorld(); + BlockState block = BlockState.get(blockStr); + SetFilter filter = new SetFilter(block); + long start = System.currentTimeMillis(); + queueHandler.apply(world, region, filter); + long diff = System.currentTimeMillis() - start; + System.out.println(diff); + } + + @Command( aliases = {"/fixlighting"}, desc = "Get the light at a position", @@ -271,44 +304,6 @@ public class RegionCommands extends MethodCommands { BBC.VISITOR_BLOCK.send(player, blocksChanged); } - @Command( - aliases = {"debugtest"}, - usage = "", - desc = "debugtest", - help = "debugtest" - ) - public void debugtest(Player player, @Selection Region region) throws WorldEditException { - QueueHandler queueHandler = Fawe.get().getQueueHandler(); - World world = player.getWorld(); - CountFilter filter = new CountFilter(); - long start = System.currentTimeMillis(); - queueHandler.apply(world, region, filter); - long diff = System.currentTimeMillis() - start; - System.out.println(diff); - } - - @Command( - aliases = {"db2"}, - usage = "", - desc = "db2", - help = "db2" - ) - public void db2(Player player, @Selection Region region) throws WorldEditException { - QueueHandler queueHandler = Fawe.get().getQueueHandler(); - World world = player.getWorld(); - IQueueExtent queue = queueHandler.getQueue(world); - BlockState block = BlockTypes.STONE.getDefaultState(); - long start = System.currentTimeMillis(); - for (BlockVector3 p : region) { - queue.setBlock(p.getX(), p.getY(), p.getZ(), block); - } - long start2 = System.currentTimeMillis(); - queue.flush(); - long diff = System.currentTimeMillis() - start; - long diff2 = System.currentTimeMillis() - start2; - System.out.println(diff + " | " + diff2); - } - @Command( aliases = {"/curve", "/spline"}, usage = " [thickness]", From 4116adcfef5a3352c5681b5a7eed700e890cd09d Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Fri, 3 May 2019 03:38:08 +1000 Subject: [PATCH 15/54] Some refactoring --- .../fawe/bukkit/beta/BukkitChunkHolder.java | 76 +++++++++---------- .../com/boydti/fawe/beta/CharFilterBlock.java | 44 +++++------ .../java/com/boydti/fawe/beta/Filter.java | 2 +- .../com/boydti/fawe/beta/FilterBlock.java | 4 +- .../java/com/boydti/fawe/beta/IChunk.java | 10 --- .../java/com/boydti/fawe/beta/ISetBlocks.java | 19 +++++ .../boydti/fawe/beta/filters/CountFilter.java | 42 ++++++---- .../fawe/beta/filters/ForkedFilter.java | 48 ++++++++++++ .../beta/implementation/QueueHandler.java | 57 ++++++-------- .../implementation/blocks/CharSetBlocks.java | 34 +++++++++ .../implementation/blocks/FullCharBlocks.java | 24 ------ .../implementation/holder/ChunkHolder.java | 18 +++-- .../collection/IterableThreadLocal.java | 14 +++- 13 files changed, 232 insertions(+), 160 deletions(-) create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/filters/ForkedFilter.java delete mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/FullCharBlocks.java diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java index 0eec7fbf7..7abe76c21 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java @@ -2,16 +2,14 @@ package com.boydti.fawe.bukkit.beta; import com.boydti.fawe.Fawe; import com.boydti.fawe.beta.Filter; -import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.IGetBlocks; import com.boydti.fawe.beta.IQueueExtent; +import com.boydti.fawe.beta.ISetBlocks; import com.boydti.fawe.beta.implementation.QueueHandler; -import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks; import com.boydti.fawe.beta.implementation.holder.ChunkHolder; import com.boydti.fawe.bukkit.v0.BukkitQueue_0; import com.boydti.fawe.bukkit.v1_13.BukkitQueue_1_13; import com.boydti.fawe.util.ReflectionUtils; -import com.google.common.util.concurrent.Futures; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.LongTag; @@ -20,8 +18,6 @@ import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.internal.Constants; import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BlockTypes; -import net.jpountz.util.UnsafeUtils; import net.minecraft.server.v1_13_R2.BiomeBase; import net.minecraft.server.v1_13_R2.BlockPosition; import net.minecraft.server.v1_13_R2.Chunk; @@ -37,18 +33,14 @@ import org.bukkit.block.Biome; import org.bukkit.craftbukkit.v1_13_R2.block.CraftBlock; import org.bukkit.event.entity.CreatureSpawnEvent; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.Future; -import java.util.concurrent.atomic.AtomicReferenceArray; public class BukkitChunkHolder> extends ChunkHolder { @Override @@ -86,7 +78,7 @@ public class BukkitChunkHolder> extends ChunkHolder { int Z = getZ(); BukkitQueue extent = (BukkitQueue) getExtent(); BukkitGetBlocks get = (BukkitGetBlocks) getOrCreateGet(); - CharSetBlocks set = (CharSetBlocks) getOrCreateSet(); + ISetBlocks set = getOrCreateSet(); Chunk nmsChunk = extent.ensureLoaded(X, Z); @@ -102,12 +94,10 @@ public class BukkitChunkHolder> extends ChunkHolder { final int ly = pos.getY(); final int lz = pos.getZ() & 15; final int layer = ly >> 4; - final char[] array = set.blocks[layer]; - if (array == null) { + if (!set.hasSection(layer)) { continue; } - final int index = (((ly & 0xF) << 8) | (lz << 4) | lx); - if (array[index] != 0) { + if (set.getBlock(lx, ly, lz).getOrdinal() != 0) { TileEntity tile = entry.getValue(); tile.z(); tile.invalidateBlockCache(); @@ -116,7 +106,6 @@ public class BukkitChunkHolder> extends ChunkHolder { } } - int bitMask = 0; synchronized (nmsChunk) { ChunkSection[] sections = nmsChunk.getSections(); @@ -128,7 +117,7 @@ public class BukkitChunkHolder> extends ChunkHolder { bitMask |= 1 << layer; - char[] setArr = set.blocks[layer]; + char[] setArr = set.getArray(layer); ChunkSection newSection; ChunkSection existingSection = sections[layer]; if (existingSection == null) { @@ -182,11 +171,12 @@ public class BukkitChunkHolder> extends ChunkHolder { } // Biomes - if (set.biomes != null) { + BiomeType[] biomes = set.getBiomes(); + if (biomes != null) { // set biomes final BiomeBase[] currentBiomes = nmsChunk.getBiomeIndex(); - for (int i = 0; i < set.biomes.length; i++) { - final BiomeType biome = set.biomes[i]; + for (int i = 0; i < biomes.length; i++) { + final BiomeType biome = biomes[i]; if (biome != null) { final Biome craftBiome = BukkitAdapter.adapt(biome); currentBiomes[i] = CraftBlock.biomeToBiomeBase(craftBiome); @@ -200,11 +190,10 @@ public class BukkitChunkHolder> extends ChunkHolder { int bx = X << 4; int bz = Z << 4; - if (set.entityRemoves != null && !set.entityRemoves.isEmpty()) { + Set entityRemoves = set.getEntityRemoves(); + if (entityRemoves != null && !entityRemoves.isEmpty()) { if (syncTasks == null) syncTasks = new Runnable[3]; - HashSet entsToRemove = set.entityRemoves; - syncTasks[2] = new Runnable() { @Override public void run() { @@ -216,7 +205,7 @@ public class BukkitChunkHolder> extends ChunkHolder { final Iterator iter = ents.iterator(); while (iter.hasNext()) { final Entity entity = iter.next(); - if (entsToRemove.contains(entity.getUniqueID())) { + if (entityRemoves.contains(entity.getUniqueID())) { iter.remove(); entity.b(false); entity.die(); @@ -229,15 +218,14 @@ public class BukkitChunkHolder> extends ChunkHolder { }; } - if (set.entities != null && !set.entities.isEmpty()) { + Set entities = set.getEntities(); + if (entities != null && !entities.isEmpty()) { if (syncTasks == null) syncTasks = new Runnable[2]; - HashSet entitiesToSpawn = set.entities; - syncTasks[1] = new Runnable() { @Override public void run() { - for (final CompoundTag nativeTag : entitiesToSpawn) { + for (final CompoundTag nativeTag : entities) { final Map entityTagMap = ReflectionUtils.getMap(nativeTag.getValue()); final StringTag idTag = (StringTag) entityTagMap.get("Id"); final ListTag posTag = (ListTag) entityTagMap.get("Pos"); @@ -274,10 +262,10 @@ public class BukkitChunkHolder> extends ChunkHolder { } // set tiles - if (set.tiles != null && !set.tiles.isEmpty()) { + Map tiles = set.getTiles(); + if (tiles != null && !tiles.isEmpty()) { if (syncTasks == null) syncTasks = new Runnable[1]; - HashMap tiles = set.tiles; syncTasks[0] = new Runnable() { @Override public void run() { @@ -307,19 +295,22 @@ public class BukkitChunkHolder> extends ChunkHolder { }; } - int finalMask = bitMask; - Runnable callback = () -> { - if (finalMask != 0) { + Runnable callback; + if (bitMask == 0) { + callback = null; + } else { + int finalMask = bitMask; + callback = () -> { // Set Modified nmsChunk.f(true); nmsChunk.mustSave = true; nmsChunk.markDirty(); // send to player extent.sendChunk(X, Z, finalMask); - } - extent.returnToPool(BukkitChunkHolder.this); - }; + extent.returnToPool(BukkitChunkHolder.this); + }; + } if (syncTasks != null) { QueueHandler queueHandler = Fawe.get().getQueueHandler(); Runnable[] finalSyncTasks = syncTasks; @@ -335,12 +326,21 @@ public class BukkitChunkHolder> extends ChunkHolder { task.run(); } } - return queueHandler.async(callback, null); + if (callback == null) { + extent.returnToPool(BukkitChunkHolder.this); + return null; + } else { + return queueHandler.async(callback, null); + } } }; return (T) (Future) queueHandler.sync(chain); } else { - callback.run(); + if (callback == null) { + extent.returnToPool(BukkitChunkHolder.this); + } else { + callback.run(); + } } } return null; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java index 6db6b7c7d..8d767b49e 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java @@ -1,7 +1,6 @@ package com.boydti.fawe.beta; import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; -import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -14,7 +13,8 @@ import static com.sk89q.worldedit.world.block.BlockTypes.states; public class CharFilterBlock implements FilterBlock { private IQueueExtent queue; private CharGetBlocks get; - private CharSetBlocks set; + + private ISetBlocks set; private char[] getArr; private @Nullable char[] setArr; @@ -39,28 +39,26 @@ public class CharFilterBlock implements FilterBlock { return this; } - public final void filter(final IGetBlocks iget, final ISetBlocks iset, final Filter filter) { - final CharSetBlocks set = (CharSetBlocks) iset; + @Override + public final void filter(final IGetBlocks iget, final ISetBlocks iset, final int layer, final Filter filter) { + this.layer = layer; final CharGetBlocks get = (CharGetBlocks) iget; - for (int layer = 0; layer < 16; layer++) { - if (!get.hasSection(layer)) continue; - this.set = set; - getArr = get.sections[layer].get(get, layer); - if (set.hasSection(layer)) { - setArr = set.blocks[layer]; - delegate = FULL; - } else { - delegate = NULL; - setArr = null; - } - this.layer = layer; - this.yy = layer << 4; + if (!get.hasSection(layer)) return; + this.set = iset; + getArr = get.sections[layer].get(get, layer); + if (set.hasSection(layer)) { + setArr = set.getArray(layer); + delegate = FULL; + } else { + delegate = NULL; + setArr = null; + } + this.yy = layer << 4; - for (y = 0, index = 0; y < 16; y++) { - for (z = 0; z < 16; z++) { - for (x = 0; x < 16; x++, index++) { - filter.applyBlock(this); - } + for (y = 0, index = 0; y < 16; y++) { + for (z = 0; z < 16; z++) { + for (x = 0; x < 16; x++, index++) { + filter.applyBlock(this); } } } @@ -305,7 +303,7 @@ public class CharFilterBlock implements FilterBlock { Set delegate */ private SetDelegate initSet() { - setArr = set.sections[layer].get(set, layer); + setArr = set.getArray(layer); return delegate = FULL; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java index 01a49bdc7..9bcdf29c8 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java @@ -57,7 +57,7 @@ public interface Filter { return this; } - default void join(final Filter parent) { + default void join() { } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java index ac6cd3312..e305dc43c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java @@ -1,7 +1,5 @@ package com.boydti.fawe.beta; -import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; -import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -11,7 +9,7 @@ public interface FilterBlock { FilterBlock init(int X, int Z, IGetBlocks chunk); - void filter(IGetBlocks get, ISetBlocks set, Filter filter); + void filter(IGetBlocks get, ISetBlocks set, int layer, Filter filter); void setOrdinal(int ordinal); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java index eb6afbd84..827bc8c7a 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java @@ -27,8 +27,6 @@ public interface IChunk> extends Trimable, Callable { int getZ(); - - /** * If the chunk is a delegate, returns it's paren'ts root * @return root IChunk @@ -42,14 +40,6 @@ public interface IChunk> extends Trimable, Callable { */ boolean isEmpty(); - /** - * Spend time optimizing for apply
- * default behavior: do nothing - */ - default void optimize() { - - } - /** * Apply the queued changes to the world
* The future returned may return another future
diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java index 51fcd9dc9..dda0dfd5a 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java @@ -2,9 +2,13 @@ package com.boydti.fawe.beta; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; +import java.util.Set; import java.util.UUID; /** @@ -26,4 +30,19 @@ public interface ISetBlocks extends IBlocks { default void optimize() { } + + BlockState getBlock(int x, int y, int z); + + char[] getArray(int layer); + + BiomeType[] getBiomes(); + + Map getTiles(); + + Set getEntities(); + + Set getEntityRemoves(); + + @Override + void reset(); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/CountFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/CountFilter.java index 052519cd7..988b60161 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/CountFilter.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/CountFilter.java @@ -1,6 +1,5 @@ package com.boydti.fawe.beta.filters; -import com.boydti.fawe.beta.Filter; import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.config.BBC; import com.sk89q.worldedit.extension.platform.Actor; @@ -12,11 +11,35 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -public class CountFilter implements Filter { +public class CountFilter extends ForkedFilter { private final int[] counter = new int[BlockTypes.states.length]; + public CountFilter() { + super(null); + } + + private CountFilter(CountFilter root) { + super(root); + } + @Override - public void applyBlock(final FilterBlock block) { + public CountFilter init() { + return new CountFilter(this); + } + + @Override + public void join(CountFilter filter) { + for (int i = 0; i < filter.counter.length; i++) { + this.counter[i] += filter.counter[i]; + } + } + + /* + Implementation + */ + + @Override + public final void applyBlock(final FilterBlock block) { counter[block.getOrdinal()]++; } @@ -42,17 +65,4 @@ public class CountFilter implements Filter { actor.print(BBC.getPrefix() + str); } } - - @Override - public Filter fork() { - return new CountFilter(); - } - - @Override - public void join(final Filter parent) { - final CountFilter other = (CountFilter) parent; - for (int i = 0; i < counter.length; i++) { - other.counter[i] += this.counter[i]; - } - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/ForkedFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/ForkedFilter.java new file mode 100644 index 000000000..6118c4dea --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/ForkedFilter.java @@ -0,0 +1,48 @@ +package com.boydti.fawe.beta.filters; + +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.FilterBlock; +import com.boydti.fawe.config.BBC; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.util.Countable; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public abstract class ForkedFilter> implements Filter { + protected final Map children; + + public ForkedFilter(T root) { + if (root != null) { + children = root.children; + } else { + children = new ConcurrentHashMap<>(); + children.put(Thread.currentThread(), (T) this); + } + } + + @Override + public final Filter fork() { + return children.computeIfAbsent(Thread.currentThread(), thread -> init()); + } + + public abstract T init(); + + @Override + public void join() { + for (Map.Entry entry : children.entrySet()) { + T filter = entry.getValue(); + if (filter != this) { + join(filter); + } + } + children.clear(); + } + + public abstract void join(T filter); +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java index 4cfe41121..b7965f2a3 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java @@ -12,7 +12,6 @@ import com.boydti.fawe.object.collection.IterableThreadLocal; import com.boydti.fawe.util.MemUtil; import com.boydti.fawe.util.TaskManager; import com.boydti.fawe.wrappers.WorldWrapper; -import com.google.common.util.concurrent.Futures; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.World; @@ -24,7 +23,6 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ExecutorService; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinTask; import java.util.concurrent.Future; @@ -163,40 +161,30 @@ public abstract class QueueHandler implements Trimable, Runnable { synchronized (queue) { FilterBlock block = null; - try { - while (true) { - // Get the next chunk pos - final int X, Z; - synchronized (chunksIter) { - if (!chunksIter.hasNext()) break; - final BlockVector2 pos = chunksIter.next(); - X = pos.getX(); - Z = pos.getZ(); - } - IChunk chunk = queue.getCachedChunk(X, Z); - // Initialize - chunk.init(queue, X, Z); - - if (!newFilter.appliesChunk(X, Z)) { - continue; - } - chunk = newFilter.applyChunk(chunk); - - if (chunk == null) continue; - - if (block == null) block = queue.initFilterBlock(); - chunk.filter(newFilter, block); - - newFilter.finishChunk(chunk); - - queue.submit(chunk); + while (true) { + // Get the next chunk pos + final int X, Z; + synchronized (chunksIter) { + if (!chunksIter.hasNext()) break; + final BlockVector2 pos = chunksIter.next(); + X = pos.getX(); + Z = pos.getZ(); } - } finally { - if (filter != newFilter) { - synchronized (filter) { - newFilter.join(filter); - } + IChunk chunk = queue.getCachedChunk(X, Z); + // Initialize + chunk.init(queue, X, Z); + + if (!newFilter.appliesChunk(X, Z)) { + continue; } + chunk = newFilter.applyChunk(chunk); + + if (chunk == null) continue; + + if (block == null) block = queue.initFilterBlock(); + chunk.filter(newFilter, block); + + queue.submit(chunk); } queue.flush(); } @@ -210,5 +198,6 @@ public abstract class QueueHandler implements Trimable, Runnable { task.quietlyJoin(); } } + filter.join(); } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java index 3fc218961..f132fe2da 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java @@ -4,10 +4,14 @@ import com.boydti.fawe.beta.ISetBlocks; import com.boydti.fawe.util.MathMan; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; import java.util.HashMap; import java.util.HashSet; +import java.util.Map; +import java.util.Set; import java.util.UUID; public class CharSetBlocks extends CharBlocks implements ISetBlocks { @@ -16,6 +20,31 @@ public class CharSetBlocks extends CharBlocks implements ISetBlocks { public HashSet entities; public HashSet entityRemoves; + @Override + public char[] getArray(int layer) { + return sections[layer].get(this, layer); + } + + @Override + public BiomeType[] getBiomes() { + return biomes; + } + + @Override + public Map getTiles() { + return tiles; + } + + @Override + public Set getEntities() { + return entities; + } + + @Override + public Set getEntityRemoves() { + return entityRemoves; + } + @Override public boolean setBiome(final int x, final int y, final int z, final BiomeType biome) { if (biomes == null) { @@ -25,6 +54,11 @@ public class CharSetBlocks extends CharBlocks implements ISetBlocks { return true; } + @Override + public BlockState getBlock(int x, int y, int z) { + return BlockTypes.states[get(x, y, z)]; + } + @Override public boolean setBlock(final int x, final int y, final int z, final BlockStateHolder holder) { set(x, y, z, holder.getOrdinalChar()); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/FullCharBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/FullCharBlocks.java deleted file mode 100644 index bbe4bfec2..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/FullCharBlocks.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.boydti.fawe.beta.implementation.blocks; - -import com.boydti.fawe.beta.IBlocks; - -// TODO implement -public class FullCharBlocks implements IBlocks { - public final boolean[] hasSections = new boolean[16]; - public final char[] blocks = new char[65536]; - - @Override - public boolean hasSection(final int layer) { - return false; - } - - @Override - public void reset() { - - } - - @Override - public boolean trim(final boolean aggressive) { - return false; - } -} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java index 153e162bd..46c491cfa 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java @@ -40,7 +40,11 @@ public abstract class ChunkHolder implements IChunk, Supplier { final IGetBlocks get = getOrCreateGet(); final ISetBlocks set = getOrCreateSet(); block = block.init(X, Z, get); - block.filter(get, set, filter); + for (int layer = 0; layer < 16; layer++) { + if (!get.hasSection(layer)) continue; + block.filter(get, set, layer, filter); + } + filter.finishChunk(this); } @Override @@ -94,12 +98,12 @@ public abstract class ChunkHolder implements IChunk, Supplier { return get(); } - @Override - public void optimize() { - if (set != null) { - set.optimize(); - } - } +// @Override +// public void optimize() { +// if (set != null) { +// set.optimize(); +// } +// } @Override public void init(final IQueueExtent extent, final int X, final int Z) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/IterableThreadLocal.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/IterableThreadLocal.java index c31704c8d..2aef7daf7 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/IterableThreadLocal.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/IterableThreadLocal.java @@ -11,8 +11,7 @@ import java.util.Iterator; import java.util.concurrent.ConcurrentLinkedDeque; public abstract class IterableThreadLocal extends ThreadLocal implements Iterable { - private ThreadLocal flag; - private ConcurrentLinkedDeque allValues = new ConcurrentLinkedDeque<>(); + private final ConcurrentLinkedDeque allValues = new ConcurrentLinkedDeque<>(); public IterableThreadLocal() { } @@ -21,7 +20,9 @@ public abstract class IterableThreadLocal extends ThreadLocal implements I protected final T initialValue() { T value = init(); if (value != null) { - allValues.add(value); + synchronized (this) { + allValues.add(value); + } } return value; } @@ -36,7 +37,12 @@ public abstract class IterableThreadLocal extends ThreadLocal implements I } public void clean() { - IterableThreadLocal.clean(this); + if (!allValues.isEmpty()) { + synchronized (this) { + IterableThreadLocal.clean(this); + allValues.clear(); + } + } } public static void clean(ThreadLocal instance) { From 27ed5960279351076438ac550b83f589aca8fabd Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Sat, 4 May 2019 02:33:45 +1000 Subject: [PATCH 16/54] filter regions? --- .../com/boydti/fawe/beta/DelegateFilter.java | 16 ++++++ .../java/com/boydti/fawe/beta/Filter.java | 13 +++-- .../com/boydti/fawe/beta/FilterBlock.java | 5 +- .../com/boydti/fawe/beta/IDelegateFilter.java | 54 +++++++++++++++++++ .../java/com/boydti/fawe/beta/ISetBlocks.java | 4 -- .../com/boydti/fawe/beta/RegionFilter.java | 37 +++++++++++++ .../beta/implementation/QueueHandler.java | 6 +-- .../implementation/blocks/CharGetBlocks.java | 3 -- .../implementation/holder/ChunkHolder.java | 9 +--- 9 files changed, 125 insertions(+), 22 deletions(-) create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilter.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateFilter.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/RegionFilter.java diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilter.java new file mode 100644 index 000000000..eb941c5a9 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilter.java @@ -0,0 +1,16 @@ +package com.boydti.fawe.beta; + +public abstract class DelegateFilter implements IDelegateFilter { + private final Filter parent; + + public DelegateFilter(Filter parent) { + this.parent = parent; + } + @Override + public Filter getParent() { + return parent; + } + + @Override + public abstract Filter fork(); +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java index 9bcdf29c8..ba55e3ef9 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java @@ -1,7 +1,10 @@ package com.boydti.fawe.beta; +import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.block.BaseBlock; +import javax.annotation.Nullable; + /** * A filter is an interface used for setting blocks */ @@ -13,8 +16,8 @@ public interface Filter { * @param cz * @return */ - default boolean appliesChunk(final int cx, final int cz) { - return true; + default Filter appliesChunk(final int cx, final int cz) { + return this; } /** @@ -25,10 +28,14 @@ public interface Filter { * @param chunk * @return */ - default IChunk applyChunk(final IChunk chunk) { + default IChunk applyChunk(final IChunk chunk, @Nullable Region region) { return chunk; } + default Filter appliesLayer(IChunk chunk, int layer) { + return this; + } + /** * Make changes to the block here
* - e.g. block.setId(...)
diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java index e305dc43c..c2e6508b3 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java @@ -1,15 +1,18 @@ package com.boydti.fawe.beta; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; +import javax.annotation.Nullable; + public interface FilterBlock { FilterBlock init(IQueueExtent queue); FilterBlock init(int X, int Z, IGetBlocks chunk); - void filter(IGetBlocks get, ISetBlocks set, int layer, Filter filter); + void filter(IGetBlocks get, ISetBlocks set, int layer, Filter filter, @Nullable Region region); void setOrdinal(int ordinal); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateFilter.java new file mode 100644 index 000000000..9f8274ef0 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateFilter.java @@ -0,0 +1,54 @@ +package com.boydti.fawe.beta; + +public interface IDelegateFilter extends Filter { + Filter getParent(); + + @Override + default Filter appliesChunk(int cx, int cz) { + Filter copy = getParent().appliesChunk(cx, cz); + if (copy == null) return null; + if (copy != getParent()) { + return newInstance(copy); + } else { + return this; + } + } + + @Override + default IChunk applyChunk(IChunk chunk) { + return getParent().applyChunk(chunk); + } + + @Override + default Filter appliesLayer(IChunk chunk, int layer) { + Filter copy = getParent().appliesLayer(chunk, layer); + if (copy == null) return null; + if (copy != getParent()) { + return newInstance(copy); + } else { + return this; + } + } + + @Override + default void applyBlock(FilterBlock block) { + getParent().applyBlock(block); + } + + @Override + default void finishChunk(IChunk chunk) { + getParent().finishChunk(chunk); + } + + @Override + default void join() { + getParent().join(); + } + + @Override + default Filter fork() { + return newInstance(getParent().fork()); + } + + Filter newInstance(Filter other); +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java index dda0dfd5a..7ba1f664a 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java @@ -27,10 +27,6 @@ public interface ISetBlocks extends IBlocks { void removeEntity(UUID uuid); - default void optimize() { - - } - BlockState getBlock(int x, int y, int z); char[] getArray(int layer); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/RegionFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/RegionFilter.java new file mode 100644 index 000000000..791e040d6 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/RegionFilter.java @@ -0,0 +1,37 @@ +package com.boydti.fawe.beta; + +import com.sk89q.worldedit.regions.Region; + +public class RegionFilter extends DelegateFilter { + private final Region region; + + public RegionFilter(Filter parent, Region region) { + super(parent); + this.region = region; + } + + @Override + public Filter appliesChunk(int cx, int cz) { + return getParent().appliesChunk(cx, cz); + } + + @Override + public Filter appliesLayer(IChunk chunk, int layer) { + return getParent().appliesLayer(chunk, layer); + } + + @Override + public void applyBlock(FilterBlock block) { + getParent().applyBlock(block); + } + + @Override + public void finishChunk(IChunk chunk) { + getParent().finishChunk(chunk); + } + + @Override + public Filter newInstance(Filter other) { + return new RegionFilter(other, region); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java index b7965f2a3..26e7bf898 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java @@ -170,13 +170,13 @@ public abstract class QueueHandler implements Trimable, Runnable { X = pos.getX(); Z = pos.getZ(); } + if (!newFilter.appliesChunk(X, Z)) { + continue; + } IChunk chunk = queue.getCachedChunk(X, Z); // Initialize chunk.init(queue, X, Z); - if (!newFilter.appliesChunk(X, Z)) { - continue; - } chunk = newFilter.applyChunk(chunk); if (chunk == null) continue; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java index fe5a0286e..5c92c09aa 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java @@ -1,8 +1,5 @@ package com.boydti.fawe.beta.implementation.blocks; -import com.boydti.fawe.beta.CharFilterBlock; -import com.boydti.fawe.beta.Filter; -import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.beta.IGetBlocks; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java index 46c491cfa..878f3c039 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java @@ -41,7 +41,7 @@ public abstract class ChunkHolder implements IChunk, Supplier { final ISetBlocks set = getOrCreateSet(); block = block.init(X, Z, get); for (int layer = 0; layer < 16; layer++) { - if (!get.hasSection(layer)) continue; + if (!get.hasSection(layer) || !filter.appliesLayer(this, layer)) continue; block.filter(get, set, layer, filter); } filter.finishChunk(this); @@ -98,13 +98,6 @@ public abstract class ChunkHolder implements IChunk, Supplier { return get(); } -// @Override -// public void optimize() { -// if (set != null) { -// set.optimize(); -// } -// } - @Override public void init(final IQueueExtent extent, final int X, final int Z) { this.extent = extent; From 7c174beaeeb2a9b9a880995aca0bed30735d6414 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Sun, 5 May 2019 03:58:26 +1000 Subject: [PATCH 17/54] Region filter --- .../fawe/bukkit/beta/BukkitChunkHolder.java | 7 - .../com/boydti/fawe/beta/CharFilterBlock.java | 78 ++++++- .../java/com/boydti/fawe/beta/Filter.java | 8 +- .../com/boydti/fawe/beta/FilterBlock.java | 3 +- .../java/com/boydti/fawe/beta/IChunk.java | 21 +- .../com/boydti/fawe/beta/IDelegateChunk.java | 12 +- .../com/boydti/fawe/beta/IDelegateFilter.java | 28 +-- .../com/boydti/fawe/beta/RegionFilter.java | 37 ---- .../beta/implementation/QueueHandler.java | 10 +- .../implementation/holder/ChunkHolder.java | 44 +++- .../sk89q/worldedit/regions/CuboidRegion.java | 32 +++ .../com/sk89q/worldedit/regions/Region.java | 33 +++ .../worldedit/regions/RegionIntersection.java | 5 + .../worldedit/regions/TransformRegion.java | 191 ------------------ .../session/request/RequestSelection.java | 6 + 15 files changed, 232 insertions(+), 283 deletions(-) delete mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/RegionFilter.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/regions/TransformRegion.java diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java index 7abe76c21..7739a66b7 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java @@ -349,11 +349,4 @@ public class BukkitChunkHolder> extends ChunkHolder { return null; } } - - @Override - public void set(final Filter filter) { - // for each block - // filter.applyBlock(block) - throw new UnsupportedOperationException("Not implemented"); - } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java index 8d767b49e..42a90e24c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java @@ -2,6 +2,8 @@ package com.boydti.fawe.beta; import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; @@ -40,7 +42,7 @@ public class CharFilterBlock implements FilterBlock { } @Override - public final void filter(final IGetBlocks iget, final ISetBlocks iset, final int layer, final Filter filter) { + public final void filter(final IGetBlocks iget, final ISetBlocks iset, final int layer, final Filter filter, final @Nullable Region region, BlockVector3 min, BlockVector3 max) { this.layer = layer; final CharGetBlocks get = (CharGetBlocks) iget; if (!get.hasSection(layer)) return; @@ -54,7 +56,81 @@ public class CharFilterBlock implements FilterBlock { setArr = null; } this.yy = layer << 4; + if (region == null) { + if (min != null && max != null) { + iterate(min, max, layer, filter); + } else { + iterate(filter); + } + } else { + if (min != null && max != null) { + iterate(region, min, max, layer, filter); + } else { + iterate(region, filter); + } + } + } + private void iterate(final Region region, final Filter filter) { + for (y = 0, index = 0; y < 16; y++) { + int absY = yy + y; + for (z = 0; z < 16; z++) { + int absZ = zz + z; + for (x = 0; x < 16; x++, index++) { + int absX = xx + x; + if (region.contains(absX, absY, absZ)) { + filter.applyBlock(this); + } + } + } + } + } + + private void iterate(final Region region, BlockVector3 min, BlockVector3 max, int layer, final Filter filter) { + int by = Math.max(min.getY(), layer << 4) & 15; + int ty = Math.min(max.getY(), 15 + (layer << 4)) & 15; + int bx = min.getX(); + int bz = min.getZ(); + int tx = max.getX(); + int tz = max.getZ(); + for (y = by; y <= ty; y++) { + int yIndex = (y << 8); + int absY = yy + y; + for (z = bz; z <= tz; z++) { + int zIndex = yIndex + ((z) << 4); + int absZ = zz + z; + for (x = bx; x <= tx; x++) { + index = zIndex + x; + int absX = xx + x; + if (region.contains(absX, absY, absZ)) { + filter.applyBlock(this); + } + + } + } + } + } + + private void iterate(BlockVector3 min, BlockVector3 max, int layer, final Filter filter) { + int by = Math.max(min.getY(), layer << 4) & 15; + int ty = Math.min(max.getY(), 15 + (layer << 4)) & 15; + int bx = min.getX(); + int bz = min.getZ(); + int tx = max.getX(); + int tz = max.getZ(); + for (y = by; y <= ty; y++) { + int yIndex = (y << 8); + for (z = bz; z <= tz; z++) { + int zIndex = yIndex + ((z) << 4); + for (x = bx; x <= tx; x++) { + index = zIndex + x; + filter.applyBlock(this); + } + } + } + } + + private final void iterate(final Filter filter) { for (y = 0, index = 0; y < 16; y++) { for (z = 0; z < 16; z++) { for (x = 0; x < 16; x++, index++) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java index ba55e3ef9..2f19852c3 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java @@ -16,8 +16,8 @@ public interface Filter { * @param cz * @return */ - default Filter appliesChunk(final int cx, final int cz) { - return this; + default boolean appliesChunk(final int cx, final int cz) { + return true; } /** @@ -32,8 +32,8 @@ public interface Filter { return chunk; } - default Filter appliesLayer(IChunk chunk, int layer) { - return this; + default boolean appliesLayer(IChunk chunk, int layer) { + return true; } /** diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java index c2e6508b3..96a06562e 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java @@ -1,6 +1,7 @@ package com.boydti.fawe.beta; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -12,7 +13,7 @@ public interface FilterBlock { FilterBlock init(int X, int Z, IGetBlocks chunk); - void filter(IGetBlocks get, ISetBlocks set, int layer, Filter filter, @Nullable Region region); + void filter(IGetBlocks get, ISetBlocks set, int layer, Filter filter, @Nullable Region region, BlockVector3 min, BlockVector3 max); void setOrdinal(int ordinal); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java index 827bc8c7a..dbc45d124 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java @@ -1,10 +1,13 @@ package com.boydti.fawe.beta; +import com.sk89q.worldedit.math.MutableBlockVector3; +import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; +import javax.annotation.Nullable; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -61,23 +64,25 @@ public interface IChunk> extends Trimable, Callable { return; } + /** + * Filter + * @param filter the filter + * @param block The filter block + * @param region The region allowed to filter (may be null) + * @param unitialized a mutable block vector (buffer) + * @param unitialized2 a mutable block vector (buffer) + */ + void filter(Filter filter, FilterBlock block, @Nullable Region region, MutableBlockVector3 unitialized, MutableBlockVector3 unitialized2); + /* set - queues a change */ boolean setBiome(int x, int y, int z, BiomeType biome); boolean setBlock(int x, int y, int z, BlockStateHolder block); - /** - * Set using the filter - * @param filter - */ - void set(Filter filter); - /* get - from the world */ BiomeType getBiome(int x, int z); BlockState getBlock(int x, int y, int z); BaseBlock getFullBlock(int x, int y, int z); - - void filter(Filter filter, FilterBlock mutable); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java index 8d57af1be..0a21e1c1a 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java @@ -1,10 +1,13 @@ package com.boydti.fawe.beta; +import com.sk89q.worldedit.math.MutableBlockVector3; +import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; +import javax.annotation.Nullable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -80,8 +83,8 @@ public interface IDelegateChunk extends IChunk { } @Override - default void filter(final Filter filter, final FilterBlock mutable) { - getParent().filter(filter, mutable); + default void filter(Filter filter, FilterBlock block, @Nullable Region region, MutableBlockVector3 unitialized, MutableBlockVector3 unitialized2) { + getParent().filter(filter, block, region, unitialized, unitialized2); } @Override @@ -98,9 +101,4 @@ public interface IDelegateChunk extends IChunk { } return null; } - - @Override - default void set(final Filter filter) { - getParent().set(filter); - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateFilter.java index 9f8274ef0..c954b91d4 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateFilter.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateFilter.java @@ -1,33 +1,25 @@ package com.boydti.fawe.beta; +import com.sk89q.worldedit.regions.Region; + +import javax.annotation.Nullable; + public interface IDelegateFilter extends Filter { Filter getParent(); @Override - default Filter appliesChunk(int cx, int cz) { - Filter copy = getParent().appliesChunk(cx, cz); - if (copy == null) return null; - if (copy != getParent()) { - return newInstance(copy); - } else { - return this; - } + default boolean appliesChunk(int cx, int cz) { + return getParent().appliesChunk(cx, cz); } @Override - default IChunk applyChunk(IChunk chunk) { - return getParent().applyChunk(chunk); + default IChunk applyChunk(IChunk chunk, @Nullable Region region) { + return getParent().applyChunk(chunk, region); } @Override - default Filter appliesLayer(IChunk chunk, int layer) { - Filter copy = getParent().appliesLayer(chunk, layer); - if (copy == null) return null; - if (copy != getParent()) { - return newInstance(copy); - } else { - return this; - } + default boolean appliesLayer(IChunk chunk, int layer) { + return getParent().appliesLayer(chunk, layer); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/RegionFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/RegionFilter.java deleted file mode 100644 index 791e040d6..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/RegionFilter.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.boydti.fawe.beta; - -import com.sk89q.worldedit.regions.Region; - -public class RegionFilter extends DelegateFilter { - private final Region region; - - public RegionFilter(Filter parent, Region region) { - super(parent); - this.region = region; - } - - @Override - public Filter appliesChunk(int cx, int cz) { - return getParent().appliesChunk(cx, cz); - } - - @Override - public Filter appliesLayer(IChunk chunk, int layer) { - return getParent().appliesLayer(chunk, layer); - } - - @Override - public void applyBlock(FilterBlock block) { - getParent().applyBlock(block); - } - - @Override - public void finishChunk(IChunk chunk) { - getParent().finishChunk(chunk); - } - - @Override - public Filter newInstance(Filter other) { - return new RegionFilter(other, region); - } -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java index 26e7bf898..a7ebe3676 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java @@ -13,6 +13,7 @@ import com.boydti.fawe.util.MemUtil; import com.boydti.fawe.util.TaskManager; import com.boydti.fawe.wrappers.WorldWrapper; import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.World; @@ -155,6 +156,9 @@ public abstract class QueueHandler implements Trimable, Runnable { tasks[i] = forkJoinPoolPrimary.submit(new Runnable() { @Override public void run() { + MutableBlockVector3 mbv1 = new MutableBlockVector3(); + MutableBlockVector3 mbv2 = new MutableBlockVector3(); + final Filter newFilter = filter.fork(); // Create a chunk that we will reuse/reset for each operation final IQueueExtent queue = getQueue(world); @@ -162,7 +166,7 @@ public abstract class QueueHandler implements Trimable, Runnable { FilterBlock block = null; while (true) { - // Get the next chunk pos + // Get the next chunk posWeakChunk final int X, Z; synchronized (chunksIter) { if (!chunksIter.hasNext()) break; @@ -177,12 +181,12 @@ public abstract class QueueHandler implements Trimable, Runnable { // Initialize chunk.init(queue, X, Z); - chunk = newFilter.applyChunk(chunk); + chunk = newFilter.applyChunk(chunk, region); if (chunk == null) continue; if (block == null) block = queue.initFilterBlock(); - chunk.filter(newFilter, block); + chunk.filter(newFilter, block, region, mbv1, mbv2); queue.submit(chunk); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java index 878f3c039..e2284fe51 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java @@ -10,11 +10,14 @@ import com.boydti.fawe.beta.ISetBlocks; import com.boydti.fawe.beta.implementation.SingleThreadQueueExtent; import com.boydti.fawe.beta.implementation.WorldChunkCache; import com.boydti.fawe.util.MathMan; +import com.sk89q.worldedit.math.MutableBlockVector3; +import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; +import javax.annotation.Nullable; import java.util.function.Supplier; /** @@ -36,15 +39,44 @@ public abstract class ChunkHolder implements IChunk, Supplier { } @Override - public void filter(final Filter filter, FilterBlock block) { + public void filter(final Filter filter, FilterBlock block, @Nullable Region region, final MutableBlockVector3 min, final MutableBlockVector3 max) { final IGetBlocks get = getOrCreateGet(); final ISetBlocks set = getOrCreateSet(); - block = block.init(X, Z, get); - for (int layer = 0; layer < 16; layer++) { - if (!get.hasSection(layer) || !filter.appliesLayer(this, layer)) continue; - block.filter(get, set, layer, filter); + try { + if (region != null) { + switch (region.getChunkBounds(X, Z, min, max)) { + case NONE: + System.out.println("NONE"); + return; + case FULL: + if (min.getY() == 0 && max.getY() == 255) { + break; + } + case PARTIAL: + region = null; + case CHECKED: + default: { + int minLayer = min.getY() >> 4; + int maxLayer = max.getY() >> 4; + System.out.println("Layers " + minLayer + " | " + maxLayer); + block = block.init(X, Z, get); + for (int layer = minLayer; layer < maxLayer; layer++) { + if (!get.hasSection(layer) || !filter.appliesLayer(this, layer)) continue; + block.filter(get, set, layer, filter, region, min, max); + } + return; + } + } + } + + block = block.init(X, Z, get); + for (int layer = 0; layer < 16; layer++) { + if (!get.hasSection(layer) || !filter.appliesLayer(this, layer)) continue; + block.filter(get, set, layer, filter, region, null, null); + } + } finally { + filter.finishChunk(this); } - filter.finishChunk(this); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java index 5d6da1301..34a42ec4d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java @@ -41,6 +41,7 @@ import java.util.Set; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.regions.Region.Contains.*; /** * An axis-aligned cuboid. It can be defined using two corners of the cuboid. @@ -627,5 +628,36 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { return new CuboidRegion(origin.subtract(size), origin.add(size)); } + @Override + public Contains getChunkBounds(int X, int Z, MutableBlockVector3 min, MutableBlockVector3 max) { + int minChunkX = minX >> 4; + if (minChunkX <= X) { + int maxChunkX = maxX >> 4; + if (maxChunkX >= X) { + int minChunkZ = minZ >> 4; + if (minChunkZ <= X) { + int maxChunkZ = maxZ >> 4; + if (maxChunkZ >= Z) { + int cx1 = X << 4; + int cx2 = cx1 + 15; + int cz1 = Z << 4; + int cz2 = cz1 + 15; + int bx = Math.max(cx1, minX); + int bz = Math.max(cz1, minZ); + int tx = Math.min(cx2, maxX); + int tz = Math.min(cz2, maxZ); + + min.setComponents(bx & 15, minY, bz & 15); + max.setComponents(tx & 15, maxY, tz & 15); + if (min.getX() == 0 && min.getZ() == 0 && max.getX() == 15 && max.getZ() == 15) { + return FULL; + } + return PARTIAL; + } + } + } + } + return NONE; + } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java index 8c4c75a48..a90bea7a8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.regions; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.world.World; @@ -28,6 +29,9 @@ import javax.annotation.Nullable; import java.util.List; import java.util.Set; +import static com.sk89q.worldedit.regions.Region.Contains.CHECKED; +import static com.sk89q.worldedit.regions.Region.Contains.NONE; + /** * Represents a physical shape. */ @@ -178,4 +182,33 @@ public interface Region extends Iterable, Cloneable { * @return the points. */ List polygonize(int maxPoints); + + default Contains getChunkBounds(int X, int Z, MutableBlockVector3 min, MutableBlockVector3 max) { + BlockVector3 pos1 = getMinimumPoint(); + BlockVector3 pos2 = getMaximumPoint(); + int cx1 = X << 4; + int cx2 = cx1 + 15; + int cz1 = Z << 4; + int cz2 = cz1 + 15; + + int bx = Math.max(cx1, pos1.getX()); + int bz = Math.max(cz1, pos1.getZ()); + int tx = Math.min(cx2, pos2.getX()); + int tz = Math.min(cz2, pos2.getZ()); + + min.setComponents(bx & 15, pos1.getY(), bz & 15); + max.setComponents(tx & 15, pos2.getY(), tz & 15); + + if (bx > cx2 || bz > cz2 || tx < cx1 || tz < cz1) { + return NONE; + } + return CHECKED; + } + + enum Contains { + FULL, + PARTIAL, + CHECKED, + NONE; + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java index 9442deaca..161852248 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java @@ -21,9 +21,14 @@ package com.sk89q.worldedit.regions; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.regions.Region.Contains.CHECKED; +import static com.sk89q.worldedit.regions.Region.Contains.FULL; +import static com.sk89q.worldedit.regions.Region.Contains.NONE; +import static com.sk89q.worldedit.regions.Region.Contains.PARTIAL; import com.google.common.collect.Iterators; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.world.World; import java.util.ArrayList; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/TransformRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/TransformRegion.java deleted file mode 100644 index 911e40b8b..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/TransformRegion.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * 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.regions; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.math.Vector3; -import com.sk89q.worldedit.math.transform.Identity; -import com.sk89q.worldedit.math.transform.Transform; -import com.sk89q.worldedit.world.World; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import javax.annotation.Nullable; - -/** - * Transforms another region according to a provided vector {@code Transform}. - * - * @see Transform - */ -public class TransformRegion extends AbstractRegion { - - private final Region region; - private Transform transform = new Identity(); - - /** - * Create a new instance. - * - * @param region the region - * @param transform the transform - */ - public TransformRegion(Region region, Transform transform) { - this(null, region, transform); - } - - /** - * Create a new instance. - * - * @param world the world, which may be null - * @param region the region - * @param transform the transform - */ - public TransformRegion(@Nullable World world, Region region, Transform transform) { - super(world); - checkNotNull(region); - checkNotNull(transform); - this.region = region; - this.transform = transform; - } - - /** - * Get the untransformed, base region. - * - * @return the base region - */ - public Region getRegion() { - return region; - } - - /** - * Get the transform that is applied. - * - * @return the transform - */ - public Transform getTransform() { - return transform; - } - - /** - * Set the transform that is applied. - * - * @param transform the transform - */ - public void setTransform(Transform transform) { - checkNotNull(transform); - this.transform = transform; - } - - @Override - public BlockVector3 getMinimumPoint() { - return transform.apply(region.getMinimumPoint().toVector3()).toBlockPoint(); - } - - @Override - public BlockVector3 getMaximumPoint() { - return transform.apply(region.getMaximumPoint().toVector3()).toBlockPoint(); - } - - @Override - public Vector3 getCenter() { - return transform.apply(region.getCenter()); - } - - @Override - public int getArea() { - return region.getArea(); // Cannot transform this - } - - @Override - public int getWidth() { - return getMaximumPoint().subtract(getMinimumPoint()).getBlockX() + 1; - } - - @Override - public int getHeight() { - return getMaximumPoint().subtract(getMinimumPoint()).getBlockY() + 1; - } - - @Override - public int getLength() { - return getMaximumPoint().subtract(getMinimumPoint()).getBlockZ() + 1; - } - - @Override - public void expand(BlockVector3... changes) throws RegionOperationException { - throw new RegionOperationException("Can't expand a TransformedRegion"); - } - - @Override - public void contract(BlockVector3... changes) throws RegionOperationException { - throw new RegionOperationException("Can't contract a TransformedRegion"); - } - - @Override - public void shift(BlockVector3 change) throws RegionOperationException { - throw new RegionOperationException("Can't change a TransformedRegion"); - } - - @Override - public boolean contains(BlockVector3 position) { - return region.contains(transform.inverse().apply(position.toVector3()).toBlockPoint()); - } - - @Override - public List polygonize(int maxPoints) { - List origPoints = region.polygonize(maxPoints); - List transformedPoints = new ArrayList<>(); - for (BlockVector2 vector : origPoints) { - transformedPoints.add(transform.apply(vector.toVector3(0)).toVector2().toBlockPoint()); - } - return transformedPoints; - } - - @Override - public Iterator iterator() { - final Iterator it = region.iterator(); - - return new Iterator() { - @Override - public boolean hasNext() { - return it.hasNext(); - } - - @Override - public BlockVector3 next() { - BlockVector3 next = it.next(); - if (next != null) { - return transform.apply(next.toVector3()).toBlockPoint(); - } else { - return null; - } - } - - @Override - public void remove() { - it.remove(); - } - }; - } -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestSelection.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestSelection.java index 9e37e4da0..3766676fd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestSelection.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestSelection.java @@ -23,6 +23,7 @@ import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.regions.NullRegion; import com.sk89q.worldedit.regions.Region; @@ -147,6 +148,11 @@ public class RequestSelection implements Region { return getRegion().polygonize(maxPoints); } + @Override + public Contains getChunkBounds(int X, int Z, MutableBlockVector3 min, MutableBlockVector3 max) { + return getRegion().getChunkBounds(X, Z, min, max); + } + @Override public Iterator iterator() { return getRegion().iterator(); From d603f45063a2cdae754c4bd66001fc14f3b632ba Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Sun, 5 May 2019 22:19:13 +1000 Subject: [PATCH 18/54] remove debug --- .../main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java | 1 - .../boydti/fawe/beta/implementation/holder/ChunkHolder.java | 4 +--- .../main/java/com/boydti/fawe/jnbt/anvil/BitArray4096.java | 1 - .../src/main/java/com/sk89q/worldedit/EditSession.java | 1 - .../main/java/com/sk89q/worldedit/regions/CuboidRegion.java | 2 +- 5 files changed, 2 insertions(+), 7 deletions(-) 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 637c61470..2b863c3c4 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 @@ -168,7 +168,6 @@ public class BukkitPlayer extends AbstractPlayerActor { Extent extent = loc.getExtent(); if (extent instanceof World) { org.bukkit.World world = Bukkit.getWorld(((World) extent).getName()); - // System.out.println("Teleport to world " + world); player.teleport(new Location(world, pos.getX(), pos.getY(), pos.getZ(), yaw, pitch)); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java index e2284fe51..3a8d1d561 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java @@ -46,7 +46,6 @@ public abstract class ChunkHolder implements IChunk, Supplier { if (region != null) { switch (region.getChunkBounds(X, Z, min, max)) { case NONE: - System.out.println("NONE"); return; case FULL: if (min.getY() == 0 && max.getY() == 255) { @@ -58,9 +57,8 @@ public abstract class ChunkHolder implements IChunk, Supplier { default: { int minLayer = min.getY() >> 4; int maxLayer = max.getY() >> 4; - System.out.println("Layers " + minLayer + " | " + maxLayer); block = block.init(X, Z, get); - for (int layer = minLayer; layer < maxLayer; layer++) { + for (int layer = minLayer; layer <= maxLayer; layer++) { if (!get.hasSection(layer) || !filter.appliesLayer(this, layer)) continue; block.filter(get, set, layer, filter, region, min, max); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/BitArray4096.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/BitArray4096.java index 497059c2f..c590f3138 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/BitArray4096.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/BitArray4096.java @@ -14,7 +14,6 @@ public final class BitArray4096 { maxEntryValue = (1 << bitsPerEntry) - 1; this.longLen = (this.bitsPerEntry * 4096) >> 6; if (buffer.length < longLen) { - System.out.println("Invalid buffer " + buffer.length + " | " + longLen); this.data = new long[longLen]; } else { this.data = buffer; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index e1202cf06..880427593 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -2490,7 +2490,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public int makeSphere(final BlockVector3 pos, final Pattern block, double radiusX, double radiusY, double radiusZ, final boolean filled) { - System.out.println("Make sphere"); radiusX += 0.5; radiusY += 0.5; radiusZ += 0.5; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java index 34a42ec4d..913285e52 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java @@ -635,7 +635,7 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { int maxChunkX = maxX >> 4; if (maxChunkX >= X) { int minChunkZ = minZ >> 4; - if (minChunkZ <= X) { + if (minChunkZ <= Z) { int maxChunkZ = maxZ >> 4; if (maxChunkZ >= Z) { int cx1 = X << 4; From 459629a2f2e8e6c7f566dda5834ac7c3081580d2 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Mon, 6 May 2019 15:57:12 +1000 Subject: [PATCH 19/54] scanchunk --- .../beta/implementation/QueueHandler.java | 13 +- .../fawe/object/regions/FuzzyRegion.java | 4 +- .../fawe/object/visitor/AboveVisitor.java | 17 +- .../function/visitor/BreadthFirstSearch.java | 91 ++++------- .../function/visitor/DirectionalVisitor.java | 17 +- .../function/visitor/DownwardVisitor.java | 14 +- .../function/visitor/NonRisingVisitor.java | 15 +- .../worldedit/function/visitor/ScanChunk.java | 151 ++++++++++++++++++ .../worldedit/regions/EllipsoidRegion.java | 10 +- 9 files changed, 231 insertions(+), 101 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/ScanChunk.java diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java index a7ebe3676..a3fbf1c04 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java @@ -181,13 +181,12 @@ public abstract class QueueHandler implements Trimable, Runnable { // Initialize chunk.init(queue, X, Z); - chunk = newFilter.applyChunk(chunk, region); - - if (chunk == null) continue; - - if (block == null) block = queue.initFilterBlock(); - chunk.filter(newFilter, block, region, mbv1, mbv2); - + IChunk newChunk = newFilter.applyChunk(chunk, region); + if (newChunk != null) { + chunk = newChunk; + if (block == null) block = queue.initFilterBlock(); + chunk.filter(newFilter, block, region, mbv1, mbv2); + } queue.submit(chunk); } queue.flush(); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/regions/FuzzyRegion.java b/worldedit-core/src/main/java/com/boydti/fawe/object/regions/FuzzyRegion.java index 3abaa65cf..f7ecfa2b4 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/regions/FuzzyRegion.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/regions/FuzzyRegion.java @@ -19,10 +19,8 @@ public class FuzzyRegion extends AbstractRegion { private final Mask mask; private BlockVectorSet set = new BlockVectorSet(); - private boolean populated; private int minX, minY, minZ, maxX, maxY, maxZ; private Extent extent; - private int count = 0; { minX = minY = minZ = Integer.MAX_VALUE; @@ -59,7 +57,7 @@ public class FuzzyRegion extends AbstractRegion { @Override public Iterator iterator() { - return (Iterator) set.iterator(); + return set.iterator(); } private final void setMinMax(int x, int y, int z) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/visitor/AboveVisitor.java b/worldedit-core/src/main/java/com/boydti/fawe/object/visitor/AboveVisitor.java index 71de953b1..373e71f5d 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/visitor/AboveVisitor.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/visitor/AboveVisitor.java @@ -6,6 +6,7 @@ import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.visitor.RecursiveVisitor; import com.sk89q.worldedit.math.BlockVector3; +import java.util.Arrays; import java.util.Collection; @@ -39,14 +40,14 @@ public class AboveVisitor extends RecursiveVisitor { this.baseY = baseY; - Collection directions = getDirections(); - directions.clear(); - directions.add(BlockVector3.at(1, 0, 0)); - directions.add(BlockVector3.at(-1, 0, 0)); - directions.add(BlockVector3.at(0, 0, 1)); - directions.add(BlockVector3.at(0, 0, -1)); - directions.add(BlockVector3.at(0, 1, 0)); - directions.add(BlockVector3.at(0, -1, 0)); + setDirections( + BlockVector3.at(1, 0, 0), + BlockVector3.at(-1, 0, 0), + BlockVector3.at(0, 0, 1), + BlockVector3.at(0, 0, -1), + BlockVector3.at(0, 1, 0), + BlockVector3.at(0, -1, 0) + ); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java index 859110b77..bbc420a76 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java @@ -23,6 +23,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.HashSet; import java.util.List; import java.util.Queue; import java.util.Set; @@ -73,7 +74,7 @@ public abstract class BreadthFirstSearch implements Operation { } private final RegionFunction function; - private List directions = new ArrayList<>(); + private BlockVector3[] directions; private BlockVectorSet visited; private final MappedFaweQueue mFaweQueue; private BlockVectorSet queue; @@ -96,23 +97,18 @@ public abstract class BreadthFirstSearch implements Operation { this.queue = new BlockVectorSet(); this.visited = new BlockVectorSet(); this.function = function; - this.directions.addAll(Arrays.asList(DEFAULT_DIRECTIONS)); + this.directions = DEFAULT_DIRECTIONS; this.maxDepth = maxDepth; } - public void setDirections(List directions) { + public void setDirections(BlockVector3... directions) { this.directions = directions; } - private IntegerTrio[] getIntDirections() { - IntegerTrio[] array = new IntegerTrio[directions.size()]; - for (int i = 0; i < array.length; i++) { - BlockVector3 dir = directions.get(i); - array[i] = new IntegerTrio(dir.getBlockX(), dir.getBlockY(), dir.getBlockZ()); - } - return array; + public void setDirections(Collection directions) { + setDirections(directions.toArray(new BlockVector3[0])); } - + /** * Get the list of directions will be visited. * @@ -121,34 +117,36 @@ public abstract class BreadthFirstSearch implements Operation { * unit vectors. An example of a valid direction is * {@code BlockVector3.at(1, 0, 1)}.

* - *

The list of directions can be cleared.

- * * @return the list of directions */ - protected Collection getDirections() { - return directions; + public Collection getDirections() { + return Arrays.asList(directions); } /** * Add the directions along the axes as directions to visit. */ - protected void addAxes() { - directions.add(BlockVector3.at(0, -1, 0)); - directions.add(BlockVector3.at(0, 1, 0)); - directions.add(BlockVector3.at(-1, 0, 0)); - directions.add(BlockVector3.at(1, 0, 0)); - directions.add(BlockVector3.at(0, 0, -1)); - directions.add(BlockVector3.at(0, 0, 1)); + public void addAxes() { + HashSet set = new HashSet<>(Arrays.asList(directions)); + set.add(BlockVector3.at(0, -1, 0)); + set.add(BlockVector3.at(0, 1, 0)); + set.add(BlockVector3.at(-1, 0, 0)); + set.add(BlockVector3.at(1, 0, 0)); + set.add(BlockVector3.at(0, 0, -1)); + set.add(BlockVector3.at(0, 0, 1)); + setDirections(set); } /** * Add the diagonal directions as directions to visit. */ - protected void addDiagonal() { - directions.add(BlockVector3.at(1, 0, 1)); - directions.add(BlockVector3.at(-1, 0, -1)); - directions.add(BlockVector3.at(1, 0, -1)); - directions.add(BlockVector3.at(-1, 0, 1)); + public void addDiagonal() { + HashSet set = new HashSet<>(Arrays.asList(directions)); + set.add(BlockVector3.at(1, 0, 1)); + set.add(BlockVector3.at(-1, 0, -1)); + set.add(BlockVector3.at(1, 0, -1)); + set.add(BlockVector3.at(-1, 0, 1)); + setDirections(set); } public void visit(final BlockVector3 pos) { @@ -159,12 +157,6 @@ public abstract class BreadthFirstSearch implements Operation { } } - public void resetVisited() { - queue.clear(); - visited.clear(); - affected = 0; - } - public void setVisited(BlockVectorSet set) { this.visited = set; } @@ -180,21 +172,6 @@ public abstract class BreadthFirstSearch implements Operation { public void setMaxBranch(int maxBranch) { this.maxBranch = maxBranch; } - /** - * Try to visit the given 'to' location. - * - * @param from the origin block - * @param to the block under question - */ - private void visit(BlockVector3 from, BlockVector3 to) { - BlockVector3 blockVector = to; - if (!visited.contains(blockVector)) { - visited.add(blockVector); - if (isVisitable(from, to)) { - queue.add(blockVector); - } - } - } /** * Return whether the given 'to' block should be visited, starting from the @@ -220,7 +197,7 @@ public abstract class BreadthFirstSearch implements Operation { MutableBlockVector3 mutable = new MutableBlockVector3(); // MutableBlockVector3 mutable2 = new MutableBlockVector3(); boolean shouldTrim = false; - IntegerTrio[] dirs = getIntDirections(); + BlockVector3[] dirs = directions; BlockVectorSet tempQueue = new BlockVectorSet(); BlockVectorSet chunkLoadSet = new BlockVectorSet(); for (currentDepth = 0; !queue.isEmpty() && currentDepth <= maxDepth; currentDepth++) { @@ -228,11 +205,11 @@ public abstract class BreadthFirstSearch implements Operation { int cx = Integer.MIN_VALUE; int cz = Integer.MIN_VALUE; for (BlockVector3 from : queue) { - for (IntegerTrio direction : dirs) { - int x = from.getBlockX() + direction.x; - int z = from.getBlockZ() + direction.z; + for (BlockVector3 direction : dirs) { + int x = from.getBlockX() + direction.getX(); + int z = from.getBlockZ() + direction.getZ(); if (cx != (cx = x >> 4) || cz != (cz = z >> 4)) { - int y = from.getBlockY() + direction.y; + int y = from.getBlockY() + direction.getY(); if (y < 0 || y >= 256) { continue; } @@ -249,13 +226,13 @@ public abstract class BreadthFirstSearch implements Operation { for (BlockVector3 from : queue) { if (function.apply(from)) affected++; for (int i = 0, j = 0; i < dirs.length && j < maxBranch; i++) { - IntegerTrio direction = dirs[i]; - int y = from.getBlockY() + direction.y; + BlockVector3 direction = dirs[i]; + int y = from.getBlockY() + direction.getY(); if (y < 0 || y >= 256) { continue; } - int x = from.getBlockX() + direction.x; - int z = from.getBlockZ() + direction.z; + int x = from.getBlockX() + direction.getX(); + int z = from.getBlockZ() + direction.getZ(); if (!visited.contains(x, y, z)) { if (isVisitable(from, BlockVector3.at(x, y, z))) { j++; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DirectionalVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DirectionalVisitor.java index 8a9542e32..9a0b8c912 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DirectionalVisitor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DirectionalVisitor.java @@ -51,14 +51,15 @@ public class DirectionalVisitor extends RecursiveVisitor { checkNotNull(mask); this.origin = origin; this.dirVec = direction; - final Collection directions = this.getDirections(); - directions.clear(); - directions.add(BlockVector3.at(1, 0, 0)); - directions.add(BlockVector3.at(-1, 0, 0)); - directions.add(BlockVector3.at(0, 0, 1)); - directions.add(BlockVector3.at(0, 0, -1)); - directions.add(BlockVector3.at(0, -1, 0)); - directions.add(BlockVector3.at(0, 1, 0)); + + setDirections( + BlockVector3.at(1, 0, 0), + BlockVector3.at(-1, 0, 0), + BlockVector3.at(0, 0, 1), + BlockVector3.at(0, 0, -1), + BlockVector3.at(0, -1, 0), + BlockVector3.at(0, 1, 0) + ); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java index a3a8dac66..e2c4f667a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java @@ -60,13 +60,13 @@ public class DownwardVisitor extends RecursiveVisitor { checkNotNull(mask); this.baseY = baseY; - Collection directions = getDirections(); - directions.clear(); - directions.add(BlockVector3.at(1, 0, 0)); - directions.add(BlockVector3.at(-1, 0, 0)); - directions.add(BlockVector3.at(0, 0, 1)); - directions.add(BlockVector3.at(0, 0, -1)); - directions.add(BlockVector3.at(0, -1, 0)); + setDirections( + BlockVector3.at(1, 0, 0), + BlockVector3.at(-1, 0, 0), + BlockVector3.at(0, 0, 1), + BlockVector3.at(0, 0, -1), + BlockVector3.at(0, -1, 0) + ); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java index 7e79e57a7..5a67fa950 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java @@ -46,13 +46,14 @@ public class NonRisingVisitor extends RecursiveVisitor { public NonRisingVisitor(Mask mask, RegionFunction function, int depth, HasFaweQueue hasFaweQueue) { super(mask, function, depth, hasFaweQueue); - Collection directions = getDirections(); - directions.clear(); - directions.add(BlockVector3.at(1, 0, 0)); - directions.add(BlockVector3.at(-1, 0, 0)); - directions.add(BlockVector3.at(0, 0, 1)); - directions.add(BlockVector3.at(0, 0, -1)); - directions.add(BlockVector3.at(0, -1, 0)); + + setDirections( + BlockVector3.at(1, 0, 0), + BlockVector3.at(-1, 0, 0), + BlockVector3.at(0, 0, 1), + BlockVector3.at(0, 0, -1), + BlockVector3.at(0, -1, 0) + ); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/ScanChunk.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/ScanChunk.java new file mode 100644 index 000000000..cfef60a74 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/ScanChunk.java @@ -0,0 +1,151 @@ +package com.sk89q.worldedit.function.visitor; + +import com.boydti.fawe.example.MappedFaweQueue; +import com.boydti.fawe.object.FaweQueue; +import com.boydti.fawe.object.HasFaweQueue; +import com.boydti.fawe.object.collection.BlockVectorSet; +import com.boydti.fawe.util.MathMan; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.math.BlockVector3; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.longs.LongArraySet; +import it.unimi.dsi.fastutil.longs.LongSet; +import it.unimi.dsi.fastutil.objects.ObjectIterator; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +/** + * A chunk based search algorithm + */ +public class ScanChunk { + private static final int MAX_QUEUE = 34816; + public static final BlockVector3[] DEFAULT_DIRECTIONS = new BlockVector3[6]; + public static final BlockVector3[] DIAGONAL_DIRECTIONS; + + static { + DEFAULT_DIRECTIONS[0] = (BlockVector3.at(0, -1, 0)); + DEFAULT_DIRECTIONS[1] = (BlockVector3.at(0, 1, 0)); + DEFAULT_DIRECTIONS[2] = (BlockVector3.at(-1, 0, 0)); + DEFAULT_DIRECTIONS[3] = (BlockVector3.at(1, 0, 0)); + DEFAULT_DIRECTIONS[4] = (BlockVector3.at(0, 0, -1)); + DEFAULT_DIRECTIONS[5] = (BlockVector3.at(0, 0, 1)); + List list = new ArrayList<>(); + for (int x = -1; x <= 1; x++) { + for (int y = -1; y <= 1; y++) { + for (int z = -1; z <= 1; z++) { + if (x != 0 || y != 0 || z != 0) { + BlockVector3 pos = BlockVector3.at(x, y, z); + if (!list.contains(pos)) { + list.add(pos); + } + } + } + } + } + Collections.sort(list, new Comparator() { + @Override + public int compare(BlockVector3 o1, BlockVector3 o2) { + return (int) Math.signum(o1.lengthSq() - o2.lengthSq()); + } + }); + DIAGONAL_DIRECTIONS = list.toArray(new BlockVector3[list.size()]); + } + + private final RegionFunction function; + private final BlockVector3[] directions; + private final Long2ObjectOpenHashMap visited; + private final Long2ObjectOpenHashMap queues; + + public ScanChunk(final RegionFunction function) { + this.function = function; + this.directions = DEFAULT_DIRECTIONS; + + this.queues = new Long2ObjectOpenHashMap<>(); + this.visited = new Long2ObjectOpenHashMap<>(); + } + + public static final long pairInt(int x, int y) { + return (((long) x) << 32) | (y & 0xffffffffL); + } + + public boolean isVisited(int x, int y, int z) { + int X = x >> 4; + int Z = z >> 4; + long pair = pairInt(X, Z); + long[][] chunk = visited.get(pair); + if (chunk == null) return false; + int layer = y >> 4; + long[] section = chunk[layer]; + if (section == null) return false; + return get(section, getLocalIndex(x & 15, y & 15, z & 15)); + } + + public void start(int x, int y, int z) { + if (!isVisited(x, y, z)) { + queue(x, y, z); + visit(x, y, z); + } + } + + public void visit(int x, int y, int z) { + int X = x >> 4; + int Z = z >> 4; + long pair = pairInt(X, Z); + long[][] chunk = visited.get(pair); + if (chunk == null) { + visited.put(pair, chunk = new long[16][]); + } + int layer = y >> 4; + long[] section = chunk[layer]; + if (section == null) { + chunk[layer] = section = new long[64]; + } + set(section, getLocalIndex(x & 15, y & 15, z & 15)); + } + + public void queue(int x, int y, int z) { + int X = x >> 4; + int Z = z >> 4; + long pair = pairInt(X, Z); + char[] queue = queues.get(pair); + if (queue == null) { + queue = queues.put(pair, queue = new char[MAX_QUEUE + 2]); + queue[0] = 2; + queue[1] = 2; + } + if (queue[1] >= queue.length) { + queue[1] = 2; + } + queue[queue[1]++] = getLocalIndex(x & 15, y, z & 15); + } + + public void process() { + LongArraySet set = new LongArraySet(); + while (!queues.isEmpty()) { + ObjectIterator> iter = queues.long2ObjectEntrySet().fastIterator(); + Long2ObjectMap.Entry entry = iter.next(); + long index = entry.getLongKey(); + int X = MathMan.unpairIntX(index); + int Z = MathMan.unpairIntY(index); + } + } + + public void set(long[] bits, int i) { + bits[i >> 6] |= (1L << (i & 0x3F)); + } + + public boolean get(long[] bits, final int i) { + return (bits[i >> 6] & (1L << (i & 0x3F))) != 0; + } + + public char getLocalIndex(int x, int y, int z) { + return (char) (y + (x << 8) + (z << 12)); + } + + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java index 9cef04a0e..0c0be6781 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java @@ -44,6 +44,7 @@ public class EllipsoidRegion extends AbstractRegion { */ private Vector3 radius; private Vector3 radiusSqr; + private Vector3 inverseRadius; private int radiusLengthSqr; private boolean sphere; @@ -136,7 +137,7 @@ public class EllipsoidRegion extends AbstractRegion { public void contract(BlockVector3... changes) throws RegionOperationException { center = center.subtract(calculateDiff(changes)); Vector3 newRadius = radius.subtract(calculateChanges(changes)); - radius = Vector3.at(1.5, 1.5, 1.5).getMaximum(newRadius); + setRadius(Vector3.at(1.5, 1.5, 1.5).getMaximum(newRadius)); } @Override @@ -187,6 +188,7 @@ public class EllipsoidRegion extends AbstractRegion { } else { this.sphere = false; } + inverseRadius = Vector3.ONE.divide(radius); } @Override @@ -233,9 +235,9 @@ public class EllipsoidRegion extends AbstractRegion { if (sphere) { return cx2 + cy2 + cz2 <= radiusLengthSqr; } - double cxd = (double) cx / radius.getBlockX(); - double cyd = (double) cy / radius.getBlockY(); - double czd = (double) cz / radius.getBlockZ(); + double cxd = cx * inverseRadius.getX(); + double cyd = cy * inverseRadius.getY(); + double czd = cz * inverseRadius.getZ(); return cxd * cxd + cyd * cyd + czd * czd <= 1; } From c797dcb194a385c47fedf7379f7c4cf2bec07bae Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Sun, 12 May 2019 23:32:04 +1000 Subject: [PATCH 20/54] WIP filter patterns --- .../fawe/bukkit/beta/BukkitChunkHolder.java | 9 +- .../boydti/fawe/bukkit/beta/BukkitQueue.java | 2 + .../com/sk89q/worldedit/blocks/LazyBlock.java | 94 ------- .../boydti/fawe/beta/ArrayFilterBlock.java | 88 ++++++ .../com/boydti/fawe/beta/CharFilterBlock.java | 260 ++++++++++++------ .../boydti/fawe/beta/ChunkFilterBlock.java | 19 ++ .../com/boydti/fawe/beta/DelegateFilter.java | 3 - .../com/boydti/fawe/beta/DirectionMask.java | 5 + .../com/boydti/fawe/beta/FilterBlock.java | 82 ++++-- .../com/boydti/fawe/beta/FilterBlockMask.java | 5 + .../main/java/com/boydti/fawe/beta/Flood.java | 192 +++++++++++++ .../java/com/boydti/fawe/beta/IChunk.java | 5 +- .../beta/{IGetBlocks.java => IChunkGet.java} | 6 +- .../beta/{ISetBlocks.java => IChunkSet.java} | 5 +- .../com/boydti/fawe/beta/IDelegateChunk.java | 5 + .../com/boydti/fawe/beta/IDelegateFilter.java | 6 +- .../com/boydti/fawe/beta/IQueueExtent.java | 22 +- .../boydti/fawe/beta/SimpleFilterBlock.java | 70 +++++ .../fawe/beta/filters/ArrayImageMask.java | 26 ++ .../beta/implementation/QueueHandler.java | 3 +- .../implementation/SimpleCharQueueExtent.java | 4 +- .../beta/implementation/WorldChunkCache.java | 20 +- .../implementation/blocks/CharGetBlocks.java | 4 +- .../implementation/blocks/CharSetBlocks.java | 4 +- .../implementation/holder/ChunkHolder.java | 32 ++- .../implementation/holder/DelegateChunk.java | 3 + .../jnbt/anvil/HeightMapMCAGenerator.java | 20 +- .../com/boydti/fawe/object/FaweQueue.java | 2 +- .../fawe/object/brush/SurfaceSpline.java | 3 +- .../brush/visualization/VirtualWorld.java | 7 +- .../object/collection/BlockVectorSet.java | 2 +- .../object/collection/DifferentialArray.java | 6 +- .../DifferentialCharBlockBuffer.java | 213 ++++++++++++++ .../collection/LocalBlockVectorSet.java | 2 +- .../object/pattern/AngleColorPattern.java | 36 ++- .../pattern/RandomFullClipboardPattern.java | 6 +- .../object/queue/FaweQueueDelegateExtent.java | 12 - .../boydti/fawe/util/EditSessionBuilder.java | 231 +++++++++++++++- .../com/boydti/fawe/util/TextureUtil.java | 2 +- .../boydti/fawe/wrappers/WorldWrapper.java | 5 - .../java/com/sk89q/worldedit/EditSession.java | 98 +++---- .../worldedit/command/tool/AreaPickaxe.java | 2 +- .../command/tool/brush/GravityBrush.java | 2 +- .../event/extent/EditSessionEvent.java | 13 +- .../extent/AbstractDelegateExtent.java | 240 +++++----------- .../com/sk89q/worldedit/extent/Extent.java | 52 +--- .../sk89q/worldedit/extent/InputExtent.java | 48 ++-- .../sk89q/worldedit/extent/OutputExtent.java | 18 +- .../worldedit/extent/PassthroughExtent.java | 177 ++++++++++++ .../sk89q/worldedit/function/mask/Mask.java | 3 + .../function/pattern/FawePattern.java | 26 +- .../worldedit/function/pattern/Pattern.java | 20 +- .../worldedit/function/visitor/ScanChunk.java | 255 ++++++++++++++--- .../sk89q/worldedit/math/BlockVector3.java | 201 ++++++-------- .../sk89q/worldedit/math/BlockVector3Imp.java | 87 ++++++ .../worldedit/math/MutableBlockVector3.java | 31 ++- .../sk89q/worldedit/world/AbstractWorld.java | 5 - .../worldedit/world/block/BaseBlock.java | 21 +- .../worldedit/world/block/BlockState.java | 10 +- .../worldedit/world/block/BlockType.java | 10 +- .../world/block/ImmutableBaseBlock.java | 28 ++ 61 files changed, 2075 insertions(+), 793 deletions(-) delete mode 100644 worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/LazyBlock.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/ArrayFilterBlock.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFilterBlock.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/DirectionMask.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlockMask.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/Flood.java rename worldedit-core/src/main/java/com/boydti/fawe/beta/{IGetBlocks.java => IChunkGet.java} (77%) rename worldedit-core/src/main/java/com/boydti/fawe/beta/{ISetBlocks.java => IChunkSet.java} (84%) create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/SimpleFilterBlock.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/filters/ArrayImageMask.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialCharBlockBuffer.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/PassthroughExtent.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3Imp.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/world/block/ImmutableBaseBlock.java diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java index 7739a66b7..605f18d8b 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java @@ -1,10 +1,9 @@ package com.boydti.fawe.bukkit.beta; import com.boydti.fawe.Fawe; -import com.boydti.fawe.beta.Filter; -import com.boydti.fawe.beta.IGetBlocks; +import com.boydti.fawe.beta.IChunkGet; import com.boydti.fawe.beta.IQueueExtent; -import com.boydti.fawe.beta.ISetBlocks; +import com.boydti.fawe.beta.IChunkSet; import com.boydti.fawe.beta.implementation.QueueHandler; import com.boydti.fawe.beta.implementation.holder.ChunkHolder; import com.boydti.fawe.bukkit.v0.BukkitQueue_0; @@ -49,7 +48,7 @@ public class BukkitChunkHolder> extends ChunkHolder { } @Override - public IGetBlocks get() { + public IChunkGet get() { BukkitQueue extent = (BukkitQueue) getExtent(); return new BukkitGetBlocks(extent.getNmsWorld(), getX(), getZ()); } @@ -78,7 +77,7 @@ public class BukkitChunkHolder> extends ChunkHolder { int Z = getZ(); BukkitQueue extent = (BukkitQueue) getExtent(); BukkitGetBlocks get = (BukkitGetBlocks) getOrCreateGet(); - ISetBlocks set = getOrCreateSet(); + IChunkSet set = getOrCreateSet(); Chunk nmsChunk = extent.ensureLoaded(X, Z); diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java index debf5283c..3d34e3cb9 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java @@ -13,7 +13,9 @@ import com.boydti.fawe.object.collection.IterableThreadLocal; import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.TaskManager; import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockID; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; diff --git a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/LazyBlock.java b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/LazyBlock.java deleted file mode 100644 index d87e7c571..000000000 --- a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/LazyBlock.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.blocks; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.math.BlockVector3; - -/** - * A implementation of a lazy block for {@link Extent#getLazyBlock(Vector)} - * that takes the block's ID and metadata, but will defer loading of NBT - * data until time of access. - * - *

NBT data is later loaded using a call to {@link Extent#getBlock(Vector)} - * with a stored {@link Extent} and location.

- * - *

All mutators on this object will throw an - * {@link UnsupportedOperationException}.

- */ -public class LazyBlock extends BaseBlock { - - private final Extent extent; - private final BlockVector3 position; - private boolean loaded = false; - - /** - * Create a new lazy block. - * - * @param type the block type - * @param extent the extent to later load the full block data from - * @param position the position to later load the full block data from - */ - public LazyBlock(BlockType type, Extent extent, BlockVector3 position) { - super(type); - checkNotNull(extent); - checkNotNull(position); - this.extent = extent; - this.position = position; - } - - /** - * Create a new lazy block. - * - * @param state the block state - * @param extent the extent to later load the full block data from - * @param position the position to later load the full block data from - */ - public LazyBlock(BlockState state, Extent extent, BlockVector3 position) { - super(state); - checkNotNull(extent); - checkNotNull(position); - this.extent = extent; - this.position = position; - } - - @Override - public CompoundTag getNbtData() { - if (!loaded) { - BaseBlock loadedBlock = extent.getFullBlock(position); - this.nbtData = loadedBlock.getNbtData(); - loaded = true; - } - return super.getNbtData(); - } - - @Override - public void setNbtData(CompoundTag nbtData) { - throw new UnsupportedOperationException("This object is immutable"); - } - -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/ArrayFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/ArrayFilterBlock.java new file mode 100644 index 000000000..c005b82f8 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/ArrayFilterBlock.java @@ -0,0 +1,88 @@ +package com.boydti.fawe.beta; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.awt.image.BufferedImage; +import java.util.concurrent.ThreadLocalRandom; + +public class ArrayFilterBlock extends SimpleFilterBlock { + private final char[] blocks; + private final byte[] heights; + private final int yOffset; + private int x, z, index; + private char ordinal; + private final int width, length; + + public ArrayFilterBlock(Extent extent, char[] blocks, byte[] heights, int width, int length, int yOffset) { + super(extent); + this.blocks = blocks; + this.width = width; + this.length = length; + this.heights = heights; + this.yOffset = yOffset; + } + + public void filter2D(Filter filter) { + for (z = 0; z < length; z++) { + for (x = 0; x < width; x++, index++) { + ordinal = blocks[ordinal]; + filter.applyBlock(this); + } + } + } + + @Override + public void setOrdinal(int ordinal) { + blocks[index] = (char) ordinal; + } + + @Override + public void setState(BlockState state) { + blocks[index] = state.getOrdinalChar(); + } + + @Override + public void setFullBlock(BaseBlock block) { + blocks[index] = block.getOrdinalChar(); + } + + @Override + public int getOrdinal() { + return ordinal; + } + + @Override + public BlockState getState() { + return BlockTypes.states[ordinal]; + } + + @Override + public BaseBlock getBaseBlock() { + return getState().toBaseBlock(); + } + + @Override + public CompoundTag getTag() { + return null; + } + + @Override + public int getX() { + return x; + } + + @Override + public int getY() { + return (heights[index] & 0xFF) + yOffset; + } + + @Override + public int getZ() { + return z; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java index 42a90e24c..6fcfbea45 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java @@ -4,6 +4,7 @@ import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; @@ -12,11 +13,10 @@ import com.sk89q.worldedit.world.registry.BlockMaterial; import javax.annotation.Nullable; import static com.sk89q.worldedit.world.block.BlockTypes.states; -public class CharFilterBlock implements FilterBlock { - private IQueueExtent queue; +public class CharFilterBlock extends ChunkFilterBlock { private CharGetBlocks get; - private ISetBlocks set; + private IChunkSet set; private char[] getArr; private @Nullable char[] setArr; @@ -25,14 +25,12 @@ public class CharFilterBlock implements FilterBlock { // local private int layer, index, x, y, z, xx, yy, zz, X, Z; - @Override - public final FilterBlock init(final IQueueExtent queue) { - this.queue = queue; - return this; + public CharFilterBlock(IQueueExtent queueExtent) { + super(queueExtent); } @Override - public final FilterBlock init(final int X, final int Z, final IGetBlocks chunk) { + public final ChunkFilterBlock init(final int X, final int Z, final IChunkGet chunk) { this.get = (CharGetBlocks) chunk; this.X = X; this.Z = Z; @@ -41,11 +39,32 @@ public class CharFilterBlock implements FilterBlock { return this; } - @Override - public final void filter(final IGetBlocks iget, final ISetBlocks iset, final int layer, final Filter filter, final @Nullable Region region, BlockVector3 min, BlockVector3 max) { + public void flood(final IChunkGet iget, final IChunkSet iset, final int layer, Flood flood, FilterBlockMask mask) { + final int maxDepth = flood.getMaxDepth(); + final boolean checkDepth = maxDepth < Character.MAX_VALUE; + if (init(iget, iset, layer)) { + while ((index = flood.poll()) != -1) { + x = index & 15; + z = (index >> 4) & 15; + y = (index >> 8) & 15; + + if (mask.applyBlock(this)) { + int depth = index >> 12; + + if (checkDepth && depth > maxDepth) { + continue; + } + + flood.apply(x, y, z, depth); + } + } + } + } + + private final boolean init(final IChunkGet iget, final IChunkSet iset, final int layer) { this.layer = layer; final CharGetBlocks get = (CharGetBlocks) iget; - if (!get.hasSection(layer)) return; + if (!get.hasSection(layer)) return false; this.set = iset; getArr = get.sections[layer].get(get, layer); if (set.hasSection(layer)) { @@ -56,17 +75,24 @@ public class CharFilterBlock implements FilterBlock { setArr = null; } this.yy = layer << 4; - if (region == null) { - if (min != null && max != null) { - iterate(min, max, layer, filter); + return true; + } + + @Override + public final void filter(final IChunkGet iget, final IChunkSet iset, final int layer, final Filter filter, final @Nullable Region region, BlockVector3 min, BlockVector3 max) { + if (init(iget, iset, layer)) { + if (region == null) { + if (min != null && max != null) { + iterate(min, max, layer, filter); + } else { + iterate(filter); + } } else { - iterate(filter); - } - } else { - if (min != null && max != null) { - iterate(region, min, max, layer, filter); - } else { - iterate(region, filter); + if (min != null && max != null) { + iterate(region, min, max, layer, filter); + } else { + iterate(region, filter); + } } } } @@ -227,7 +253,7 @@ public class CharFilterBlock implements FilterBlock { @Override public final CompoundTag getTag() { - return null; + return get.getTag(x, y + (layer << 4), z); } public final BlockState getOrdinalBelow() { @@ -310,71 +336,135 @@ public class CharFilterBlock implements FilterBlock { public final BlockState getStateRelative(final int x, final int y, final int z) { final int newX = this.x + x; - if (newX >> 4 == 0) { - final int newZ = this.z + z; - if (newZ >> 4 == 0) { - final int newY = this.y + y; - final int layerAdd = newY >> 4; - switch (layerAdd) { - case 0: - return states[getArr[this.index + ((y << 8) + (z << 4) + x)]]; - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: { - final int newLayer = layer + layerAdd; - if (newLayer < 16) { - final int index = ((newY & 15) << 8) + (newZ << 4) + newX; - return states[get.sections[newLayer].get(get, newLayer, index)]; - } - break; - } - case -1: - case -2: - case -3: - case -4: - case -5: - case -6: - case -7: - case -8: - case -9: - case -10: - case -11: - case -12: - case -13: - case -14: - case -15: { - final int newLayer = layer + layerAdd; - if (newLayer >= 0) { - final int index = ((newY & 15) << 8) + (newZ << 4) + newX; - return states[get.sections[newLayer].get(get, newLayer, index)]; - } - break; + final int newZ = this.z + z; + if (newX >> 4 == 0 && newZ >> 4 == 0) { + final int newY = this.y + y; + final int layerAdd = newY >> 4; + switch (layerAdd) { + case 0: + return states[getArr[this.index + ((y << 8) + (z << 4) + x)]]; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: { + final int newLayer = layer + layerAdd; + if (newLayer < 16) { + final int index = ((newY & 15) << 8) + (newZ << 4) + newX; + return states[get.sections[newLayer].get(get, newLayer, index)]; } + break; + } + case -1: + case -2: + case -3: + case -4: + case -5: + case -6: + case -7: + case -8: + case -9: + case -10: + case -11: + case -12: + case -13: + case -14: + case -15: { + final int newLayer = layer + layerAdd; + if (newLayer >= 0) { + final int index = ((newY & 15) << 8) + (newZ << 4) + newX; + return states[get.sections[newLayer].get(get, newLayer, index)]; + } + break; } - return BlockTypes.__RESERVED__.getDefaultState(); } + return BlockTypes.__RESERVED__.getDefaultState(); } -// queue.get - // TODO return normal get block final int newY = this.y + y + yy; if (newY >= 0 && newY <= 256) { - return queue.getBlock(xx + newX, newY, this.zz + this.z + z); + return getExtent().getBlock(xx + newX, newY, this.zz + newZ); } return BlockTypes.__RESERVED__.getDefaultState(); } + public final BaseBlock getFullBlockRelative(final int x, final int y, final int z) { + final int newX = this.x + x; + final int newZ = this.z + z; + if (newX >> 4 == 0 && newZ >> 4 == 0) { + final int newY = this.y + y; + final int layerAdd = newY >> 4; + BlockState state = BlockTypes.__RESERVED__.getDefaultState(); + switch (layerAdd) { + case 0: + state = states[getArr[this.index + ((y << 8) + (z << 4) + x)]]; + break; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: { + final int newLayer = layer + layerAdd; + if (newLayer < 16) { + final int index = ((newY & 15) << 8) + (newZ << 4) + newX; + state = states[get.sections[newLayer].get(get, newLayer, index)]; + } + break; + } + case -1: + case -2: + case -3: + case -4: + case -5: + case -6: + case -7: + case -8: + case -9: + case -10: + case -11: + case -12: + case -13: + case -14: + case -15: { + final int newLayer = layer + layerAdd; + if (newLayer >= 0) { + final int index = ((newY & 15) << 8) + (newZ << 4) + newX; + state = states[get.sections[newLayer].get(get, newLayer, index)]; + } + break; + } + } + if (state.getMaterial().hasContainer()) { + final CompoundTag tag = get.getTag(x, y + (layer << 4), z); + return state.toBaseBlock(tag); + } + } + final int newY = this.y + y + yy; + if (newY >= 0 && newY <= 256) { + return getExtent().getFullBlock(xx + newX, newY, this.zz + newZ); + } + return BlockTypes.__RESERVED__.getDefaultState().toBaseBlock(); + } + /* Set delegate */ @@ -383,6 +473,22 @@ public class CharFilterBlock implements FilterBlock { return delegate = FULL; } + @Override + public BiomeType getBiome(int x, int z) { + if ((x >> 4) == X && (z >> 4) == Z) { + return get.getBiome(x & 15, z & 15); + } + return getExtent().getBiome(x, z); + } + + @Override + public boolean setBiome(int x, int y, int z, BiomeType biome) { + if ((x >> 4) == X && (z >> 4) == Z) { + return set.setBiome(x & 15, z & 15, biome); + } + return getExtent().setBiome(x, y, z, biome); + } + private interface SetDelegate { void set(CharFilterBlock block, char value); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFilterBlock.java new file mode 100644 index 000000000..59560279b --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFilterBlock.java @@ -0,0 +1,19 @@ +package com.boydti.fawe.beta; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; + +import javax.annotation.Nullable; + +public abstract class ChunkFilterBlock extends FilterBlock { + public ChunkFilterBlock(Extent extent) { + super(extent); + } + + public abstract ChunkFilterBlock init(int X, int Z, IChunkGet chunk); + + public abstract void flood(final IChunkGet iget, final IChunkSet iset, final int layer, Flood flood, FilterBlockMask mask); + + public abstract void filter(IChunkGet get, IChunkSet set, int layer, Filter filter, @Nullable Region region, BlockVector3 min, BlockVector3 max); +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilter.java index eb941c5a9..5bc48aa80 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilter.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilter.java @@ -10,7 +10,4 @@ public abstract class DelegateFilter implements IDelegateFilter { public Filter getParent() { return parent; } - - @Override - public abstract Filter fork(); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/DirectionMask.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/DirectionMask.java new file mode 100644 index 000000000..4efce15ec --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/DirectionMask.java @@ -0,0 +1,5 @@ +package com.boydti.fawe.beta; + +public interface DirectionMask { + boolean apply(int fromX, int fromY, int fromZ, int toX, int toY, int toZ); +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java index 96a06562e..007b25a6d 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java @@ -1,6 +1,7 @@ package com.boydti.fawe.beta; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.block.BaseBlock; @@ -8,64 +9,97 @@ import com.sk89q.worldedit.world.block.BlockState; import javax.annotation.Nullable; -public interface FilterBlock { - FilterBlock init(IQueueExtent queue); +public abstract class FilterBlock extends BlockVector3 implements Extent { + private final Extent extent; - FilterBlock init(int X, int Z, IGetBlocks chunk); + public FilterBlock(Extent extent) { + this.extent = extent; + } - void filter(IGetBlocks get, ISetBlocks set, int layer, Filter filter, @Nullable Region region, BlockVector3 min, BlockVector3 max); + public final Extent getExtent() { + return extent; + } - void setOrdinal(int ordinal); + public abstract void setOrdinal(int ordinal); - void setState(BlockState state); + public abstract void setState(BlockState state); - void setFullBlock(BaseBlock block); + public abstract void setFullBlock(BaseBlock block); - int getOrdinal(); + public abstract int getOrdinal(); - BlockState getState(); + public abstract BlockState getState(); - BaseBlock getBaseBlock(); + public abstract BaseBlock getBaseBlock(); - CompoundTag getTag(); + public abstract CompoundTag getTag(); - default BlockState getOrdinalBelow() { + @Override + public BlockVector3 getMinimumPoint() { + return getExtent().getMinimumPoint(); + } + + @Override + public BlockVector3 getMaximumPoint() { + return getExtent().getMaximumPoint(); + } + + @Override + public BlockState getBlock(int x, int y, int z) { + return getStateRelative(x - getX(), y - getY(), z - getZ()); + } + + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + return getFullBlockRelative(x - getX(), y - getY(), z - getZ()); + } + + public BlockState getOrdinalBelow() { return getStateRelative(0, -1, 0); } - default BlockState getStateAbove() { + public BlockState getStateAbove() { return getStateRelative(0, 1, 0); } - default BlockState getStateRelativeY(final int y) { + public BlockState getStateRelativeY(final int y) { return getStateRelative(0, y, 0); } - int getX(); + public BlockState getStateRelative(final int x, final int y, final int z) { + return getFullBlockRelative(x, y, z).toBlockState(); + } - int getY(); + public BaseBlock getFullBlockRelative(int x, int y, int z) { + return getExtent().getFullBlock(x + getX(), y + getY(), z + getZ()); + } - int getZ(); + @Override + public abstract int getX(); - default int getLocalX() { + @Override + public abstract int getY(); + + @Override + public abstract int getZ(); + + public int getLocalX() { return getX() & 15; } - default int getLocalY() { + public int getLocalY() { return getY() & 15; } - default int getLocalZ() { + public int getLocalZ() { return getZ() & 15; } - default int getChunkX() { + public int getChunkX() { return getX() >> 4; } - default int getChunkZ() { + public int getChunkZ() { return getZ() >> 4; } - - BlockState getStateRelative(final int x, final int y, final int z); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlockMask.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlockMask.java new file mode 100644 index 000000000..e7728435c --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlockMask.java @@ -0,0 +1,5 @@ +package com.boydti.fawe.beta; + +public interface FilterBlockMask { + boolean applyBlock(final FilterBlock block); +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/Flood.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/Flood.java new file mode 100644 index 000000000..bfc567181 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/Flood.java @@ -0,0 +1,192 @@ +package com.boydti.fawe.beta; + +import com.boydti.fawe.Fawe; +import com.boydti.fawe.beta.implementation.QueueHandler; +import com.boydti.fawe.beta.implementation.WorldChunkCache; +import com.boydti.fawe.util.MathMan; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.world.World; +import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; + +import java.util.concurrent.ConcurrentLinkedQueue; + +public class Flood { + private final int maxBranch; + private final int maxDepth; + private final Direction[] directions; + + private int[] queue; + private long[] visit; + + private int[][] queues; + private long[][] visits; + + private int X, Y, Z; + + private ConcurrentLinkedQueue queuePool = new ConcurrentLinkedQueue<>(); + private final Long2ObjectLinkedOpenHashMap chunkVisits; + private final Long2ObjectLinkedOpenHashMap chunkQueues; + + public Flood(int maxBranch, int maxDepth, Direction[] directions) { + this.maxBranch = maxBranch; + this.maxDepth = maxDepth; + this.directions = directions; + + this.queues = new int[27][]; + this.visits = new long[27][]; + + this.chunkVisits = new Long2ObjectLinkedOpenHashMap<>(); + this.chunkQueues = new Long2ObjectLinkedOpenHashMap<>(); + } + + public synchronized void run(World world) { + QueueHandler queueHandler = Fawe.get().getQueueHandler(); + IQueueExtent fq = queueHandler.getQueue(world); + while (!chunkQueues.isEmpty()) { + long firstKey = chunkQueues.firstLongKey(); + int X = MathMan.unpairIntX(firstKey); + int Z = MathMan.unpairIntY(firstKey); + int[][] chunkQueue = chunkQueues.get(firstKey); + // apply + } + } + + private void init(int X, int Y, int Z) { + this.X = X; + this.Y = Y; + this.Z = Z; + } + + public void start(int x, int y, int z) { + push(x, y, z, 0); + } + + private void push(int x, int y, int z, int depth) { + int X = x >> 4; + int Z = z >> 4; + long pair = MathMan.pairInt(X, Z); + int layer = y >> 4; + int[] section = getOrCreateQueue(pair, layer); + int val = (x & 15) + ((z & 15) << 4) + ((y & 15) << 8) + (depth << 12); + push(section, val); + } + + private int[] getOrCreateQueue(long pair, int layer) { + int[][] arrs = chunkQueues.get(pair); + if (arrs == null) { + chunkQueues.put(pair, arrs = new int[16][]); + } + int[] section = arrs[layer]; + if (section == null) { + arrs[layer] = section = newQueue(); + } + return section; + } + + private int[] newQueue() { + int[] arr = queuePool.poll(); + if (arr != null) { + arr[0] = 2; + arr[1] = 2; + return arr; + } + return new int[4096]; + } + + public int poll() { + int index = queue[0]; + if (index == queue[1]) { + return -1; + } + queue[0] = index + 1; + return queue[index]; + } + + private void push(int[] queue, int val) { + int indexStart = queue[0]; + int indexEnd = queue[1]; + push(indexStart, indexEnd, queue, val); + } + + private void push(int indexStart, int indexEnd, int[] queue, int val) { + if (indexStart > 2) { + queue[0] = --indexStart; + queue[indexStart] = val; + } else { + queue[indexEnd] = val; + queue[0] = ++indexEnd; + } + } + + public Direction[] getDirections() { + return directions; + } + + public int getMaxBranch() { + return maxBranch; + } + + public int getMaxDepth() { + return maxDepth; + } + + public void apply(int x, int y, int z, int depth) { + for (int i = 0, j = 0; i < directions.length && j < maxBranch; i++) { + final Direction dir = directions[i]; + final int ty = y + dir.getBlockY(); + final int tx = x + dir.getBlockX(); + final int tz = z + dir.getBlockZ(); + + int index; + long[] visit; + int[] queue; + final int or = tx | ty | tz; + if (or > 15 || or < 0) { + visit = this.visit; + queue = this.queue; + index = tx + (tz << 4) + (ty << 8); + } else { + int nextX = tx >> 4; + int nextY = ty >> 4; + int nextZ = tz >> 4; + int sectionIndex = nextX + nextZ * 3 + nextZ * 9 + 13; + visit = visits[sectionIndex]; + queue = queues[sectionIndex]; + if (visit == null || queue == null) { + long pair = MathMan.pairInt(X + nextX, Z + nextZ); + int layer = Y + nextY; + if (layer < 0 || layer > 15) { + continue; + } + queues[sectionIndex] = queue = getOrCreateQueue(pair, layer); + } + index = (tx & 15) + ((tz & 15) << 4) + ((ty & 15) << 8); + } + if (!getAndSet(visit, index)) { + j++; + push(queue, index + (depth << 12)); + } + } + } + + public void set(long[] bits, int i) { + bits[i >> 6] |= (1L << (i & 0x3F)); + } + + public final boolean getAndSet(long[] bits, int i) { + int index = i >> 6; + long offset = (1L << (i & 0x3F)); + long val = bits[index]; + if ((val & offset) != 0) { + return true; + } else { + bits[index] |= offset; + return false; + } + } + + public boolean get(long[] bits, final int i) { + return (bits[i >> 6] & (1L << (i & 0x3F))) != 0; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java index dbc45d124..bdc17bb47 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java @@ -11,7 +11,6 @@ import javax.annotation.Nullable; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; -import java.util.function.Supplier; /** * Represents a chunk in the queue {@link IQueueExtent} @@ -72,7 +71,9 @@ public interface IChunk> extends Trimable, Callable { * @param unitialized a mutable block vector (buffer) * @param unitialized2 a mutable block vector (buffer) */ - void filter(Filter filter, FilterBlock block, @Nullable Region region, MutableBlockVector3 unitialized, MutableBlockVector3 unitialized2); + void filter(Filter filter, ChunkFilterBlock block, @Nullable Region region, MutableBlockVector3 unitialized, MutableBlockVector3 unitialized2); + + void flood(Flood flood, FilterBlockMask mask, ChunkFilterBlock block); /* set - queues a change */ boolean setBiome(int x, int y, int z, BiomeType biome); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IGetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkGet.java similarity index 77% rename from worldedit-core/src/main/java/com/boydti/fawe/beta/IGetBlocks.java rename to worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkGet.java index b865e1f91..62ec359a9 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IGetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkGet.java @@ -1,6 +1,7 @@ package com.boydti.fawe.beta; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.InputExtent; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -8,11 +9,14 @@ import com.sk89q.worldedit.world.block.BlockState; /** * Interface for getting blocks */ -public interface IGetBlocks extends IBlocks, Trimable { +public interface IChunkGet extends IBlocks, Trimable, InputExtent { + @Override BaseBlock getFullBlock(int x, int y, int z); + @Override BiomeType getBiome(int x, int z); + @Override BlockState getBlock(int x, int y, int z); CompoundTag getTag(int x, int y, int z); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkSet.java similarity index 84% rename from worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java rename to worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkSet.java index 7ba1f664a..138efc6be 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkSet.java @@ -1,6 +1,7 @@ package com.boydti.fawe.beta; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.OutputExtent; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -14,8 +15,8 @@ import java.util.UUID; /** * Interface for setting blocks */ -public interface ISetBlocks extends IBlocks { - boolean setBiome(int x, int y, int z, BiomeType biome); +public interface IChunkSet extends IBlocks, OutputExtent { + boolean setBiome(int x, int z, BiomeType biome); boolean setBlock(int x, int y, int z, BlockStateHolder holder); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java index 0a21e1c1a..9a5f4add1 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java @@ -26,6 +26,11 @@ public interface IDelegateChunk extends IChunk { return root; } + @Override + default void flood(Flood flood, FilterBlockMask mask, FilterBlock block) { + getParent().flood(flood, mask, block); + } + @Override default boolean setBiome(final int x, final int y, final int z, final BiomeType biome) { return getParent().setBiome(x, y, z, biome); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateFilter.java index c954b91d4..e85587e59 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateFilter.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateFilter.java @@ -39,7 +39,11 @@ public interface IDelegateFilter extends Filter { @Override default Filter fork() { - return newInstance(getParent().fork()); + Filter fork = getParent().fork(); + if (fork != getParent()) { + return newInstance(fork); + } + return this; } Filter newInstance(Filter other); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java index a19e7ea8c..633dad3a8 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java @@ -1,7 +1,10 @@ package com.boydti.fawe.beta; import com.boydti.fawe.beta.implementation.WorldChunkCache; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -12,7 +15,7 @@ import java.util.concurrent.Future; * TODO: implement Extent (need to refactor Extent first) * Interface for a queue based extent which uses chunks */ -public interface IQueueExtent extends Flushable, Trimable { +public interface IQueueExtent extends Flushable, Trimable, Extent { void init(WorldChunkCache world); /** @@ -51,11 +54,26 @@ public interface IQueueExtent extends Flushable, Trimable { return chunk.getBlock(x & 15, y, z & 15); } + @Override + default BaseBlock getFullBlock(int x, int y, int z) { + final IChunk chunk = getCachedChunk(x >> 4, z >> 4); + return chunk.getFullBlock(x & 15, y, z & 15); + } + default BiomeType getBiome(final int x, final int z) { final IChunk chunk = getCachedChunk(x >> 4, z >> 4); return chunk.getBiome(x & 15, z & 15); } + @Override + default BlockVector3 getMinimumPoint() { + return getCache().getWorld().getMinimumPoint(); + } + + @Override + default BlockVector3 getMaximumPoint() { + return getCache().getWorld().getMaximumPoint(); + } /** * Create a new root IChunk object
* - Full chunks will be reused, so a more optimized chunk can be returned in that case
@@ -81,5 +99,5 @@ public interface IQueueExtent extends Flushable, Trimable { @Override void flush(); - FilterBlock initFilterBlock(); + ChunkFilterBlock initFilterBlock(); } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/SimpleFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/SimpleFilterBlock.java new file mode 100644 index 000000000..34da51861 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/SimpleFilterBlock.java @@ -0,0 +1,70 @@ +package com.boydti.fawe.beta; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; + +import javax.annotation.Nullable; + +public abstract class SimpleFilterBlock extends FilterBlock { + public SimpleFilterBlock(Extent extent) { + super(extent); + } + + private int x, y, z, ordinal; + private CompoundTag nbt; + + public void init(int x, int y, int z, int ordinal) { + this.x = x; + this.y = y; + this.z = z; + this.ordinal = ordinal; + } + + public void init(int x, int y, int z, int ordinal, CompoundTag nbt) { + this.x = x; + this.y = y; + this.z = z; + this.ordinal = ordinal; + this.nbt = nbt; + } + + @Override + public int getOrdinal() { + return ordinal; + } + + @Override + public BlockState getState() { + return BlockTypes.states[ordinal]; + } + + @Override + public BaseBlock getBaseBlock() { + return getState().toBaseBlock(nbt); + } + + @Override + public CompoundTag getTag() { + return nbt; + } + + @Override + public int getX() { + return x; + } + + @Override + public int getY() { + return y; + } + + @Override + public int getZ() { + return z; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/ArrayImageMask.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/ArrayImageMask.java new file mode 100644 index 000000000..41ceed910 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/ArrayImageMask.java @@ -0,0 +1,26 @@ +package com.boydti.fawe.beta.filters; + +import com.boydti.fawe.beta.DelegateFilter; +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.FilterBlock; +import com.boydti.fawe.beta.FilterBlockMask; + +import java.awt.image.BufferedImage; +import java.util.concurrent.ThreadLocalRandom; + +public class ArrayImageMask implements FilterBlockMask { + private final ThreadLocalRandom r; + private final boolean white; + private final BufferedImage img; + + public ArrayImageMask(BufferedImage img, boolean white) { + this.img = img; + this.white = white; + this.r = ThreadLocalRandom.current(); + } + @Override + public boolean applyBlock(FilterBlock block) { + int height = img.getRGB(block.getX(), block.getZ()) & 0xFF; + return ((height == 255 || height > 0 && !white && r.nextInt(256) <= height)); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java index a3fbf1c04..666ededbf 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java @@ -2,6 +2,7 @@ package com.boydti.fawe.beta.implementation; import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.ChunkFilterBlock; import com.boydti.fawe.beta.Filter; import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.beta.IChunk; @@ -163,7 +164,7 @@ public abstract class QueueHandler implements Trimable, Runnable { // Create a chunk that we will reuse/reset for each operation final IQueueExtent queue = getQueue(world); synchronized (queue) { - FilterBlock block = null; + ChunkFilterBlock block = null; while (true) { // Get the next chunk posWeakChunk diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java index af1bce4b1..80ce0d560 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java @@ -6,8 +6,6 @@ import com.boydti.fawe.beta.FilterBlock; public abstract class SimpleCharQueueExtent extends SingleThreadQueueExtent { @Override public FilterBlock initFilterBlock() { - FilterBlock filter = new CharFilterBlock(); - filter = filter.init(this); - return filter; + return new CharFilterBlock(this); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/WorldChunkCache.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/WorldChunkCache.java index 9e5d4461f..243bc23c5 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/WorldChunkCache.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/WorldChunkCache.java @@ -1,6 +1,6 @@ package com.boydti.fawe.beta.implementation; -import com.boydti.fawe.beta.IGetBlocks; +import com.boydti.fawe.beta.IChunkGet; import com.boydti.fawe.beta.Trimable; import com.sk89q.worldedit.world.World; import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; @@ -15,7 +15,7 @@ import java.util.function.Supplier; * - avoids conversion between palette and raw data on every block get */ public class WorldChunkCache implements Trimable { - protected final Long2ObjectLinkedOpenHashMap> getCache; + protected final Long2ObjectLinkedOpenHashMap> getCache; private final World world; protected WorldChunkCache(final World world) { @@ -37,13 +37,13 @@ public class WorldChunkCache implements Trimable { * @param provider used to create if it isn't already cached * @return cached IGetBlocks */ - public synchronized IGetBlocks get(final long index, final Supplier provider) { - final WeakReference ref = getCache.get(index); + public synchronized IChunkGet get(final long index, final Supplier provider) { + final WeakReference ref = getCache.get(index); if (ref != null) { - final IGetBlocks blocks = ref.get(); + final IChunkGet blocks = ref.get(); if (blocks != null) return blocks; } - final IGetBlocks blocks = provider.get(); + final IChunkGet blocks = provider.get(); getCache.put(index, new WeakReference<>(blocks)); return blocks; } @@ -52,11 +52,11 @@ public class WorldChunkCache implements Trimable { public synchronized boolean trim(final boolean aggressive) { boolean result = true; if (!getCache.isEmpty()) { - final ObjectIterator>> iter = getCache.long2ObjectEntrySet().fastIterator(); + final ObjectIterator>> iter = getCache.long2ObjectEntrySet().fastIterator(); while (iter.hasNext()) { - final Long2ObjectMap.Entry> entry = iter.next(); - final WeakReference value = entry.getValue(); - final IGetBlocks igb = value.get(); + final Long2ObjectMap.Entry> entry = iter.next(); + final WeakReference value = entry.getValue(); + final IChunkGet igb = value.get(); if (igb == null) iter.remove(); else { result = false; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java index 5c92c09aa..467d78ee8 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java @@ -1,11 +1,11 @@ package com.boydti.fawe.beta.implementation.blocks; -import com.boydti.fawe.beta.IGetBlocks; +import com.boydti.fawe.beta.IChunkGet; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; -public abstract class CharGetBlocks extends CharBlocks implements IGetBlocks { +public abstract class CharGetBlocks extends CharBlocks implements IChunkGet { @Override public BaseBlock getFullBlock(final int x, final int y, final int z) { return BlockTypes.states[get(x, y, z)].toBaseBlock(); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java index f132fe2da..883fe34a9 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java @@ -1,6 +1,6 @@ package com.boydti.fawe.beta.implementation.blocks; -import com.boydti.fawe.beta.ISetBlocks; +import com.boydti.fawe.beta.IChunkSet; import com.boydti.fawe.util.MathMan; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.world.biome.BiomeType; @@ -14,7 +14,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; -public class CharSetBlocks extends CharBlocks implements ISetBlocks { +public class CharSetBlocks extends CharBlocks implements IChunkSet { public BiomeType[] biomes; public HashMap tiles; public HashSet entities; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java index 3a8d1d561..dbf456a72 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java @@ -1,12 +1,15 @@ package com.boydti.fawe.beta.implementation.holder; +import com.boydti.fawe.beta.ChunkFilterBlock; import com.boydti.fawe.beta.Filter; import com.boydti.fawe.beta.FilterBlock; +import com.boydti.fawe.beta.FilterBlockMask; +import com.boydti.fawe.beta.Flood; import com.boydti.fawe.beta.IQueueExtent; import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks; import com.boydti.fawe.beta.IChunk; -import com.boydti.fawe.beta.IGetBlocks; -import com.boydti.fawe.beta.ISetBlocks; +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IChunkSet; import com.boydti.fawe.beta.implementation.SingleThreadQueueExtent; import com.boydti.fawe.beta.implementation.WorldChunkCache; import com.boydti.fawe.util.MathMan; @@ -23,9 +26,9 @@ import java.util.function.Supplier; /** * Abstract IChunk class that implements basic get/set blocks */ -public abstract class ChunkHolder implements IChunk, Supplier { - private IGetBlocks get; - private ISetBlocks set; +public abstract class ChunkHolder implements IChunk, Supplier { + private IChunkGet get; + private IChunkSet set; private IBlockDelegate delegate; private IQueueExtent extent; private int X,Z; @@ -39,9 +42,14 @@ public abstract class ChunkHolder implements IChunk, Supplier { } @Override - public void filter(final Filter filter, FilterBlock block, @Nullable Region region, final MutableBlockVector3 min, final MutableBlockVector3 max) { - final IGetBlocks get = getOrCreateGet(); - final ISetBlocks set = getOrCreateSet(); + public void flood(Flood flood, FilterBlockMask mask, ChunkFilterBlock block) { +// block.flood(get, set, mask, block, ); + } + + @Override + public void filter(final Filter filter, ChunkFilterBlock block, @Nullable Region region, @Nullable final MutableBlockVector3 min, @Nullable final MutableBlockVector3 max) { + final IChunkGet get = getOrCreateGet(); + final IChunkSet set = getOrCreateSet(); try { if (region != null) { switch (region.getChunkBounds(X, Z, min, max)) { @@ -106,21 +114,21 @@ public abstract class ChunkHolder implements IChunk, Supplier { return set == null || set.isEmpty(); } - public final IGetBlocks getOrCreateGet() { + public final IChunkGet getOrCreateGet() { if (get == null) get = newGet(); return get; } - public final ISetBlocks getOrCreateSet() { + public final IChunkSet getOrCreateSet() { if (set == null) set = set(); return set; } - public ISetBlocks set() { + public IChunkSet set() { return new CharSetBlocks(); } - private IGetBlocks newGet() { + private IChunkGet newGet() { if (extent instanceof SingleThreadQueueExtent) { final WorldChunkCache cache = ((SingleThreadQueueExtent) extent).getCache(); return cache.get(MathMan.pairInt(X, Z), this); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java index a41e8357e..91e28814f 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java @@ -1,5 +1,8 @@ package com.boydti.fawe.beta.implementation.holder; +import com.boydti.fawe.beta.FilterBlock; +import com.boydti.fawe.beta.FilterBlockMask; +import com.boydti.fawe.beta.Flood; import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.IDelegateChunk; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java index 5cce020b4..6debbbe3c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java @@ -2,6 +2,12 @@ package com.boydti.fawe.jnbt.anvil; import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.ArrayFilterBlock; +import com.boydti.fawe.beta.DelegateFilter; +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.FilterBlock; +import com.boydti.fawe.beta.SimpleFilterBlock; +import com.boydti.fawe.beta.filters.ArrayImageMask; import com.boydti.fawe.example.SimpleIntFaweChunk; import com.boydti.fawe.jnbt.anvil.HeightMapMCADrawer; import com.boydti.fawe.jnbt.anvil.MCAChunk; @@ -1022,7 +1028,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr @Override public BlockState getBlock(BlockVector3 position) { - return getLazyBlock(position); + return getBlock(position.getX(), position.getY(), position.getZ()); } public BlockState getFloor(int x, int z) { @@ -1045,12 +1051,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr } @Override - public BlockState getLazyBlock(BlockVector3 position) { - return getLazyBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ()); - } - - @Override - public BlockState getLazyBlock(int x, int y, int z) { + public BlockState getBlock(int x, int y, int z) { return BlockState.getFromInternalId(getCombinedId4Data(x, y, z)); } @@ -1340,6 +1341,11 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr } } + public void test() { +// ArrayImageMask mask = new ArrayImageMask(img, white); +// filter = new ArrayFilterBlock(this, overlayArr, heights.get(), getWidth(), getLength(), 1); + } + public void setOverlay(BufferedImage img, Pattern pattern, boolean white) { if (pattern instanceof BlockStateHolder) { setOverlay(img, ((BlockStateHolder) pattern).getInternalId(), white); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/FaweQueue.java b/worldedit-core/src/main/java/com/boydti/fawe/object/FaweQueue.java index 4e56a4977..484cd90e2 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/FaweQueue.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/FaweQueue.java @@ -72,7 +72,7 @@ public interface FaweQueue extends HasFaweQueue, Extent { } @Override - default BlockState getLazyBlock(int x, int y, int z) { + default BlockState getBlock(int x, int y, int z) { int combinedId4Data = getCachedCombinedId4Data(x, y, z, BlockTypes.AIR.getInternalId()); try { BlockState state = BlockState.getFromInternalId(combinedId4Data); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/SurfaceSpline.java b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/SurfaceSpline.java index 3e6ea0c6b..d6c1c37f5 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/SurfaceSpline.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/SurfaceSpline.java @@ -50,6 +50,7 @@ public class SurfaceSpline implements Brush { n.setContinuity(continuity); nodes.add(n); } + MutableBlockVector3 mutable = MutableBlockVector3.at(0, 0, 0); interpol.setNodes(nodes); final double splinelength = interpol.arcLength(0, 1); for (double loop = 0; loop <= 1; loop += 1D / splinelength / quality) { @@ -60,7 +61,7 @@ public class SurfaceSpline implements Brush { tipy = editSession.getNearestSurfaceTerrainBlock(tipx, tipz, tipy, 0, maxY); if (tipy == -1) continue; if (radius == 0) { - BlockVector3 set = MutableBlockVector3.get(tipx, tipy, tipz); + BlockVector3 set = mutable.setComponents(tipx, tipy, tipz); try { pattern.apply(editSession, set, set); } catch (WorldEditException e) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/VirtualWorld.java b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/VirtualWorld.java index 4eb958fcb..4a2009b58 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/VirtualWorld.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/VirtualWorld.java @@ -24,7 +24,12 @@ public interface VirtualWorld extends SimpleWorld, FaweQueue, Closeable { @Override default BaseBlock getFullBlock(BlockVector3 position) { - return getLazyBlock(position).toBaseBlock(); + return getBlock(position).toBaseBlock(); + } + + @Override + default BaseBlock getFullBlock(int x, int y, int z) { + return getBlock(x, y, z).toBaseBlock(); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BlockVectorSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BlockVectorSet.java index a16f43a9d..2c32bb2a2 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BlockVectorSet.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BlockVectorSet.java @@ -43,7 +43,7 @@ public class BlockVectorSet extends AbstractCollection implements int newSize = count + size; if (newSize > index) { int localIndex = index - count; - MutableBlockVector3 pos = new MutableBlockVector3(set.getIndex(localIndex)); + BlockVector3 pos = set.getIndex(localIndex); if (pos != null) { int pair = entry.getIntKey(); int cx = MathMan.unpairX(pair); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialArray.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialArray.java index a8c399721..9141e7d6d 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialArray.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialArray.java @@ -244,9 +244,9 @@ public final class DifferentialArray implements DifferentialCollection { return dataBytes; } -// public char[] getCharArray() { -// return dataChars; -// } + public char[] getCharArray() { + return dataChars; + } public int[] getIntArray() { return dataInts; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialCharBlockBuffer.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialCharBlockBuffer.java new file mode 100644 index 000000000..15a52d950 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialCharBlockBuffer.java @@ -0,0 +1,213 @@ +package com.boydti.fawe.object.collection; + +import com.boydti.fawe.object.FaweInputStream; +import com.boydti.fawe.object.FaweOutputStream; + +import java.io.IOException; +import java.lang.reflect.Array; + +/** + * Records changes made through the {@link #set(int, int, int, char)} method
+ * Changes are not recorded if you edit the raw data + */ +public final class DifferentialCharBlockBuffer implements DifferentialCollection { + + private final int width, length; + private final int t1, t2; + private char[][][][][] data; + private char[][][][][] changes; + + public DifferentialCharBlockBuffer(int width, int length) { + this.width = width; + this.length = length; + this.t1 = (length + 15) >> 4; + this.t2 = (width + 15) >> 4; + } + + @Override + public char[][][][][] get() { + return data; + } + + @Override + public void flushChanges(FaweOutputStream out) throws IOException { + boolean modified = isModified(); + out.writeBoolean(modified); + + if (modified) { + writeArray(changes, 0, 0, out); + } + clearChanges(); + } + + private void writeArray(Object arr, int level, int index, FaweOutputStream out) throws IOException { + if (level == 4) { + if (arr != null) { + char[] level4 = (char[]) arr; + out.writeVarInt(level4.length); + for (char c : level4) { + out.writeChar(c); + } + } else { + out.writeVarInt(0); + } + } else { + int len = arr == null ? 0 : Array.getLength(arr); + out.writeVarInt(len); + for (int i = 0; i < len; i++) { + Object elem = Array.get(arr, i); + writeArray(elem, level + 1, i, out); + } + } + } + + @Override + public void undoChanges(FaweInputStream in) throws IOException { + if (changes != null && changes.length != 0) throw new IllegalStateException("There are uncommitted changes, please flush first"); + boolean modified = in.readBoolean(); + if (modified) { + int len = in.readVarInt(); + if (len == 0) { + data = null; + } else { + for (int i = 0; i < len; i++) { + readArray(data, i, 1, in); + } + } + } + + clearChanges(); + } + + @Override + public void redoChanges(FaweInputStream in) throws IOException { + clearChanges(); + throw new UnsupportedOperationException("Not implemented"); + } + + private void readArray(Object dataElem, int index, int level, FaweInputStream in) throws IOException { + int len = in.readVarInt(); + if (level == 4) { + char[][] castedElem = (char[][]) dataElem; + if (len == 0) { + castedElem[index] = null; + } else { + char[] current = castedElem[index]; + for (int i = 0; i < len; i++) { + current[i] = in.readChar(); + } + } + } else { + if (len == 0) { + Array.set(dataElem, index, null); + } else { + Object nextElem = Array.get(dataElem, index); + for (int i = 0; i < len; i++) { + readArray(nextElem, i, level + 1, in); + } + } + } + } + + public boolean isModified() { + return changes != null; + } + + public void clearChanges() { + changes = null; + } + + public void set(int x, int y, int z, char combined) { + if (combined == 0) combined = 1; + int localX = x & 15; + int localZ = z & 15; + int chunkX = x >> 4; + int chunkZ = z >> 4; + if (data == null) { + data = new char[t1][][][][]; + changes = new char[0][][][][]; + } + + char[][][][] arr = data[chunkZ]; + if (arr == null) { + arr = data[chunkZ] = new char[t2][][][]; + } + char[][][] arr2 = arr[chunkX]; + if (arr2 == null) { + arr2 = arr[chunkX] = new char[256][][]; + } + + char[][] yMap = arr2[y]; + if (yMap == null) { + arr2[y] = yMap = new char[16][]; + } + boolean newSection; + char current; + char[] zMap = yMap[localZ]; + if (zMap == null) { + yMap[localZ] = zMap = new char[16]; + + if (changes == null) { + changes = new char[t1][][][][]; + } else if (changes != null && changes.length != 0) { + initialChange(changes, chunkX, chunkZ, localX, localZ, y, (char) -combined); + } + + } else { + if (changes == null || changes.length == 0) changes = new char[t1][][][][]; + appendChange(changes, chunkX, chunkZ, localX, localZ, y, (char) (zMap[localX] - combined)); + } + + zMap[localX] = combined; + } + + private void initialChange(char[][][][][] src, int chunkX, int chunkZ, int localX, int localZ, int y, char combined) { + char[][][][] arr = src[chunkZ]; + if (arr == null) { + src[chunkZ] = new char[0][][][]; + return; + } else if (arr.length == 0) return; + + char[][][] arr2 = arr[chunkX]; + if (arr2 == null) { + arr[chunkX] = new char[0][][]; + return; + } else if (arr2.length == 0) return; + + char[][] yMap = arr2[y]; + if (yMap == null) { + arr2[y] = new char[0][]; + return; + } else if (yMap.length == 0) return; + + char[] zMap = yMap[localZ]; + if (zMap == null) { + yMap[localZ] = new char[0]; + return; + } else if (zMap.length == 0) return; + + char current = zMap[localX]; + zMap[localX] = combined; + } + + private void appendChange(char[][][][][] src, int chunkX, int chunkZ, int localX, int localZ, int y, char combined) { + char[][][][] arr = src[chunkZ]; + if (arr == null || arr.length == 0) { + arr = src[chunkZ] = new char[t2][][][]; + } + char[][][] arr2 = arr[chunkX]; + if (arr2 == null || arr2.length == 0) { + arr2 = arr[chunkX] = new char[256][][]; + } + + char[][] yMap = arr2[y]; + if (yMap == null || yMap.length == 0) { + arr2[y] = yMap = new char[16][]; + } + char[] zMap = yMap[localZ]; + if (zMap == null || zMap.length == 0) { + yMap[localZ] = zMap = new char[16]; + } + zMap[localX] = combined; + } +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVectorSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVectorSet.java index 863de2781..14b532bba 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVectorSet.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVectorSet.java @@ -100,7 +100,7 @@ public class LocalBlockVectorSet implements Set { this.offsetZ = z; } - public BlockVector3 getIndex(int getIndex) { + protected BlockVector3 getIndex(int getIndex) { int size = size(); if (getIndex > size) { return null; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AngleColorPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AngleColorPattern.java index f11fc4896..64e3ee009 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AngleColorPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AngleColorPattern.java @@ -2,8 +2,10 @@ package com.boydti.fawe.object.pattern; import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.object.DataAnglePattern; import com.boydti.fawe.util.TextureHolder; +import com.boydti.fawe.util.TextureUtil; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -15,11 +17,11 @@ import com.sk89q.worldedit.world.block.BlockType; import java.io.IOException; public class AngleColorPattern extends DataAnglePattern { - protected transient TextureHolder util; + protected transient TextureUtil util; - public AngleColorPattern(Extent extent, TextureHolder util, int distance) { + public AngleColorPattern(Extent extent, TextureHolder holder, int distance) { super(extent, distance); - this.util = util; + this.util = holder.getTextureUtil(); } public int getColor(int color, int slope) { @@ -31,15 +33,28 @@ public class AngleColorPattern extends DataAnglePattern { return (((color >> 24) & 0xFF) << 24) + (newRed << 16) + (newGreen << 8) + (newBlue << 0); } + @Override + public void apply(FilterBlock block) { + BlockState state = block.getState(); + int slope = getSlope(state, block); + if (slope == -1) return; + int color = util.getColor(state.getBlockType()); + if (color == 0) return; + int newColor = getColor(color, slope); + BlockType newBlock = util.getNearestBlock(newColor); + if (newBlock == null) return; + newBlock.apply(block); + } + @Override public BaseBlock apply(BlockVector3 position) { BaseBlock block = extent.getFullBlock(position); int slope = getSlope(block, position); if (slope == -1) return block; - int color = util.getTextureUtil().getColor(block.getBlockType()); + int color = util.getColor(block.getBlockType()); if (color == 0) return block; int newColor = getColor(color, slope); - return util.getTextureUtil().getNearestBlock(newColor).getDefaultState().toBaseBlock(); + return util.getNearestBlock(newColor).getDefaultState().toBaseBlock(); } @Override @@ -51,7 +66,7 @@ public class AngleColorPattern extends DataAnglePattern { int z = vector.getBlockZ(); int height = extent.getNearestSurfaceTerrainBlock(x, z, y, 0, maxY); if (height > 0) { - BlockStateHolder below = extent.getLazyBlock(x, height - 1, z); + BlockStateHolder below = extent.getBlock(x, height - 1, z); if (!below.getBlockType().getMaterial().isMovementBlocker()) { return Integer.MAX_VALUE; } @@ -65,16 +80,11 @@ public class AngleColorPattern extends DataAnglePattern { BlockStateHolder block = extent.getBlock(getPosition); int slope = getSlope(block, getPosition); if (slope == -1) return false; - int color = util.getTextureUtil().getColor(block.getBlockType()); + int color = util.getColor(block.getBlockType()); if (color == 0) return false; int newColor = getColor(color, slope); - BlockType newBlock = util.getTextureUtil().getNearestBlock(newColor); + BlockType newBlock = util.getNearestBlock(newColor); if (newBlock == null) return false; return extent.setBlock(setPosition, newBlock.getDefaultState()); } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - util = Fawe.get().getCachedTextureUtil(true, 0, 100); - } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomFullClipboardPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomFullClipboardPattern.java index 36c3eb08c..82863af97 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomFullClipboardPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomFullClipboardPattern.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.object.PseudoRandom; import com.boydti.fawe.object.schematic.Schematic; import com.sk89q.worldedit.WorldEditException; @@ -25,14 +26,15 @@ public class RandomFullClipboardPattern extends AbstractPattern { private final Extent extent; private final MutableBlockVector3 mutable = new MutableBlockVector3(); private final List clipboards; - private boolean randomRotate; - private boolean randomFlip; + private final boolean randomRotate; + private final boolean randomFlip; public RandomFullClipboardPattern(Extent extent, List clipboards, boolean randomRotate, boolean randomFlip) { checkNotNull(clipboards); this.clipboards = clipboards; this.extent = extent; this.randomRotate = randomRotate; + this.randomFlip = randomFlip; } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/queue/FaweQueueDelegateExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/queue/FaweQueueDelegateExtent.java index 0eed3a025..f2f67ab60 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/queue/FaweQueueDelegateExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/queue/FaweQueueDelegateExtent.java @@ -86,16 +86,4 @@ public class FaweQueueDelegateExtent extends DelegateFaweQueue { public boolean setBlock(int x, int y, int z, BlockStateHolder block) throws WorldEditException { return parentExtent.setBlock(x, y, z, block); } - - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return parentExtent.getLazyBlock(position); - } - - @Override - public BlockState getLazyBlock(int x, int y, int z) { - return parentExtent.getLazyBlock(x, y, z); - } - - } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java b/worldedit-core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java index b6e3de434..81e11ddc5 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java @@ -2,14 +2,36 @@ package com.boydti.fawe.util; import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweAPI; +import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.Settings; +import com.boydti.fawe.jnbt.anvil.MCAQueue; +import com.boydti.fawe.jnbt.anvil.MCAWorld; +import com.boydti.fawe.logging.LoggingChangeSet; import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory; import com.boydti.fawe.object.*; +import com.boydti.fawe.object.brush.visualization.VirtualWorld; +import com.boydti.fawe.object.changeset.BlockBagChangeSet; +import com.boydti.fawe.object.changeset.CPUOptimizedChangeSet; import com.boydti.fawe.object.changeset.DiskStorageHistory; import com.boydti.fawe.object.changeset.FaweChangeSet; import com.boydti.fawe.object.changeset.MemoryOptimizedHistory; +import com.boydti.fawe.object.exception.FaweException; +import com.boydti.fawe.object.extent.FastWorldEditExtent; +import com.boydti.fawe.object.extent.HeightBoundExtent; +import com.boydti.fawe.object.extent.MultiRegionExtent; +import com.boydti.fawe.object.extent.NullExtent; +import com.boydti.fawe.object.extent.ProcessedWEExtent; +import com.boydti.fawe.object.extent.SingleRegionExtent; +import com.boydti.fawe.object.extent.SlowExtent; +import com.boydti.fawe.object.extent.StripNBTExtent; +import com.boydti.fawe.object.progress.ChatProgressTracker; +import com.boydti.fawe.object.progress.DefaultProgressTracker; +import com.boydti.fawe.wrappers.WorldWrapper; import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.event.extent.EditSessionEvent; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.eventbus.EventBus; @@ -190,7 +212,214 @@ public class EditSessionBuilder { return this; } + private boolean wrapped; + + private AbstractDelegateExtent wrapExtent(final AbstractDelegateExtent extent, final EventBus eventBus, EditSessionEvent event, final EditSession.Stage stage) { + event = event.clone(stage); + event.setExtent(extent); + eventBus.post(event); + if (event.isCancelled()) { + return new NullExtent(extent, BBC.WORLDEDIT_CANCEL_REASON_MANUAL); + } + final Extent toReturn = event.getExtent(); + if(toReturn instanceof com.sk89q.worldedit.extent.NullExtent) { + return new NullExtent(toReturn, null); + } + if (!(toReturn instanceof AbstractDelegateExtent)) { + Fawe.debug("Extent " + toReturn + " must be AbstractDelegateExtent"); + return extent; + } + if (toReturn != extent) { + String className = toReturn.getClass().getName().toLowerCase(); + for (String allowed : Settings.IMP.EXTENT.ALLOWED_PLUGINS) { + if (className.contains(allowed.toLowerCase())) { + this.wrapped = true; + return (AbstractDelegateExtent) toReturn; + } + } + if (Settings.IMP.EXTENT.DEBUG) { + Fawe.debug("&cPotentially unsafe extent blocked: " + toReturn.getClass().getName()); + Fawe.debug("&8 - &7For area restrictions, it is recommended to use the FaweAPI"); + Fawe.debug("&8 - &7For block logging, it is recommended to use use BlocksHub"); + Fawe.debug("&8 - &7To allow this plugin add it to the FAWE `allowed-plugins` list"); + Fawe.debug("&8 - &7To hide this message set `debug` to false in the FAWE config.yml"); + if (toReturn.getClass().getName().contains("CoreProtect")) { + Fawe.debug("Note on CoreProtect: "); + Fawe.debug(" - If you disable CP's WE logger (CP config) and this still shows, please update CP"); + Fawe.debug(" - Use BlocksHub and set `debug` false in the FAWE config"); + } + } + } + return extent; + } + + public EditSessionBuilder commit() { + // reset + wrapped = false; + // + if (worldName == null) { + if (world == null) { + if (queue == null) { + worldName = ""; + } else { + worldName = queue.getWorldName(); + } + } else { + worldName = Fawe.imp().getWorldName(world); + } + } + if (world == null && !this.worldName.isEmpty()) { + world = FaweAPI.getWorld(this.worldName); + } + if (eventBus == null) { + eventBus = WorldEdit.getInstance().getEventBus(); + } + if (event == null) { + event = new EditSessionEvent(world, player == null ? null : (player.getPlayer()), -1, null); + } + if (player == null && event.getActor() != null) { + player = FawePlayer.wrap(event.getActor()); + } + if (limit == null) { + if (player == null) { + limit = FaweLimit.MAX; + } else { + limit = player.getLimit(); + } + } + if (autoQueue == null) { + autoQueue = true; + } + if (fastmode == null) { + if (player == null) { + fastmode = !Settings.IMP.HISTORY.ENABLE_FOR_CONSOLE; + } else { + fastmode = player.getSession().hasFastMode(); + } + } + if (checkMemory == null) { + checkMemory = player != null && !this.fastmode; + } + if (checkMemory) { + if (MemUtil.isMemoryLimitedSlow()) { + if (Perm.hasPermission(player, "worldedit.fast")) { + BBC.WORLDEDIT_OOM_ADMIN.send(player); + } + throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_LOW_MEMORY); + } + } +// this.originalLimit = limit; + this.blockBag = limit.INVENTORY_MODE != 0 ? blockBag : null; +// this.limit = limit.copy(); + + if (queue == null) { + boolean placeChunks = this.fastmode || this.limit.FAST_PLACEMENT; + World unwrapped = WorldWrapper.unwrap(world); + if (unwrapped instanceof FaweQueue) { + queue = (FaweQueue) unwrapped; + } else if (unwrapped instanceof MCAWorld) { + queue = ((MCAWorld) unwrapped).getQueue(); + } else if (player != null && world.equals(player.getWorld())) { + queue = player.getFaweQueue(placeChunks, autoQueue); + } else { + queue = SetQueue.IMP.getNewQueue(world, placeChunks, autoQueue); + } + } + if (combineStages == null) { + combineStages = + // If it's enabled in the settings + Settings.IMP.HISTORY.COMBINE_STAGES + // If fast placement is disabled, it's slower to perform a copy on each chunk + && this.limit.FAST_PLACEMENT + // If the specific queue doesn't support it + && queue.supports(FaweQueue.Capability.CHANGE_TASKS) + // If the edit uses items from the inventory we can't use a delayed task + && this.blockBag == null; + } +// if (Settings.IMP.EXPERIMENTAL.ANVIL_QUEUE_MODE && !(queue instanceof MCAQueue)) { +// queue = new MCAQueue(queue); +// } + if (!Settings.IMP.QUEUE.PROGRESS.DISPLAY.equalsIgnoreCase("false") && player != null) { + switch (Settings.IMP.QUEUE.PROGRESS.DISPLAY.toLowerCase()) { + case "chat": + this.queue.setProgressTask(new ChatProgressTracker(player)); + break; + case "title": + case "true": + default: + this.queue.setProgressTask(new DefaultProgressTracker(player)); + } + } +// this.bypassAll = wrapExtent(new FastWorldEditExtent(world, queue), eventBus, event, EditSession.Stage.BEFORE_CHANGE); +// this.bypassHistory = (this.extent = wrapExtent(bypassAll, eventBus, event, EditSession.Stage.BEFORE_REORDER)); +// if (!this.fastMode || changeSet != null) { +// if (changeSet == null) { +// if (Settings.IMP.HISTORY.USE_DISK) { +// UUID uuid = player == null ? EditSession.CONSOLE : player.getUUID(); +// if (Settings.IMP.HISTORY.USE_DATABASE) { +// changeSet = new RollbackOptimizedHistory(world, uuid); +// } else { +// changeSet = new DiskStorageHistory(world, uuid); +// } +// } else if (combineStages && Settings.IMP.HISTORY.COMPRESSION_LEVEL == 0 && !(queue instanceof MCAQueue)) { +// changeSet = new CPUOptimizedChangeSet(world); +// } else { +// changeSet = new MemoryOptimizedHistory(world); +// } +// } +// if (this.limit.SPEED_REDUCTION > 0) { +// this.bypassHistory = new SlowExtent(this.bypassHistory, this.limit.SPEED_REDUCTION); +// } +// if (changeSet instanceof NullChangeSet && Fawe.imp().getBlocksHubApi() != null && player != null) { +// changeSet = LoggingChangeSet.wrap(player, changeSet); +// } +// if (!(changeSet instanceof NullChangeSet)) { +// if (!(changeSet instanceof LoggingChangeSet) && player != null && Fawe.imp().getBlocksHubApi() != null) { +// changeSet = LoggingChangeSet.wrap(player, changeSet); +// } +// if (this.blockBag != null) { +// changeSet = new BlockBagChangeSet(changeSet, blockBag, limit.INVENTORY_MODE == 1); +// } +// if (combineStages) { +// changeTask = changeSet; +// changeSet.addChangeTask(queue); +// } else { +// this.extent = (history = new HistoryExtent(this, bypassHistory, changeSet, queue)); +//// if (this.blockBag != null) { +//// this.extent = new BlockBagExtent(this.extent, blockBag, limit.INVENTORY_MODE == 1); +//// } +// } +// } +// } +// if (allowedRegions == null) { +// if (player != null && !player.hasPermission("fawe.bypass") && !player.hasPermission("fawe.bypass.regions") && !(queue instanceof VirtualWorld)) { +// allowedRegions = player.getCurrentRegions(); +// } +// } +// this.maxY = getWorld() == null ? 255 : world.getMaxY(); +// if (allowedRegions != null) { +// if (allowedRegions.length == 0) { +// this.extent = new NullExtent(this.extent, BBC.WORLDEDIT_CANCEL_REASON_NO_REGION); +// } else { +// this.extent = new ProcessedWEExtent(this.extent, this.limit); +// if (allowedRegions.length == 1) { +// Region region = allowedRegions[0]; +// this.extent = new SingleRegionExtent(this.extent, this.limit, allowedRegions[0]); +// } else { +// this.extent = new MultiRegionExtent(this.extent, this.limit, allowedRegions); +// } +// } +// } else { +// this.extent = new HeightBoundExtent(this.extent, this.limit, 0, maxY); +// } +// if (this.limit.STRIP_NBT != null && !this.limit.STRIP_NBT.isEmpty()) { +// this.extent = new StripNBTExtent(this.extent, this.limit.STRIP_NBT); +// } +// this.extent = wrapExtent(this.extent, bus, event, Stage.BEFORE_HISTORY); + return this; + } + public EditSession build() { - return new EditSession(worldName, world, queue, player, limit, changeSet, allowedRegions, autoQueue, fastmode, checkMemory, combineStages, blockBag, eventBus, event); + return new EditSession(worldName, world, queue, player, limit, changeSet, allowedRegions, autoQueue, fastmode, checkMemory, combineStages, blockBag, eventBus, event); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java b/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java index 84d3af4ad..ae0989472 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java @@ -486,7 +486,7 @@ public class TextureUtil implements TextureHolder { BlockType block = getNearestBlock(color); TextureUtil.BiomeColor biome = getNearestBiome(color); int blockColor = getColor(block); - blockAndBiomeIdOutput[0] = block.getInternalId(); + blockAndBiomeIdOutput[0] = block.getDefaultState().getOrdinalChar(); blockAndBiomeIdOutput[1] = biome.id; if (colorDistance(biome.grassCombined, color) - biomePriority > colorDistance(blockColor, color)) { 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 4f111f826..476483d99 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 @@ -235,11 +235,6 @@ public class WorldWrapper extends AbstractWorld { return parent.getBlock(position); } - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return parent.getLazyBlock(position); - } - @Override public BaseBlock getFullBlock(BlockVector3 position) { return parent.getFullBlock(position); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index 880427593..1f9aaf8ca 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -42,7 +42,6 @@ import com.boydti.fawe.object.changeset.CPUOptimizedChangeSet; import com.boydti.fawe.object.changeset.DiskStorageHistory; import com.boydti.fawe.object.changeset.FaweChangeSet; import com.boydti.fawe.object.changeset.MemoryOptimizedHistory; -import com.boydti.fawe.object.collection.BlockVectorSet; import com.boydti.fawe.object.collection.LocalBlockVectorSet; import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.object.extent.FastWorldEditExtent; @@ -61,6 +60,7 @@ import com.boydti.fawe.object.mask.ResettableMask; import com.boydti.fawe.object.pattern.ExistingPattern; import com.boydti.fawe.object.progress.ChatProgressTracker; import com.boydti.fawe.object.progress.DefaultProgressTracker; +import com.boydti.fawe.util.EditSessionBuilder; import com.boydti.fawe.util.ExtentTraverser; import com.boydti.fawe.util.MaskTraverser; import com.boydti.fawe.util.MathMan; @@ -79,28 +79,18 @@ import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.ChangeSetExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.MaskingExtent; -import com.sk89q.worldedit.extent.cache.LastAccessExtentCache; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.extent.inventory.BlockBagExtent; -import com.sk89q.worldedit.extent.reorder.ChunkBatchingExtent; -import com.sk89q.worldedit.extent.reorder.MultiStageReorder; -import com.sk89q.worldedit.extent.validation.BlockChangeLimiter; -import com.sk89q.worldedit.extent.validation.DataValidatorExtent; -import com.sk89q.worldedit.extent.world.BlockQuirkExtent; -import com.sk89q.worldedit.extent.world.ChunkLoadingExtent; -import com.sk89q.worldedit.extent.world.FastModeExtent; import com.sk89q.worldedit.extent.world.SurvivalModeExtent; import com.sk89q.worldedit.function.GroundFunction; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.RegionMaskingFilter; -import com.sk89q.worldedit.function.block.BlockDistributionCounter; import com.sk89q.worldedit.function.block.BlockReplace; import com.sk89q.worldedit.function.block.Naturalizer; import com.sk89q.worldedit.function.generator.ForestGenerator; import com.sk89q.worldedit.function.generator.GardenPatchGenerator; import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.function.mask.BlockMaskBuilder; -import com.sk89q.worldedit.function.mask.BlockStateMask; import com.sk89q.worldedit.function.mask.BlockTypeMask; import com.sk89q.worldedit.function.mask.BoundedHeightMask; import com.sk89q.worldedit.function.mask.ExistingBlockMask; @@ -116,7 +106,6 @@ import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.function.pattern.WaterloggedRemover; import com.sk89q.worldedit.function.util.RegionOffset; import com.sk89q.worldedit.function.visitor.DirectionalVisitor; import com.sk89q.worldedit.function.visitor.DownwardVisitor; @@ -127,12 +116,10 @@ import com.sk89q.worldedit.function.visitor.RecursiveVisitor; import com.sk89q.worldedit.function.visitor.RegionVisitor; import com.sk89q.worldedit.history.UndoContext; import com.sk89q.worldedit.history.change.BlockChange; -import com.sk89q.worldedit.history.changeset.BlockOptimizedHistory; import com.sk89q.worldedit.history.changeset.ChangeSet; import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; -import com.sk89q.worldedit.internal.expression.runtime.RValue; import com.sk89q.worldedit.internal.expression.runtime.ExpressionTimeoutException; import com.sk89q.worldedit.internal.expression.runtime.RValue; import com.sk89q.worldedit.math.BlockVector2; @@ -142,7 +129,6 @@ import com.sk89q.worldedit.math.MutableBlockVector2; import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.math.Vector2; import com.sk89q.worldedit.math.Vector3; -import com.sk89q.worldedit.math.interpolation.Interpolation; import com.sk89q.worldedit.math.interpolation.KochanekBartelsInterpolation; import com.sk89q.worldedit.math.interpolation.Node; import com.sk89q.worldedit.math.noise.RandomNoise; @@ -159,21 +145,30 @@ import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.TreeGenerator; -import com.sk89q.worldedit.util.collection.DoubleArrayList; import com.sk89q.worldedit.util.eventbus.EventBus; -import com.sk89q.worldedit.world.NullWorld; import com.sk89q.worldedit.world.SimpleWorld; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.*; -import com.sk89q.worldedit.world.registry.LegacyMapper; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockCategories; +import com.sk89q.worldedit.world.block.BlockID; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.weather.WeatherType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; import static com.google.common.base.Preconditions.checkArgument; @@ -204,19 +199,19 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, BEFORE_CHANGE } - private World world; - private String worldName; - private FaweQueue queue; - private boolean wrapped; - private boolean fastMode; - private AbstractDelegateExtent extent; - private HistoryExtent history; - private AbstractDelegateExtent bypassHistory; - private AbstractDelegateExtent bypassAll; - private FaweLimit originalLimit; - private FaweLimit limit; - private FawePlayer player; - private FaweChangeSet changeTask; + private final World world; + private final String worldName; + private final FaweQueue queue; + private final boolean wrapped; + private final boolean fastMode; + private final AbstractDelegateExtent extent; + private final HistoryExtent history; + private final AbstractDelegateExtent bypassHistory; + private final AbstractDelegateExtent bypassAll; + private final FaweLimit originalLimit; + private final FaweLimit limit; + private final FawePlayer player; + private final FaweChangeSet changeTask; private MutableBlockVector3 mutablebv = new MutableBlockVector3(); @@ -249,7 +244,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, if (event == null) { event = new EditSessionEvent(world, player == null ? null : (player.getPlayer()), -1, null); } - event.setEditSession(this); if (player == null && event.getActor() != null) { player = FawePlayer.wrap(event.getActor()); } @@ -393,7 +387,10 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, this.extent = new StripNBTExtent(this.extent, this.limit.STRIP_NBT); } this.extent = wrapExtent(this.extent, bus, event, Stage.BEFORE_HISTORY); - setExtent(this.extent); + } + + public EditSession(EditSessionBuilder builder) { + super(builder.) } /** @@ -496,15 +493,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, return bypassHistory; } - public Extent getExtent() { - return extent; - } - - public void setExtent(AbstractDelegateExtent extent) { - this.extent = extent; - new ExtentTraverser(this).setNext(extent); - } - /** * Get the FawePlayer or null * @@ -1057,17 +1045,8 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, return queue.getOpacity(x, y, z); } - @Override - public BlockState getLazyBlock(final BlockVector3 position) { - return getLazyBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ()); - } - - public BlockState getLazyBlock(int x, int y, int z) { - return extent.getLazyBlock(x, y, z); - } - public BlockState getBlock(int x, int y, int z) { - return getLazyBlock(x, y, z); + return extent.getBlock(x, y, z); } @Override @@ -1085,7 +1064,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * * @param position the position * @return the block type - * @deprecated Use {@link #getLazyBlock(BlockVector3)} or {@link #getBlock(BlockVector3)} + * @deprecated Use {@link #getBlock(BlockVector3)} or {@link #getBlock(BlockVector3)} */ @Deprecated public BlockType getBlockType(final BlockVector3 position) { @@ -1099,7 +1078,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @param z the Z coordinate * @param minY minimal height * @param maxY maximal height - * @param filter a mask of blocks to consider, or null to consider any solid (movement-blocking) block * @return height of highest block found or 'minY' */ public int getHighestTerrainBlock(int x, int z, int minY, int maxY) { @@ -2918,11 +2896,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * Generate a shape for the given expression. * * @param region the region to generate the shape in - * @param zero the coordinate origin for x/y/z variables - * @param unit the scale of the x/y/z/ variables - * @param pattern the default material to make the shape from - * @param expressionString the expression defining the shape - * @param hollow whether the shape should be hollow * @return number of blocks changed * @throws ExpressionException * @throws MaxChangedBlocksException @@ -3433,8 +3406,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, CompoundTag nbt = block.getNbtData(); if (nbt != null) { if (nbt.containsKey("items")) { - block.setNbtData(null); - return setBlock(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(), block); + return setBlock(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(), block.toBlockState().toBaseBlock()); } } return false; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java index aa18e499f..97abe6b0a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java @@ -49,7 +49,7 @@ public class AreaPickaxe implements BlockTool { for (int x = ox - range; x <= ox + range; ++x) { for (int z = oz - range; z <= oz + range; ++z) { for (int y = oy + range; y >= oy - range; --y) { - if (initialType.equals(editSession.getLazyBlock(x, y, z))) { + if (initialType.equals(editSession.getBlock(x, y, z))) { continue; } editSession.setBlock(x, y, z, BlockTypes.AIR.getDefaultState()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java index 646915f30..6578beb99 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java @@ -49,7 +49,7 @@ public class GravityBrush implements Brush { for (int z = position.getBlockZ() + size; z > position.getBlockZ() - size; --z) { int freeSpot = startCheckY; for (int y = startCheckY; y <= endY; y++) { - BlockStateHolder block = editSession.getLazyBlock(x, y, z); + BlockStateHolder block = editSession.getBlock(x, y, z); if (!block.getBlockType().getMaterial().isAir()) { if (y != freeSpot) { editSession.setBlock(x, y, z, EditSession.nullBlock); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java index c94ba677a..fe1e845c5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java @@ -66,7 +66,6 @@ public class EditSessionEvent extends Event implements Cancellable { private final int maxBlocks; private final Stage stage; private Extent extent; - private EditSession session; private boolean cancelled; /** @@ -84,14 +83,6 @@ public class EditSessionEvent extends Event implements Cancellable { this.stage = stage; } - public void setEditSession(EditSession session) { - this.session = session; - } - - public EditSession getEditSession() { - return session; - } - /** * Get the actor for this event. * @@ -169,9 +160,7 @@ public class EditSessionEvent extends Event implements Cancellable { * @return a new event */ public EditSessionEvent clone(Stage stage) { - EditSessionEvent clone = new EditSessionEvent(world, actor, maxBlocks, stage); - clone.setEditSession(session); - return clone; + return new EditSessionEvent(world, actor, maxBlocks, stage); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java index d3021c391..93b541b2f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java @@ -22,8 +22,6 @@ package com.sk89q.worldedit.extent; import com.boydti.fawe.jnbt.anvil.generator.GenBase; import com.boydti.fawe.jnbt.anvil.generator.Resource; import com.boydti.fawe.object.extent.LightingExtent; -import static com.google.common.base.Preconditions.checkNotNull; - import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; @@ -41,29 +39,40 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.registry.BundledBlockData; -import java.util.List; + import javax.annotation.Nullable; +import java.util.List; -public class AbstractDelegateExtent implements LightingExtent { - private transient final Extent extent; - protected MutableBlockVector3 mutable = new MutableBlockVector3(0, 0, 0); +import static com.google.common.base.Preconditions.checkNotNull; - /** - * Create a new instance. - * - * @param extent the extent - */ - public AbstractDelegateExtent(Extent extent) { - checkNotNull(extent); - this.extent = extent; +public class AbstractDelegateExtent implements Extent, LightingExtent { + private final Extent extent; + + public AbstractDelegateExtent(Extent parent) { + this.extent = parent; } - public int getSkyLight(int x, int y, int z) { - if (extent instanceof LightingExtent) { - return ((LightingExtent) extent).getSkyLight(x, y, z); - } - return 0; + /** + * Get the extent. + * + * @return the extent + */ + public final Extent getExtent() { + return extent; + } + + /* + Bounds + */ + + @Override + public BlockVector3 getMinimumPoint() { + return extent.getMinimumPoint(); + } + + @Override + public BlockVector3 getMaximumPoint() { + return extent.getMaximumPoint(); } @Override @@ -71,11 +80,40 @@ public class AbstractDelegateExtent implements LightingExtent { return extent.getMaxY(); } + /* + Input + Output + */ + @Override - public BlockType getBlockType(BlockVector3 position) { - return extent.getBlockType(position); + public BlockState getBlock(int x, int y, int z) { + return extent.getBlock(x, y, z); } + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + return extent.getFullBlock(x, y, z); + } + + @Override + public BiomeType getBiome(int x, int z) { + return extent.getBiome(x, z); + } + + @Override + public boolean setBiome(int x, int z, BiomeType biome) { + return extent.setBiome(x, z, biome); + } + + /* + Light + */ + + public int getSkyLight(int x, int y, int z) { + if (extent instanceof LightingExtent) { + return ((LightingExtent) extent).getSkyLight(x, y, z); + } + return 0; + } public int getBlockLight(int x, int y, int z) { if (extent instanceof LightingExtent) { @@ -88,7 +126,7 @@ public class AbstractDelegateExtent implements LightingExtent { if (extent instanceof LightingExtent) { return ((LightingExtent) extent).getOpacity(x, y, z); } - return getLazyBlock(x, y, z).getBlockType().getMaterial().getLightOpacity(); + return getBlock(x, y, z).getBlockType().getMaterial().getLightOpacity(); } @Override @@ -103,164 +141,20 @@ public class AbstractDelegateExtent implements LightingExtent { if (extent instanceof LightingExtent) { return ((LightingExtent) extent).getBrightness(x, y, z); } - return getLazyBlock(x, y, z).getBlockType().getMaterial().getLightValue(); + return getBlock(x, y, z).getBlockType().getMaterial().getLightValue(); } - /** - * Get the extent. - * - * @return the extent + /* + Generic */ - public Extent getExtent() { - return extent; - } - - @Override - public BlockState getLazyBlock(int x, int y, int z) { - return extent.getLazyBlock(mutable.setComponents(x, y, z)); - } - - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return extent.getLazyBlock(position); - } - - @Override - public > boolean setBlock(int x, int y, int z, T block) throws WorldEditException { - return setBlock(mutable.setComponents(x, y, z), block); - } - - public BlockState getBlock(BlockVector3 position) { - return extent.getBlock(position); - } - - @Override - public BaseBlock getFullBlock(BlockVector3 position) { - return extent.getFullBlock(position); - } - - @Override - public > boolean setBlock(BlockVector3 location, T block) throws WorldEditException { - return extent.setBlock(location, block); - } - - @Override - @Nullable - public Entity createEntity(Location location, BaseEntity entity) { - return extent.createEntity(location, entity); - } - - @Override - public List getEntities() { - return extent.getEntities(); - } - - @Override - public List getEntities(Region region) { - return extent.getEntities(region); - } - - @Override - public BiomeType getBiome(BlockVector2 position) { - return extent.getBiome(position); - } - - @Override - public boolean setBiome(BlockVector2 position, BiomeType biome) { - return extent.setBiome(position, biome); - } - - @Override - public boolean setBiome(int x, int y, int z, BiomeType biome) { - return extent.setBiome(x, y, z, biome); - } - - @Override - public int getHighestTerrainBlock(int x, int z, int minY, int maxY) { - return extent.getHighestTerrainBlock(x, z, minY, maxY); - } - - @Override - public BlockVector3 getMinimumPoint() { - return extent.getMinimumPoint(); - } - - @Override - public BlockVector3 getMaximumPoint() { - return extent.getMaximumPoint(); - } - - protected Operation commitBefore() { - return null; - } @Override public String toString() { return super.toString() + ":" + extent.toString(); } - @Override - public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) { - return extent.getNearestSurfaceLayer(x, z, y, minY, maxY); - } - - @Override - public int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) { - return extent.getHighestTerrainBlock(x, z, minY, maxY, filter); - } - - @Override - public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) { - return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir); - } - - @Override - public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) { - return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY); - } - - @Override - public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) { - return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax); - } - - public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) { - return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask); - } - - @Override - public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, boolean ignoreAir) { - return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir); - } - - @Override - public void addCaves(Region region) throws WorldEditException { - extent.addCaves(region); - } - - @Override - public void generate(Region region, GenBase gen) throws WorldEditException { - extent.generate(region, gen); - } - - @Override - public void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException { - extent.spawnResource(region, gen, rarity, frequency); - } - - @Override - public boolean contains(BlockVector3 pt) { - return extent.contains(pt); - } - - @Override - public void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException { - extent.addOre(region, mask, material, size, frequency, rarity, minY, maxY); - } - - @Override - public void addOres(Region region, Mask mask) throws WorldEditException { - extent.addOres(region, mask); + protected Operation commitBefore() { + return null; } @Override @@ -279,6 +173,4 @@ public class AbstractDelegateExtent implements LightingExtent { return null; } } - - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java index 9c2416eb0..3f41ba3cb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java @@ -117,33 +117,11 @@ public interface Extent extends InputExtent, OutputExtent { return null; } - @Override - default BlockState getBlock(BlockVector3 position) { - return getFullBlock(position).toImmutableState(); - } - - @Override - default BlockState getLazyBlock(BlockVector3 position) { - return getFullBlock(position).toImmutableState(); - } - - default BlockState getLazyBlock(int x, int y, int z) { - return getLazyBlock(BlockVector3.at(x, y, z)); - } - - default > boolean setBlock(int x, int y, int z, T state) throws WorldEditException { - return setBlock(BlockVector3.at(x, y, z), state); - } - - default boolean setBiome(int x, int y, int z, BiomeType biome) { - return setBiome(BlockVector2.at(x, z), biome); - } - default int getHighestTerrainBlock(final int x, final int z, int minY, int maxY) { maxY = Math.min(maxY, Math.max(0, maxY)); minY = Math.max(0, minY); for (int y = maxY; y >= minY; --y) { - BlockState block = getLazyBlock(x, y, z); + BlockState block = getBlock(x, y, z); if (block.getBlockType().getMaterial().isMovementBlocker()) { return y; } @@ -167,20 +145,20 @@ public interface Extent extends InputExtent, OutputExtent { int clearanceBelow = y - minY; int clearance = Math.min(clearanceAbove, clearanceBelow); - BlockState block = getLazyBlock(x, y, z); + BlockState block = getBlock(x, y, z); boolean state = !block.getBlockType().getMaterial().isMovementBlocker(); int data1 = PropertyGroup.LEVEL.get(block); int data2 = data1; int offset = state ? 0 : 1; for (int d = 0; d <= clearance; d++) { int y1 = y + d; - block = getLazyBlock(x, y1, z); + block = getBlock(x, y1, z); if (!block.getBlockType().getMaterial().isMovementBlocker() != state) { return ((y1 - offset) << 4) - (15 - (state ? PropertyGroup.LEVEL.get(block) : data1)); } data1 = PropertyGroup.LEVEL.get(block); int y2 = y - d; - block = getLazyBlock(x, y2, z); + block = getBlock(x, y2, z); if (!block.getBlockType().getMaterial().isMovementBlocker() != state) { return ((y2 + offset) << 4) - (15 - (state ? PropertyGroup.LEVEL.get(block) : data2)); } @@ -189,7 +167,7 @@ public interface Extent extends InputExtent, OutputExtent { if (clearanceAbove != clearanceBelow) { if (clearanceAbove < clearanceBelow) { for (int layer = y - clearance - 1; layer >= minY; layer--) { - block = getLazyBlock(x, layer, z); + block = getBlock(x, layer, z); if (!block.getBlockType().getMaterial().isMovementBlocker() != state) { int data = (state ? PropertyGroup.LEVEL.get(block) : data1); return ((layer + offset) << 4) + 0; @@ -198,7 +176,7 @@ public interface Extent extends InputExtent, OutputExtent { } } else { for (int layer = y + clearance + 1; layer <= maxY; layer++) { - block = getLazyBlock(x, layer, z); + block = getBlock(x, layer, z); if (!block.getBlockType().getMaterial().isMovementBlocker() != state) { return ((layer - offset) << 4) - (15 - (state ? PropertyGroup.LEVEL.get(block) : data2)); } @@ -254,33 +232,33 @@ public interface Extent extends InputExtent, OutputExtent { int clearanceAbove = maxY - y; int clearanceBelow = y - minY; int clearance = Math.min(clearanceAbove, clearanceBelow); - BlockStateHolder block = getLazyBlock(x, y, z); + BlockStateHolder block = getBlock(x, y, z); boolean state = !block.getBlockType().getMaterial().isMovementBlocker(); int offset = state ? 0 : 1; for (int d = 0; d <= clearance; d++) { int y1 = y + d; - block = getLazyBlock(x, y1, z); + block = getBlock(x, y1, z); if (!block.getMaterial().isMovementBlocker() != state && block.getBlockType() != BlockTypes.__RESERVED__) return y1 - offset; int y2 = y - d; - block = getLazyBlock(x, y2, z); + block = getBlock(x, y2, z); if (!block.getMaterial().isMovementBlocker() != state && block.getBlockType() != BlockTypes.__RESERVED__) return y2 + offset; } if (clearanceAbove != clearanceBelow) { if (clearanceAbove < clearanceBelow) { for (int layer = y - clearance - 1; layer >= minY; layer--) { - block = getLazyBlock(x, layer, z); + block = getBlock(x, layer, z); if (!block.getMaterial().isMovementBlocker() != state && block.getBlockType() != BlockTypes.__RESERVED__) return layer + offset; } } else { for (int layer = y + clearance + 1; layer <= maxY; layer++) { - block = getLazyBlock(x, layer, z); + block = getBlock(x, layer, z); if (!block.getMaterial().isMovementBlocker() != state && block.getBlockType() != BlockTypes.__RESERVED__) return layer - offset; } } } int result = state ? failedMin : failedMax; if(result > 0 && !ignoreAir) { - block = getLazyBlock(x, result, z); + block = getBlock(x, result, z); return block.getBlockType().getMaterial().isAir() ? -1 : result; } return result; @@ -296,7 +274,7 @@ public interface Extent extends InputExtent, OutputExtent { } } - default public void addSchems(Region region, Mask mask, List clipboards, int rarity, boolean rotate) throws WorldEditException { + default void addSchems(Region region, Mask mask, List clipboards, int rarity, boolean rotate) throws WorldEditException { spawnResource(region, new SchemGen(mask, this, clipboards, rotate), rarity, 1); } @@ -320,11 +298,11 @@ public interface Extent extends InputExtent, OutputExtent { return (pt.containedWithin(min, max)); } - default public void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException { + default void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException { spawnResource(region, new OreGen(this, mask, material, size, minY, maxY), rarity, frequency); } - default public void addOres(Region region, Mask mask) throws WorldEditException { + default void addOres(Region region, Mask mask) throws WorldEditException { addOre(region, mask, BlockTypes.DIRT.getDefaultState(), 33, 10, 100, 0, 255); addOre(region, mask, BlockTypes.GRAVEL.getDefaultState(), 33, 8, 100, 0, 255); addOre(region, mask, BlockTypes.ANDESITE.getDefaultState(), 33, 10, 100, 0, 79); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/InputExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/InputExtent.java index 3edcccb43..1f4342518 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/InputExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/InputExtent.java @@ -22,6 +22,8 @@ package com.sk89q.worldedit.extent; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MutableBlockVector2; +import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -46,42 +48,31 @@ public interface InputExtent { * @param position position of the block * @return the block */ - BlockState getBlock(BlockVector3 position); + default BlockState getBlock(BlockVector3 position) { + return getBlock(position.getX(), position.getY(), position.getZ()); + } + + default BlockState getBlock(int x, int y, int z) { + return getBlock(MutableBlockVector3.get(x, y, z)); + } default BlockType getBlockType(BlockVector3 position) { return getBlock(position).getBlockType(); } - /** - * Get a lazy, immutable snapshot of the block at the given location that only - * immediately contains information about the block's type (and metadata). - * - *

Further information (such as NBT data) will be available by the - * time of access. Therefore, it is not recommended that - * this method is used if the world is being simulated at the time of - * call. If the block needs to be stored for future use, then this method should - * definitely not be used. Moreover, the block that is returned is immutable (or - * should be), and therefore modifications should not be attempted on it. If a - * modifiable copy is required, then the block should be cloned.

- * - *

This method exists because it is sometimes important to inspect the block - * at a given location, but {@link #getBlock(Vector)} may be too expensive in - * the underlying implementation. It is also not possible to implement - * caching if the returned object is mutable, so this methods allows caching - * implementations to be used.

- * - * @param position position of the block - * @return the block - */ - BlockState getLazyBlock(BlockVector3 position); - /** * Get a immutable snapshot of the block at the given location. * * @param position position of the block * @return the block */ - BaseBlock getFullBlock(BlockVector3 position); + default BaseBlock getFullBlock(BlockVector3 position) { + return getFullBlock(position.getX(), position.getY(), position.getZ()); + } + + default BaseBlock getFullBlock(int x, int y, int z) { + return getFullBlock(MutableBlockVector3.get(x, y, z)); + } /** * Get the biome at the given location. @@ -92,6 +83,11 @@ public interface InputExtent { * @param position the (x, z) location to check the biome at * @return the biome at the location */ - BiomeType getBiome(BlockVector2 position); + default BiomeType getBiome(BlockVector2 position) { + return getBiome(position.getX(), position.getZ()); + } + default BiomeType getBiome(int x, int z) { + return getBiome(MutableBlockVector2.get(x, z)); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java index 53351e0b0..a7e73c1bd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java @@ -23,6 +23,8 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MutableBlockVector2; +import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -50,7 +52,13 @@ public interface OutputExtent { * @return true if the block was successfully set (return value may not be accurate) * @throws WorldEditException thrown on an error */ - > boolean setBlock(BlockVector3 position, T block) throws WorldEditException; + default > boolean setBlock(BlockVector3 position, T block) throws WorldEditException { + return setBlock(position.getX(), position.getY(), position.getZ(), block); + } + + default > boolean setBlock(int x, int y, int z, T block) throws WorldEditException { + return setBlock(MutableBlockVector3.get(x, y, z), block); + } /** * Set the biome. @@ -59,7 +67,13 @@ public interface OutputExtent { * @param biome the biome to set to * @return true if the biome was successfully set (return value may not be accurate) */ - boolean setBiome(BlockVector2 position, BiomeType biome); + default boolean setBiome(BlockVector2 position, BiomeType biome) { + return setBiome(position.getX(), 0, position.getBlockZ(), biome); + } + + default boolean setBiome(int x, int y, int z, BiomeType biome) { + return setBiome(MutableBlockVector2.get(x, z), biome); + } /** * Return an {@link Operation} that should be called to tie up loose ends diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/PassthroughExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/PassthroughExtent.java new file mode 100644 index 000000000..c8df9204e --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/PassthroughExtent.java @@ -0,0 +1,177 @@ +package com.sk89q.worldedit.extent; + +import com.boydti.fawe.jnbt.anvil.generator.GenBase; +import com.boydti.fawe.jnbt.anvil.generator.Resource; +import com.boydti.fawe.object.extent.LightingExtent; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.OperationQueue; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.util.Countable; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; + +import javax.annotation.Nullable; +import java.util.List; + +public class PassthroughExtent extends AbstractDelegateExtent { + private final Extent extent; + + public PassthroughExtent(Extent parent) { + super(parent); + this.extent = parent; + } + + @Override + public List getEntities(Region region) { + return extent.getEntities(region); + } + + @Override + public List getEntities() { + return extent.getEntities(); + } + + @Override + @Nullable + public Entity createEntity(Location location, BaseEntity entity) { + return extent.createEntity(location, entity); + } + + @Override + public int getHighestTerrainBlock(int x, int z, int minY, int maxY) { + return extent.getHighestTerrainBlock(x, z, minY, maxY); + } + + @Override + public int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) { + return extent.getHighestTerrainBlock(x, z, minY, maxY, filter); + } + + @Override + public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) { + return extent.getNearestSurfaceLayer(x, z, y, minY, maxY); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) { + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) { + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) { + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) { + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, boolean ignoreAir) { + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir); + } + + @Override + public void addCaves(Region region) throws WorldEditException { + extent.addCaves(region); + } + + @Override + public void generate(Region region, GenBase gen) throws WorldEditException { + extent.generate(region, gen); + } + + @Override + public void addSchems(Region region, Mask mask, List clipboards, int rarity, boolean rotate) throws WorldEditException { + extent.addSchems(region, mask, clipboards, rarity, rotate); + } + + @Override + public void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException { + extent.spawnResource(region, gen, rarity, frequency); + } + + @Override + public boolean contains(BlockVector3 pt) { + return extent.contains(pt); + } + + @Override + public void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException { + extent.addOre(region, mask, material, size, frequency, rarity, minY, maxY); + } + + @Override + public void addOres(Region region, Mask mask) throws WorldEditException { + extent.addOres(region, mask); + } + + @Override + public List> getBlockDistribution(Region region) { + return extent.getBlockDistribution(region); + } + + @Override + public List> getBlockDistributionWithData(Region region) { + return extent.getBlockDistributionWithData(region); + } + + @Override + public BlockArrayClipboard lazyCopy(Region region) { + return extent.lazyCopy(region); + } + + @Override + public BlockState getBlock(BlockVector3 position) { + return extent.getBlock(position); + } + + @Override + public BlockType getBlockType(BlockVector3 position) { + return extent.getBlockType(position); + } + + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + return extent.getFullBlock(position); + } + + @Override + public BiomeType getBiome(BlockVector2 position) { + return extent.getBiome(position); + } + + @Override + public > boolean setBlock(BlockVector3 position, T block) throws WorldEditException { + return extent.setBlock(position, block); + } + + @Override + public > boolean setBlock(int x, int y, int z, T block) throws WorldEditException { + return extent.setBlock(x, y, z, block); + } + + @Override + public boolean setBiome(BlockVector2 position, BiomeType biome) { + return extent.setBiome(position, biome); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java index 38b3783b1..05e22d9d2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.function.mask; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.minecraft.util.commands.Link; import com.sk89q.worldedit.command.UtilityCommands; import com.sk89q.worldedit.math.BlockVector3; @@ -42,6 +43,8 @@ public interface Mask { */ boolean test(BlockVector3 vector); +// boolean test(FilterBlock block); + /** * Get the 2D version of this mask if one exists. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/FawePattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/FawePattern.java index 8a797f5cd..a45ac9168 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/FawePattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/FawePattern.java @@ -16,17 +16,17 @@ import com.sk89q.worldedit.world.block.BlockState; */ @Link(clazz = UtilityCommands.class, value = "patterns") public interface FawePattern extends Pattern { - - @Deprecated - default BaseBlock apply(BlockVector3 position) { - throw new UnsupportedOperationException("Please use apply(extent, get, set)"); - } - - /** - * Return a {@link BlockStateHolder} for the given position. - * - * @return a block - */ - @Override - boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException; +// +// @Deprecated +// default BaseBlock apply(BlockVector3 position) { +// throw new UnsupportedOperationException("Please use apply(extent, get, set)"); +// } +// +// /** +// * Return a {@link BlockStateHolder} for the given position. +// * +// * @return a block +// */ +// @Override +// boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException; } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java index 290240c2c..93eeb07a5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.function.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.minecraft.util.commands.Link; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.UtilityCommands; @@ -26,23 +27,12 @@ import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.block.BlockState; /** * Returns a {@link BlockStateHolder} for a given position. */ @Link(clazz = UtilityCommands.class, value = "patterns") -public interface Pattern{ - -// @Override -// default BaseBlock next(BlockVector3 position) { -// return new BaseBlock(apply(position)); -// } -// -// @Override -// default BaseBlock next(int x, int y, int z) { -// return new BaseBlock(apply(BlockVector3.at(x, y, z))); -// } +public interface Pattern { /** * Return a {@link BlockStateHolder} for the given position. @@ -55,4 +45,10 @@ public interface Pattern{ default boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { return extent.setBlock(set, apply(get)); } + +// void apply(FilterBlock block); + + default void apply(FilterBlock block) { + apply((BlockVector3) block).apply(block); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/ScanChunk.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/ScanChunk.java index cfef60a74..96ce3ca37 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/ScanChunk.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/ScanChunk.java @@ -1,23 +1,19 @@ package com.sk89q.worldedit.function.visitor; -import com.boydti.fawe.example.MappedFaweQueue; -import com.boydti.fawe.object.FaweQueue; -import com.boydti.fawe.object.HasFaweQueue; -import com.boydti.fawe.object.collection.BlockVectorSet; +import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.util.MathMan; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.math.BlockVector3; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.LongArraySet; -import it.unimi.dsi.fastutil.longs.LongSet; import it.unimi.dsi.fastutil.objects.ObjectIterator; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; -import java.util.Map; +import java.util.concurrent.ConcurrentLinkedQueue; /** * A chunk based search algorithm @@ -58,15 +54,15 @@ public class ScanChunk { private final RegionFunction function; private final BlockVector3[] directions; - private final Long2ObjectOpenHashMap visited; - private final Long2ObjectOpenHashMap queues; + private final Long2ObjectOpenHashMap visits; + private final Long2ObjectOpenHashMap queues; public ScanChunk(final RegionFunction function) { this.function = function; this.directions = DEFAULT_DIRECTIONS; this.queues = new Long2ObjectOpenHashMap<>(); - this.visited = new Long2ObjectOpenHashMap<>(); + this.visits = new Long2ObjectOpenHashMap<>(); } public static final long pairInt(int x, int y) { @@ -77,7 +73,7 @@ public class ScanChunk { int X = x >> 4; int Z = z >> 4; long pair = pairInt(X, Z); - long[][] chunk = visited.get(pair); + long[][] chunk = visits.get(pair); if (chunk == null) return false; int layer = y >> 4; long[] section = chunk[layer]; @@ -87,7 +83,7 @@ public class ScanChunk { public void start(int x, int y, int z) { if (!isVisited(x, y, z)) { - queue(x, y, z); + push(x, y, z); visit(x, y, z); } } @@ -96,45 +92,240 @@ public class ScanChunk { int X = x >> 4; int Z = z >> 4; long pair = pairInt(X, Z); - long[][] chunk = visited.get(pair); - if (chunk == null) { - visited.put(pair, chunk = new long[16][]); + long[][] arrs = visits.get(pair); + if (arrs == null) { + visits.put(pair, arrs = new long[16][]); } int layer = y >> 4; - long[] section = chunk[layer]; + long[] section = arrs[layer]; if (section == null) { - chunk[layer] = section = new long[64]; + arrs[layer] = section = new long[64]; } set(section, getLocalIndex(x & 15, y & 15, z & 15)); } - public void queue(int x, int y, int z) { + private char[] getOrCreateQueue(long pair, int layer) { + char[][] arrs = queues.get(pair); + if (arrs == null) { + queues.put(pair, arrs = new char[16][]); + } + + char[] section = arrs[layer]; + if (section == null) { + arrs[layer] = section = newQueue(); + } + return section; + } + + private void push(int x, int y, int z) { int X = x >> 4; int Z = z >> 4; long pair = pairInt(X, Z); - char[] queue = queues.get(pair); - if (queue == null) { - queue = queues.put(pair, queue = new char[MAX_QUEUE + 2]); - queue[0] = 2; - queue[1] = 2; + int layer = y >> 4; + char[] section = getOrCreateQueue(pair, layer); + push(section, x & 15, y & 15, z & 15); + } + + private void push(char[] queue, int x, int y, int z) { + char indexStart = queue[0]; + char indexEnd = queue[1]; + push(indexStart, indexEnd, queue, x, y, z); + } + + private void push(char indexStart, char indexEnd, char[] queue, int x, int y, int z) { + char index = getLocalIndex(x, y, z); + if (indexStart > 2) { + queue[0] = --indexStart; + queue[indexStart] = index; + } else { + queue[indexEnd] = index; + queue[0] = ++indexEnd; } - if (queue[1] >= queue.length) { - queue[1] = 2; - } - queue[queue[1]++] = getLocalIndex(x & 15, y, z & 15); } public void process() { LongArraySet set = new LongArraySet(); while (!queues.isEmpty()) { - ObjectIterator> iter = queues.long2ObjectEntrySet().fastIterator(); - Long2ObjectMap.Entry entry = iter.next(); - long index = entry.getLongKey(); - int X = MathMan.unpairIntX(index); - int Z = MathMan.unpairIntY(index); +// ObjectIterator> iter = queues.long2ObjectEntrySet().fastIterator(); +// Long2ObjectMap.Entry entry = iter.next(); +// long index = entry.getLongKey(); +// int X = MathMan.unpairIntX(index); +// int Z = MathMan.unpairIntY(index); +// // check that adjacent chunks aren;t being processed +// +// char[] queue = entry.getValue(); +// long[][] visit = visits.get(index); +// if (visit == null) { +// visits.put(index, visit = new long[16][]); +// } } } + private ConcurrentLinkedQueue queuePool = new ConcurrentLinkedQueue<>(); + + private char[] newQueue() { + char[] arr = queuePool.poll(); + if (arr != null) { + arr[0] = 2; + arr[1] = 2; + return arr; + } + return new char[4096]; + } + + public void process4(int xx, int yy, int zz, char[] queue, long[] visit) { + char index; + while ((index = queue[0]) != queue[1]) { + queue[0]++; + + char triple = queue[index]; + int x = index & 15; + int z = (index >> 4) & 15; + int y = index >> 8; + + int absX = xx + x; + int absY = yy + y; + int absZ = zz + z; + + apply(xx + x, yy + y, zz + z); + + int x1 = x, x2 = x; + + // find start of scan-line + int i1 = index; + while (true) { + if (x1 < 0) { + // queue in west chunk + break; + } + if (get(visit, i1)) break; + // visit + set(visit, i1); + + i1--; + x1--; + } + i1++; + x1++; + + // find end of scan-line + int i2 = index; + while (true) { + if (x2 > 15) { + // queue in east chunk + break; + } + if (get(visit, i2)) break; + set(visit, i2); + i2++; + x2++; + } + i2--; + x2--; + + // find start + } + } + + public void apply(int x, int y, int z) { + + } + + public void process4(int X, int Z, char[][] queues, long[][] visit) { + int xx = X << 4; + int zz = Z << 4; + + // TODO fetch instead of create + final BlockVector3[] dirs = directions; + char[][] dirQueues = new char[directions.length][]; + while (true) { + boolean empty = true; + for (int layer = 0; layer < 16; layer++) { + char[] queue = queues[layer]; + if (queue == null) continue; + char index; + while ((index = queue[0]) != queue[1]) { + queue[0]++; + + char triple = queue[index]; + int x = index & 15; + int z = (index >> 4) & 15; + int y = index >> 8; + } + queuePool.add(queue); + queues[layer] = null; + continue; + } + + if (empty) break; + } + // empty queues + +// while (indexStart != indexEnd) { +// char index = queue[indexStart++]; +// byte dirs = 0xF; +// int x = index & 15; +// int z = (index >> 4) & 15; +// int y = index >> 8; +// +// int layer = y >> 4; +// long[] visitBits = visit[layer]; +// +// int x1 = x; +// int x2 = x; +// +// // find start of scan-line +// int i1 = index; +// while (true) { +// if (x1 < 0) { +// // queue in adjacent chunk +// break; +// } +// if (get(visitBits, i1--)) break; +// x1--; +// } +// i1++; +// x1++; +// +// // find end of scan-line +// int i2 = index; +// while (true) { +// if (x2 > 15) { +// // queue in adjacent chunk +// break; +// } +// if (get(visitBits, i2++)) break; +// x2++; +// } +// i2--; +// x2--; +// +// boolean scanUp = false; +// boolean scanDown = false; +// boolean scanLeft = false; +// boolean scanRight = false; +// +// for (int i = i1; i <= i2; i++) { +// if (!scanDown && y > 0 && ) +// } +// +// for (int i=x1; i<=x2; i++) { // find scan-lines above this one +// if (!inScanLine && y>0 && ip.getPixel(i,y-1)==color) +// {push(i, y-1); inScanLine = true;} +// else if (inScanLine && y>0 && ip.getPixel(i,y-1)!=color) +// inScanLine = false; +// } +// +// inScanLine = false; +// for (int i=x1; i<=x2; i++) { // find scan-lines below this one +// if (!inScanLine && y> 6] |= (1L << (i & 0x3F)); } @@ -144,7 +335,7 @@ public class ScanChunk { } public char getLocalIndex(int x, int y, int z) { - return (char) (y + (x << 8) + (z << 12)); + return (char) (x + (z << 4) + (y << 8)); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java index f465f4142..bb4d0dc3e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java @@ -29,58 +29,36 @@ import java.util.Comparator; /** * An immutable 3-dimensional vector. */ -public class BlockVector3 { +public abstract class BlockVector3 { - public static final BlockVector3 ZERO = new BlockVector3(0, 0, 0); - public static final BlockVector3 UNIT_X = new BlockVector3(1, 0, 0); - public static final BlockVector3 UNIT_Y = new BlockVector3(0, 1, 0); - public static final BlockVector3 UNIT_Z = new BlockVector3(0, 0, 1); - public static final BlockVector3 ONE = new BlockVector3(1, 1, 1); + public static final BlockVector3 ZERO = new BlockVector3Imp(0, 0, 0); + public static final BlockVector3 UNIT_X = new BlockVector3Imp(1, 0, 0); + public static final BlockVector3 UNIT_Y = new BlockVector3Imp(0, 1, 0); + public static final BlockVector3 UNIT_Z = new BlockVector3Imp(0, 0, 1); + public static final BlockVector3 ONE = new BlockVector3Imp(1, 1, 1); public static BlockVector3 at(double x, double y, double z) { return at((int) Math.floor(x), (int) Math.floor(y), (int) Math.floor(z)); } public static BlockVector3 at(int x, int y, int z) { - return new BlockVector3(x, y, z); + return new BlockVector3Imp(x, y, z); } - // thread-safe initialization idiom - private static final class YzxOrderComparator { - private static final Comparator YZX_ORDER = (a, b) -> { - return ComparisonChain.start() - .compare(a.y, b.y) - .compare(a.z, b.z) - .compare(a.x, b.x) - .result(); - }; - } + static final Comparator YZX_ORDER = (a, b) -> ComparisonChain.start() + .compare(a.getY(), b.getY()) + .compare(a.getZ(), b.getZ()) + .compare(a.getX(), b.getX()) + .result(); /** * Returns a comparator that sorts vectors first by Y, then Z, then X. - * + * *

* Useful for sorting by chunk block storage order. */ public static Comparator sortByCoordsYzx() { - return YzxOrderComparator.YZX_ORDER; - } - - protected int x, y, z; - - protected BlockVector3(){} - - /** - * Construct an instance. - * - * @param x the X coordinate - * @param y the Y coordinate - * @param z the Z coordinate - */ - protected BlockVector3(int x, int y, int z) { - this.x = x; - this.y = y; - this.z = z; + return YZX_ORDER; } public MutableBlockVector3 setComponents(double x, double y, double z) { @@ -92,27 +70,27 @@ public class BlockVector3 { } public MutableBlockVector3 mutX(double x) { - return new MutableBlockVector3((int) x, y, z); + return new MutableBlockVector3((int) x, getY(), getZ()); } public MutableBlockVector3 mutY(double y) { - return new MutableBlockVector3(x, (int) y, z); + return new MutableBlockVector3(getX(), (int) y, getZ()); } public MutableBlockVector3 mutZ(double z) { - return new MutableBlockVector3(x, y, (int) z); + return new MutableBlockVector3(getX(), getY(), (int) z); } public MutableBlockVector3 mutX(int x) { - return new MutableBlockVector3(x, y, z); + return new MutableBlockVector3(x, getY(), getZ()); } public MutableBlockVector3 mutY(int y) { - return new MutableBlockVector3(x, y, z); + return new MutableBlockVector3(getX(), y, getZ()); } public MutableBlockVector3 mutZ(int z) { - return new MutableBlockVector3(x, y, z); + return new MutableBlockVector3(getX(), getY(), z); } /** @@ -120,9 +98,7 @@ public class BlockVector3 { * * @return the x coordinate */ - public int getX() { - return x; - } + public abstract int getX(); /** * Get the X coordinate. @@ -130,7 +106,7 @@ public class BlockVector3 { * @return the x coordinate */ public int getBlockX() { - return x; + return getX(); } /** @@ -140,7 +116,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 withX(int x) { - return BlockVector3.at(x, y, z); + return BlockVector3.at(x, getY(), getZ()); } /** @@ -148,9 +124,7 @@ public class BlockVector3 { * * @return the y coordinate */ - public int getY() { - return y; - } + public abstract int getY(); /** * Get the Y coordinate. @@ -158,7 +132,7 @@ public class BlockVector3 { * @return the y coordinate */ public int getBlockY() { - return y; + return getY(); } /** @@ -168,7 +142,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 withY(int y) { - return BlockVector3.at(x, y, z); + return BlockVector3.at(getX(), y, getZ()); } /** @@ -176,9 +150,7 @@ public class BlockVector3 { * * @return the z coordinate */ - public int getZ() { - return z; - } + public abstract int getZ(); /** * Get the Z coordinate. @@ -186,7 +158,7 @@ public class BlockVector3 { * @return the z coordinate */ public int getBlockZ() { - return z; + return getZ(); } /** @@ -196,7 +168,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 withZ(int z) { - return BlockVector3.at(x, y, z); + return BlockVector3.at(getX(), getY(), z); } /** @@ -206,7 +178,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 add(BlockVector3 other) { - return add(other.x, other.y, other.z); + return add(other.getX(), other.getY(), other.getZ()); } /** @@ -218,7 +190,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 add(int x, int y, int z) { - return BlockVector3.at(this.x + x, this.y + y, this.z + z); + return BlockVector3.at(this.getX() + x, this.getY() + y, this.getZ() + z); } /** @@ -229,12 +201,12 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 add(BlockVector3... others) { - int newX = x, newY = y, newZ = z; + int newX = getX(), newY = getY(), newZ = getZ(); for (BlockVector3 other : others) { - newX += other.x; - newY += other.y; - newZ += other.z; + newX += other.getX(); + newY += other.getY(); + newZ += other.getZ(); } return BlockVector3.at(newX, newY, newZ); @@ -248,7 +220,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 subtract(BlockVector3 other) { - return subtract(other.x, other.y, other.z); + return subtract(other.getX(), other.getY(), other.getZ()); } /** @@ -261,7 +233,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 subtract(int x, int y, int z) { - return BlockVector3.at(this.x - x, this.y - y, this.z - z); + return BlockVector3.at(this.getX() - x, this.getY() - y, this.getZ() - z); } /** @@ -272,12 +244,12 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 subtract(BlockVector3... others) { - int newX = x, newY = y, newZ = z; + int newX = getX(), newY = getY(), newZ = getZ(); for (BlockVector3 other : others) { - newX -= other.x; - newY -= other.y; - newZ -= other.z; + newX -= other.getX(); + newY -= other.getY(); + newZ -= other.getZ(); } return BlockVector3.at(newX, newY, newZ); @@ -290,7 +262,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 multiply(BlockVector3 other) { - return multiply(other.x, other.y, other.z); + return multiply(other.getX(), other.getY(), other.getZ()); } /** @@ -302,7 +274,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 multiply(int x, int y, int z) { - return BlockVector3.at(this.x * x, this.y * y, this.z * z); + return BlockVector3.at(this.getX() * x, this.getY() * y, this.getZ() * z); } /** @@ -312,12 +284,12 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 multiply(BlockVector3... others) { - int newX = x, newY = y, newZ = z; + int newX = getX(), newY = getY(), newZ = getZ(); for (BlockVector3 other : others) { - newX *= other.x; - newY *= other.y; - newZ *= other.z; + newX *= other.getX(); + newY *= other.getY(); + newZ *= other.getZ(); } return BlockVector3.at(newX, newY, newZ); @@ -340,7 +312,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 divide(BlockVector3 other) { - return divide(other.x, other.y, other.z); + return divide(other.getX(), other.getY(), other.getZ()); } /** @@ -352,7 +324,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 divide(int x, int y, int z) { - return BlockVector3.at(this.x / x, this.y / y, this.z / z); + return BlockVector3.at(this.getX() / x, this.getY() / y, this.getZ() / z); } /** @@ -380,7 +352,7 @@ public class BlockVector3 { * @return length, squared */ public int lengthSq() { - return x * x + y * y + z * z; + return getX() * getX() + getY() * getY() + getZ() * getZ(); } /** @@ -400,9 +372,9 @@ public class BlockVector3 { * @return distance */ public int distanceSq(BlockVector3 other) { - int dx = other.x - x; - int dy = other.y - y; - int dz = other.z - z; + int dx = other.getX() - getX(); + int dy = other.getY() - getY(); + int dz = other.getZ() - getZ(); return dx * dx + dy * dy + dz * dz; } @@ -414,9 +386,9 @@ public class BlockVector3 { */ public BlockVector3 normalize() { double len = length(); - double x = this.x / len; - double y = this.y / len; - double z = this.z / len; + double x = this.getX() / len; + double y = this.getY() / len; + double z = this.getZ() / len; return BlockVector3.at(x, y, z); } @@ -427,7 +399,7 @@ public class BlockVector3 { * @return the dot product of this and the other vector */ public double dot(BlockVector3 other) { - return x * other.x + y * other.y + z * other.z; + return getX() * other.getX() + getY() * other.getY() + getZ() * other.getZ(); } /** @@ -437,10 +409,10 @@ public class BlockVector3 { * @return the cross product of this and the other vector */ public BlockVector3 cross(BlockVector3 other) { - return new BlockVector3( - y * other.z - z * other.y, - z * other.x - x * other.z, - x * other.y - y * other.x + return new BlockVector3Imp( + getY() * other.getZ() - getZ() * other.getY(), + getZ() * other.getX() - getX() * other.getZ(), + getX() * other.getY() - getY() * other.getX() ); } @@ -452,7 +424,7 @@ public class BlockVector3 { * @return true if the vector is contained */ public boolean containedWithin(BlockVector3 min, BlockVector3 max) { - return x >= min.x && x <= max.x && y >= min.y && y <= max.y && z >= min.z && z <= max.z; + return getX() >= min.getX() && getX() <= max.getX() && getY() >= min.getY() && getY() <= max.getY() && getZ() >= min.getZ() && getZ() <= max.getZ(); } /** @@ -464,11 +436,11 @@ public class BlockVector3 { */ public BlockVector3 clampY(int min, int max) { checkArgument(min <= max, "minimum cannot be greater than maximum"); - if (y < min) { - return BlockVector3.at(x, min, z); + if (getY() < min) { + return BlockVector3.at(getX(), min, getZ()); } - if (y > max) { - return BlockVector3.at(x, max, z); + if (getY() > max) { + return BlockVector3.at(getX(), max, getZ()); } return this; } @@ -512,7 +484,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 abs() { - return BlockVector3.at(Math.abs(x), Math.abs(y), Math.abs(z)); + return BlockVector3.at(Math.abs(getX()), Math.abs(getY()), Math.abs(getZ())); } /** @@ -528,8 +500,8 @@ public class BlockVector3 { */ public BlockVector3 transform2D(double angle, double aboutX, double aboutZ, double translateX, double translateZ) { angle = Math.toRadians(angle); - double x = this.x - aboutX; - double z = this.z - aboutZ; + double x = this.getX() - aboutX; + double z = this.getZ() - aboutZ; double cos = Math.cos(angle); double sin = Math.sin(angle); double x2 = x * cos - z * sin; @@ -537,7 +509,7 @@ public class BlockVector3 { return BlockVector3.at( x2 + aboutX + translateX, - y, + getY(), z2 + aboutZ + translateZ ); } @@ -583,10 +555,10 @@ public class BlockVector3 { * @return minimum */ public BlockVector3 getMinimum(BlockVector3 v2) { - return new BlockVector3( - Math.min(x, v2.x), - Math.min(y, v2.y), - Math.min(z, v2.z) + return new BlockVector3Imp( + Math.min(getX(), v2.getX()), + Math.min(getY(), v2.getY()), + Math.min(getZ(), v2.getZ()) ); } @@ -597,10 +569,10 @@ public class BlockVector3 { * @return maximum */ public BlockVector3 getMaximum(BlockVector3 v2) { - return new BlockVector3( - Math.max(x, v2.x), - Math.max(y, v2.y), - Math.max(z, v2.z) + return new BlockVector3Imp( + Math.max(getX(), v2.getX()), + Math.max(getY(), v2.getY()), + Math.max(getZ(), v2.getZ()) ); } @@ -610,31 +582,34 @@ public class BlockVector3 { * @return a new {@link BlockVector2} */ public BlockVector2 toBlockVector2() { - return BlockVector2.at(x, z); + return BlockVector2.at(getX(), getZ()); } public Vector3 toVector3() { - return Vector3.at(x, y, z); + return Vector3.at(getX(), getY(), getZ()); } @Override - public boolean equals(Object obj) { + public final boolean equals(Object obj) { if (!(obj instanceof BlockVector3)) { return false; } - BlockVector3 other = (BlockVector3) obj; - return other.x == this.x && other.y == this.y && other.z == this.z; + return equals((BlockVector3) obj); + } + + public final boolean equals(BlockVector3 other) { + return other.getX() == this.getX() && other.getY() == this.getY() && other.getZ() == this.getZ(); } @Override public int hashCode() { - return (x ^ (z << 12)) ^ (y << 24); + return (getX() ^ (getZ() << 12)) ^ (getY() << 24); } @Override public String toString() { - return "(" + x + ", " + y + ", " + z + ")"; + return "(" + getX() + ", " + getY() + ", " + getZ() + ")"; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3Imp.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3Imp.java new file mode 100644 index 000000000..69a148401 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3Imp.java @@ -0,0 +1,87 @@ +/* + * 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.math; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.collect.ComparisonChain; +import com.sk89q.worldedit.math.transform.AffineTransform; + +import java.util.Comparator; + +/** + * An immutable 3-dimensional vector. + */ +public class BlockVector3Imp extends BlockVector3 { + + public static final BlockVector3Imp ZERO = new BlockVector3Imp(0, 0, 0); + public static final BlockVector3Imp UNIT_X = new BlockVector3Imp(1, 0, 0); + public static final BlockVector3Imp UNIT_Y = new BlockVector3Imp(0, 1, 0); + public static final BlockVector3Imp UNIT_Z = new BlockVector3Imp(0, 0, 1); + public static final BlockVector3Imp ONE = new BlockVector3Imp(1, 1, 1); + + public static BlockVector3Imp at(double x, double y, double z) { + return at((int) Math.floor(x), (int) Math.floor(y), (int) Math.floor(z)); + } + + public static BlockVector3Imp at(int x, int y, int z) { + return new BlockVector3Imp(x, y, z); + } + + private final int x, y, z; + + /** + * Construct an instance. + * + * @param x the X coordinate + * @param y the Y coordinate + * @param z the Z coordinate + */ + protected BlockVector3Imp(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public final int getX() { + return x; + } + + @Override + public final int getY() { + return y; + } + + @Override + public final int getZ() { + return z; + } + + @Override + public int hashCode() { + return (getX() ^ (getZ() << 12)) ^ (getY() << 24); + } + + @Override + public String toString() { + return "(" + getX() + ", " + getY() + ", " + getZ() + ")"; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableBlockVector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableBlockVector3.java index 89ee154f5..f065b905b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableBlockVector3.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableBlockVector3.java @@ -9,6 +9,14 @@ public class MutableBlockVector3 extends BlockVector3 { } }; + public static MutableBlockVector3 at(double x, double y, double z) { + return at((int) Math.floor(x), (int) Math.floor(y), (int) Math.floor(z)); + } + + public static MutableBlockVector3 at(int x, int y, int z) { + return new MutableBlockVector3(x, y, z); + } + public static MutableBlockVector3 get(int x, int y, int z) { return MUTABLE_CACHE.get().setComponents(x, y, z); } @@ -16,15 +24,19 @@ public class MutableBlockVector3 extends BlockVector3 { public MutableBlockVector3() {} public MutableBlockVector3(BlockVector3 other) { - super(other.getX(), other.getY(), other.getZ()); + this(other.getX(), other.getY(), other.getZ()); } public MutableBlockVector3 setComponents(BlockVector3 other) { return setComponents(other.getBlockX(), other.getBlockY(), other.getBlockZ()); } + private int x,y,z; + public MutableBlockVector3(int x, int y, int z) { - super(x, y, z); + this.x = x; + this.y = y; + this.z = z; } @Override @@ -35,6 +47,21 @@ public class MutableBlockVector3 extends BlockVector3 { return this; } + @Override + public final int getX() { + return x; + } + + @Override + public final int getY() { + return y; + } + + @Override + public final int getZ() { + return z; + } + @Override public MutableBlockVector3 mutX(double x) { this.x = (int) x; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java index cc5b4be68..cbfb6be0e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java @@ -91,11 +91,6 @@ public abstract class AbstractWorld implements World { return false; } - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return getBlock(position); - } - @Override public boolean queueBlockBreakEffect(Platform server, BlockVector3 position, BlockType blockType, double priority) { if (taskId == -1) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java index 886dee7cc..18ca8fbdf 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.world.block; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; @@ -47,9 +48,7 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public class BaseBlock implements BlockStateHolder { private final BlockState blockState; - - @Nullable - protected CompoundTag nbtData; + private final CompoundTag nbtData; @Deprecated public BaseBlock() { @@ -83,6 +82,7 @@ public class BaseBlock implements BlockStateHolder { public BaseBlock(BlockState blockState) { this.blockState = blockState; + nbtData = null; } /** @@ -157,7 +157,7 @@ public class BaseBlock implements BlockStateHolder { @Override public void setNbtData(@Nullable CompoundTag nbtData) { - this.nbtData = nbtData; + throw new UnsupportedOperationException("Immutable"); } /** @@ -202,7 +202,7 @@ public class BaseBlock implements BlockStateHolder { } @Override - public int getOrdinal() { + public final int getOrdinal() { return blockState.getOrdinal(); } @@ -227,6 +227,10 @@ public class BaseBlock implements BlockStateHolder { } } + public BlockState toBlockState() { + return blockState; + } + @Override public int hashCode() { return getOrdinal(); @@ -246,7 +250,12 @@ public class BaseBlock implements BlockStateHolder { return extent.setBlock(set, this); } - @Override + @Override + public void apply(FilterBlock block) { + block.setFullBlock(this); + } + + @Override public boolean hasNbtData() { return this.nbtData != null; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index 3aef40e27..041faa865 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.world.block; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.command.SuggestInputParseException; import com.boydti.fawe.object.string.MutableCharSequence; import com.boydti.fawe.util.StringMan; @@ -62,7 +63,7 @@ public class BlockState implements BlockStateHolder, FawePattern { this.internalId = internalId; this.ordinal = ordinal; this.ordinalChar = (char) ordinal; - this.emptyBaseBlock = new BaseBlock(this); + this.emptyBaseBlock = new ImmutableBaseBlock(this); } /** @@ -218,6 +219,11 @@ public class BlockState implements BlockStateHolder, FawePattern { return extent.setBlock(set, this); } + @Override + public final void apply(FilterBlock block) { + block.setOrdinal(ordinal); + } + @Override public BaseBlock apply(BlockVector3 position) { return this.toBaseBlock(); @@ -333,7 +339,7 @@ public class BlockState implements BlockStateHolder, FawePattern { } @Override - public int getOrdinal() { + public final int getOrdinal() { return this.ordinal; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java index 7a5f89f73..de459a6db 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.world.block; import static com.google.common.base.Preconditions.checkArgument; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.util.ReflectionUtils; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; @@ -45,7 +46,7 @@ import java.util.*; import java.util.stream.Collectors; import java.util.stream.IntStream; -public class BlockType implements FawePattern { +public final class BlockType implements FawePattern { private final String id; private final BlockTypes.Settings settings; @@ -179,7 +180,7 @@ public class BlockType implements FawePattern { * * @return The default state */ - public BlockState getDefaultState() { + public final BlockState getDefaultState() { return this.settings.defaultState; } @@ -306,6 +307,11 @@ public class BlockType implements FawePattern { return this.getDefaultState().toBaseBlock(); } + @Override + public final void apply(FilterBlock block) { + block.setOrdinal(getDefaultState().getOrdinal()); + } + public Mask toMask(Extent extent) { return new SingleBlockTypeMask(extent, this); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/ImmutableBaseBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/ImmutableBaseBlock.java new file mode 100644 index 000000000..f738aa6f7 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/ImmutableBaseBlock.java @@ -0,0 +1,28 @@ +package com.sk89q.worldedit.world.block; + +import com.boydti.fawe.beta.FilterBlock; +import com.sk89q.jnbt.CompoundTag; + +import javax.annotation.Nullable; + +public final class ImmutableBaseBlock extends BaseBlock { + public ImmutableBaseBlock(BlockState blockState) { + super(blockState); + } + + @Nullable + @Override + public CompoundTag getNbtData() { + return null; + } + + @Override + public boolean hasNbtData() { + return false; + } + + @Override + public final void apply(FilterBlock block) { + block.setOrdinal(getOrdinal()); + } +} From 43a654176330cc9f0fc76002f7c5fb952d800f0e Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Mon, 13 May 2019 00:21:01 +1000 Subject: [PATCH 21/54] shift some code to EditSessionBuilder --- .../com/boydti/fawe/object/HistoryExtent.java | 8 +- .../brush/visualization/VisualExtent.java | 2 +- .../fawe/object/extent/FaweRegionExtent.java | 57 +--- .../boydti/fawe/util/EditSessionBuilder.java | 208 +++++++++----- .../java/com/sk89q/worldedit/EditSession.java | 267 +++--------------- .../worldedit/command/tool/BrushTool.java | 12 +- .../extent/AbstractDelegateExtent.java | 4 +- 7 files changed, 200 insertions(+), 358 deletions(-) diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/HistoryExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/HistoryExtent.java index e66e505c6..c52ecf6f8 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/HistoryExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/HistoryExtent.java @@ -35,7 +35,6 @@ public class HistoryExtent extends AbstractDelegateExtent { private FaweChangeSet changeSet; private final FaweQueue queue; - private final EditSession session; /** * Create a new instance. @@ -43,12 +42,11 @@ public class HistoryExtent extends AbstractDelegateExtent { * @param extent the extent * @param changeSet the change set */ - public HistoryExtent(final EditSession session, final Extent extent, final FaweChangeSet changeSet, FaweQueue queue) { + public HistoryExtent(final Extent extent, final FaweChangeSet changeSet, FaweQueue queue) { super(extent); checkNotNull(changeSet); this.queue = queue; this.changeSet = changeSet; - this.session = session; } public FaweChangeSet getChangeSet() { @@ -61,9 +59,9 @@ public class HistoryExtent extends AbstractDelegateExtent { @Override public > boolean setBlock(int x, int y, int z, B block) throws WorldEditException { - BaseBlock previous = queue.getFullBlock(mutable.setComponents(x, y, z)).toBaseBlock(); + BaseBlock previous = queue.getFullBlock(x, y, z); if (previous.getInternalId() == block.getInternalId()) { - if (!previous.hasNbtData() && (block instanceof BaseBlock && !((BaseBlock)block).hasNbtData())) { + if (!previous.hasNbtData() && (block instanceof BaseBlock && !block.hasNbtData())) { return false; } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualExtent.java index c8b29f3ef..4b8eeb0ba 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualExtent.java @@ -40,7 +40,7 @@ public class VisualExtent extends AbstractDelegateExtent { @Override public boolean setBlock(int x, int y, int z, BlockStateHolder block) throws WorldEditException { - BlockStateHolder previous = super.getLazyBlock(x, y, z); + BlockStateHolder previous = super.getBlock(x, y, z); int cx = x >> 4; int cz = z >> 4; long chunkPair = MathMan.pairInt(cx, cz); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/FaweRegionExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/FaweRegionExtent.java index 3c6cb801b..6e9306b07 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/FaweRegionExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/FaweRegionExtent.java @@ -56,17 +56,6 @@ public abstract class FaweRegionExtent extends ResettableExtent { return contains(p.getBlockX(), p.getBlockZ()); } - @Override - public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { - if (!contains(location)) { - if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); - } - return false; - } - return super.setBlock(location, block); - } - @Override public > boolean setBlock(int x, int y, int z, B block) throws WorldEditException { if (!contains(x, y, z)) { @@ -78,17 +67,6 @@ public abstract class FaweRegionExtent extends ResettableExtent { return super.setBlock(x, y, z, block); } - @Override - public boolean setBiome(BlockVector2 position, BiomeType biome) { - if (!contains(position)) { - if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); - } - return false; - } - return super.setBiome(position, biome); - } - @Override public boolean setBiome(int x, int y, int z, BiomeType biome) { if (!contains(x, y, z)) { @@ -110,7 +88,18 @@ public abstract class FaweRegionExtent extends ResettableExtent { } return super.getBiome(position); } - + + @Override + public BiomeType getBiome(int x, int z) { + if (!contains(x, z)) { + if (!limit.MAX_FAILS()) { + WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + } + return null; + } + return super.getBiome(x, z); + } + @Override public BaseBlock getFullBlock(BlockVector3 position) { if (!contains(position)) { @@ -133,28 +122,6 @@ public abstract class FaweRegionExtent extends ResettableExtent { return super.getBlock(position); } - @Override - public BlockState getLazyBlock(BlockVector3 position) { - if (!contains(position)) { - if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); - } - return EditSession.nullBlock; - } - return super.getLazyBlock(position); - } - - @Override - public BlockState getLazyBlock(int x, int y, int z) { - if (!contains(x, y, z)) { - if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); - } - return EditSession.nullBlock; - } - return super.getLazyBlock(x, y, z); - } - @Override public int getBlockLight(int x, int y, int z) { if (!contains(x, y, z)) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java b/worldedit-core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java index 81e11ddc5..0c7bce19e 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java @@ -79,6 +79,12 @@ public class EditSessionBuilder { this.worldName = Fawe.imp().getWorldName(world); } + public EditSessionBuilder(World world, String worldName) { + if (world == null && worldName == null) throw new NullPointerException("Both world and worldname cannot be null"); + this.world = world; + this.worldName = worldName; + } + public EditSessionBuilder(@Nonnull String worldName) { checkNotNull(worldName); this.worldName = worldName; @@ -253,8 +259,16 @@ public class EditSessionBuilder { return extent; } - public EditSessionBuilder commit() { - // reset + private FaweChangeSet changeTask; + private AbstractDelegateExtent extent; + private int maxY; + private HistoryExtent history; + private AbstractDelegateExtent bypassHistory; + private AbstractDelegateExtent bypassAll; + + public EditSessionBuilder compile() { + if (extent != null) return this; + wrapped = false; // if (worldName == null) { @@ -336,9 +350,6 @@ public class EditSessionBuilder { // If the edit uses items from the inventory we can't use a delayed task && this.blockBag == null; } -// if (Settings.IMP.EXPERIMENTAL.ANVIL_QUEUE_MODE && !(queue instanceof MCAQueue)) { -// queue = new MCAQueue(queue); -// } if (!Settings.IMP.QUEUE.PROGRESS.DISPLAY.equalsIgnoreCase("false") && player != null) { switch (Settings.IMP.QUEUE.PROGRESS.DISPLAY.toLowerCase()) { case "chat": @@ -350,76 +361,131 @@ public class EditSessionBuilder { this.queue.setProgressTask(new DefaultProgressTracker(player)); } } -// this.bypassAll = wrapExtent(new FastWorldEditExtent(world, queue), eventBus, event, EditSession.Stage.BEFORE_CHANGE); -// this.bypassHistory = (this.extent = wrapExtent(bypassAll, eventBus, event, EditSession.Stage.BEFORE_REORDER)); -// if (!this.fastMode || changeSet != null) { -// if (changeSet == null) { -// if (Settings.IMP.HISTORY.USE_DISK) { -// UUID uuid = player == null ? EditSession.CONSOLE : player.getUUID(); -// if (Settings.IMP.HISTORY.USE_DATABASE) { -// changeSet = new RollbackOptimizedHistory(world, uuid); -// } else { -// changeSet = new DiskStorageHistory(world, uuid); + this.bypassAll = wrapExtent(new FastWorldEditExtent(world, queue), eventBus, event, EditSession.Stage.BEFORE_CHANGE); + this.bypassHistory = (this.extent = wrapExtent(bypassAll, eventBus, event, EditSession.Stage.BEFORE_REORDER)); + if (!this.fastmode || changeSet != null) { + if (changeSet == null) { + if (Settings.IMP.HISTORY.USE_DISK) { + UUID uuid = player == null ? EditSession.CONSOLE : player.getUUID(); + if (Settings.IMP.HISTORY.USE_DATABASE) { + changeSet = new RollbackOptimizedHistory(world, uuid); + } else { + changeSet = new DiskStorageHistory(world, uuid); + } + } else if (combineStages && Settings.IMP.HISTORY.COMPRESSION_LEVEL == 0 && !(queue instanceof MCAQueue)) { + changeSet = new CPUOptimizedChangeSet(world); + } else { + changeSet = new MemoryOptimizedHistory(world); + } + } + if (this.limit.SPEED_REDUCTION > 0) { + this.bypassHistory = new SlowExtent(this.bypassHistory, this.limit.SPEED_REDUCTION); + } + if (changeSet instanceof NullChangeSet && Fawe.imp().getBlocksHubApi() != null && player != null) { + changeSet = LoggingChangeSet.wrap(player, changeSet); + } + if (!(changeSet instanceof NullChangeSet)) { + if (!(changeSet instanceof LoggingChangeSet) && player != null && Fawe.imp().getBlocksHubApi() != null) { + changeSet = LoggingChangeSet.wrap(player, changeSet); + } + if (this.blockBag != null) { + changeSet = new BlockBagChangeSet(changeSet, blockBag, limit.INVENTORY_MODE == 1); + } + if (combineStages) { + changeTask = changeSet; + changeSet.addChangeTask(queue); + } else { + this.extent = (history = new HistoryExtent(bypassHistory, changeSet, queue)); +// if (this.blockBag != null) { +// this.extent = new BlockBagExtent(this.extent, blockBag, limit.INVENTORY_MODE == 1); // } -// } else if (combineStages && Settings.IMP.HISTORY.COMPRESSION_LEVEL == 0 && !(queue instanceof MCAQueue)) { -// changeSet = new CPUOptimizedChangeSet(world); -// } else { -// changeSet = new MemoryOptimizedHistory(world); -// } -// } -// if (this.limit.SPEED_REDUCTION > 0) { -// this.bypassHistory = new SlowExtent(this.bypassHistory, this.limit.SPEED_REDUCTION); -// } -// if (changeSet instanceof NullChangeSet && Fawe.imp().getBlocksHubApi() != null && player != null) { -// changeSet = LoggingChangeSet.wrap(player, changeSet); -// } -// if (!(changeSet instanceof NullChangeSet)) { -// if (!(changeSet instanceof LoggingChangeSet) && player != null && Fawe.imp().getBlocksHubApi() != null) { -// changeSet = LoggingChangeSet.wrap(player, changeSet); -// } -// if (this.blockBag != null) { -// changeSet = new BlockBagChangeSet(changeSet, blockBag, limit.INVENTORY_MODE == 1); -// } -// if (combineStages) { -// changeTask = changeSet; -// changeSet.addChangeTask(queue); -// } else { -// this.extent = (history = new HistoryExtent(this, bypassHistory, changeSet, queue)); -//// if (this.blockBag != null) { -//// this.extent = new BlockBagExtent(this.extent, blockBag, limit.INVENTORY_MODE == 1); -//// } -// } -// } -// } -// if (allowedRegions == null) { -// if (player != null && !player.hasPermission("fawe.bypass") && !player.hasPermission("fawe.bypass.regions") && !(queue instanceof VirtualWorld)) { -// allowedRegions = player.getCurrentRegions(); -// } -// } -// this.maxY = getWorld() == null ? 255 : world.getMaxY(); -// if (allowedRegions != null) { -// if (allowedRegions.length == 0) { -// this.extent = new NullExtent(this.extent, BBC.WORLDEDIT_CANCEL_REASON_NO_REGION); -// } else { -// this.extent = new ProcessedWEExtent(this.extent, this.limit); -// if (allowedRegions.length == 1) { -// Region region = allowedRegions[0]; -// this.extent = new SingleRegionExtent(this.extent, this.limit, allowedRegions[0]); -// } else { -// this.extent = new MultiRegionExtent(this.extent, this.limit, allowedRegions); -// } -// } -// } else { -// this.extent = new HeightBoundExtent(this.extent, this.limit, 0, maxY); -// } -// if (this.limit.STRIP_NBT != null && !this.limit.STRIP_NBT.isEmpty()) { -// this.extent = new StripNBTExtent(this.extent, this.limit.STRIP_NBT); -// } -// this.extent = wrapExtent(this.extent, bus, event, Stage.BEFORE_HISTORY); + } + } + } + if (allowedRegions == null) { + if (player != null && !player.hasPermission("fawe.bypass") && !player.hasPermission("fawe.bypass.regions") && !(queue instanceof VirtualWorld)) { + allowedRegions = player.getCurrentRegions(); + } + } + this.maxY = world == null ? 255 : world.getMaxY(); + if (allowedRegions != null) { + if (allowedRegions.length == 0) { + this.extent = new NullExtent(this.extent, BBC.WORLDEDIT_CANCEL_REASON_NO_REGION); + } else { + this.extent = new ProcessedWEExtent(this.extent, this.limit); + if (allowedRegions.length == 1) { + this.extent = new SingleRegionExtent(this.extent, this.limit, allowedRegions[0]); + } else { + this.extent = new MultiRegionExtent(this.extent, this.limit, allowedRegions); + } + } + } else { + this.extent = new HeightBoundExtent(this.extent, this.limit, 0, maxY); + } + if (this.limit.STRIP_NBT != null && !this.limit.STRIP_NBT.isEmpty()) { + this.extent = new StripNBTExtent(this.extent, this.limit.STRIP_NBT); + } + this.extent = wrapExtent(this.extent, eventBus, event, EditSession.Stage.BEFORE_HISTORY); return this; } public EditSession build() { - return new EditSession(worldName, world, queue, player, limit, changeSet, allowedRegions, autoQueue, fastmode, checkMemory, combineStages, blockBag, eventBus, event); + return new EditSession(this); + } + + public Extent getExtent() { + return extent; + } + + public World getWorld() { + return world; + } + + public String getWorldName() { + return worldName; + } + + public FaweQueue getQueue() { + return queue; + } + + public boolean isWrapped() { + return wrapped; + } + + public boolean hasFastMode() { + return fastmode; + } + + public HistoryExtent getHistory() { + return history; + } + + public AbstractDelegateExtent getBypassHistory() { + return bypassHistory; + } + + public AbstractDelegateExtent getBypassAll() { + return bypassAll; + } + + public FaweLimit getLimit() { + return limit; + } + + public FawePlayer getPlayer() { + return player; + } + + public FaweChangeSet getChangeTask() { + return changeTask; + } + + public BlockBag getBlockBag() { + return blockBag; + } + + public int getMaxY() { + return maxY; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index 1f9aaf8ca..8fb6178f7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -204,19 +204,18 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, private final FaweQueue queue; private final boolean wrapped; private final boolean fastMode; - private final AbstractDelegateExtent extent; private final HistoryExtent history; - private final AbstractDelegateExtent bypassHistory; - private final AbstractDelegateExtent bypassAll; + private AbstractDelegateExtent bypassHistory; + private AbstractDelegateExtent bypassAll; private final FaweLimit originalLimit; private final FaweLimit limit; private final FawePlayer player; private final FaweChangeSet changeTask; - private MutableBlockVector3 mutablebv = new MutableBlockVector3(); + private final MutableBlockVector3 mutablebv = new MutableBlockVector3(); private int changes = 0; - private BlockBag blockBag; + private final BlockBag blockBag; private final int maxY; @@ -234,163 +233,26 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, } public EditSession(@Nullable String worldName, @Nullable World world, @Nullable FaweQueue queue, @Nullable FawePlayer player, @Nullable FaweLimit limit, @Nullable FaweChangeSet changeSet, @Nullable Region[] allowedRegions, @Nullable Boolean autoQueue, @Nullable Boolean fastmode, @Nullable Boolean checkMemory, @Nullable Boolean combineStages, @Nullable BlockBag blockBag, @Nullable EventBus bus, @Nullable EditSessionEvent event) { - super(world); - this.worldName = worldName == null ? world == null ? queue == null ? "" : queue.getWorldName() : Fawe.imp().getWorldName(world) : worldName; - if (world == null && this.worldName != null) world = FaweAPI.getWorld(this.worldName); - this.world = world; - if (bus == null) { - bus = WorldEdit.getInstance().getEventBus(); - } - if (event == null) { - event = new EditSessionEvent(world, player == null ? null : (player.getPlayer()), -1, null); - } - if (player == null && event.getActor() != null) { - player = FawePlayer.wrap(event.getActor()); - } - this.player = player; - if (limit == null) { - if (player == null) { - limit = FaweLimit.MAX; - } else { - limit = player.getLimit(); - } - } - if (autoQueue == null) { - autoQueue = true; - } - if (fastmode == null) { - if (player == null) { - fastmode = !Settings.IMP.HISTORY.ENABLE_FOR_CONSOLE; - } else { - fastmode = player.getSession().hasFastMode(); - } - } - this.fastMode = fastmode; - if (checkMemory == null) { - checkMemory = player != null && !this.fastMode; - } - if (checkMemory) { - if (MemUtil.isMemoryLimitedSlow()) { - if (Perm.hasPermission(player, "worldedit.fast")) { - BBC.WORLDEDIT_OOM_ADMIN.send(player); - } - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_LOW_MEMORY); - } - } - this.originalLimit = limit; - this.blockBag = limit.INVENTORY_MODE != 0 ? blockBag : null; - this.limit = limit.copy(); - - if (queue == null) { - boolean placeChunks = this.fastMode || this.limit.FAST_PLACEMENT; - World unwrapped = WorldWrapper.unwrap(world); - if (unwrapped instanceof FaweQueue) { - queue = (FaweQueue) unwrapped; - } else if (unwrapped instanceof MCAWorld) { - queue = ((MCAWorld) unwrapped).getQueue(); - } else if (player != null && world.equals(player.getWorld())) { - queue = player.getFaweQueue(placeChunks, autoQueue); - } else { - queue = SetQueue.IMP.getNewQueue(world, placeChunks, autoQueue); - } - } - if (combineStages == null) { - combineStages = - // If it's enabled in the settings - Settings.IMP.HISTORY.COMBINE_STAGES - // If fast placement is disabled, it's slower to perform a copy on each chunk - && this.limit.FAST_PLACEMENT - // If the specific queue doesn't support it - && queue.supports(FaweQueue.Capability.CHANGE_TASKS) - // If the edit uses items from the inventory we can't use a delayed task - && this.blockBag == null; - } - if (Settings.IMP.EXPERIMENTAL.ANVIL_QUEUE_MODE && !(queue instanceof MCAQueue)) { - queue = new MCAQueue(queue); - } - this.queue = queue; - this.queue.addEditSession(this); - if (!Settings.IMP.QUEUE.PROGRESS.DISPLAY.equalsIgnoreCase("false") && player != null) { - switch (Settings.IMP.QUEUE.PROGRESS.DISPLAY.toLowerCase()) { - case "chat": - this.queue.setProgressTask(new ChatProgressTracker(player)); - break; - case "title": - case "true": - default: - this.queue.setProgressTask(new DefaultProgressTracker(player)); - } - } - this.bypassAll = wrapExtent(new FastWorldEditExtent(world, queue), bus, event, Stage.BEFORE_CHANGE); - this.bypassHistory = (this.extent = wrapExtent(bypassAll, bus, event, Stage.BEFORE_REORDER)); - if (!this.fastMode || changeSet != null) { - if (changeSet == null) { - if (Settings.IMP.HISTORY.USE_DISK) { - UUID uuid = player == null ? CONSOLE : player.getUUID(); - if (Settings.IMP.HISTORY.USE_DATABASE) { - changeSet = new RollbackOptimizedHistory(world, uuid); - } else { - changeSet = new DiskStorageHistory(world, uuid); - } - } else if (combineStages && Settings.IMP.HISTORY.COMPRESSION_LEVEL == 0 && !(queue instanceof MCAQueue)) { - changeSet = new CPUOptimizedChangeSet(world); - } else { - changeSet = new MemoryOptimizedHistory(world); - } - } - if (this.limit.SPEED_REDUCTION > 0) { - this.bypassHistory = new SlowExtent(this.bypassHistory, this.limit.SPEED_REDUCTION); - } - if (changeSet instanceof NullChangeSet && Fawe.imp().getBlocksHubApi() != null && player != null) { - changeSet = LoggingChangeSet.wrap(player, changeSet); - } - if (!(changeSet instanceof NullChangeSet)) { - if (!(changeSet instanceof LoggingChangeSet) && player != null && Fawe.imp().getBlocksHubApi() != null) { - changeSet = LoggingChangeSet.wrap(player, changeSet); - } - if (this.blockBag != null) { - changeSet = new BlockBagChangeSet(changeSet, blockBag, limit.INVENTORY_MODE == 1); - } - if (combineStages) { - changeTask = changeSet; - changeSet.addChangeTask(queue); - } else { - this.extent = (history = new HistoryExtent(this, bypassHistory, changeSet, queue)); -// if (this.blockBag != null) { -// this.extent = new BlockBagExtent(this.extent, blockBag, limit.INVENTORY_MODE == 1); -// } - } - } - } - if (allowedRegions == null) { - if (player != null && !player.hasPermission("fawe.bypass") && !player.hasPermission("fawe.bypass.regions") && !(queue instanceof VirtualWorld)) { - allowedRegions = player.getCurrentRegions(); - } - } - this.maxY = getWorld() == null ? 255 : world.getMaxY(); - if (allowedRegions != null) { - if (allowedRegions.length == 0) { - this.extent = new NullExtent(this.extent, BBC.WORLDEDIT_CANCEL_REASON_NO_REGION); - } else { - this.extent = new ProcessedWEExtent(this.extent, this.limit); - if (allowedRegions.length == 1) { - Region region = allowedRegions[0]; - this.extent = new SingleRegionExtent(this.extent, this.limit, allowedRegions[0]); - } else { - this.extent = new MultiRegionExtent(this.extent, this.limit, allowedRegions); - } - } - } else { - this.extent = new HeightBoundExtent(this.extent, this.limit, 0, maxY); - } - if (this.limit.STRIP_NBT != null && !this.limit.STRIP_NBT.isEmpty()) { - this.extent = new StripNBTExtent(this.extent, this.limit.STRIP_NBT); - } - this.extent = wrapExtent(this.extent, bus, event, Stage.BEFORE_HISTORY); + this(new EditSessionBuilder(world, worldName).queue(queue).player(player).limit(limit).changeSet(changeSet).allowedRegions(allowedRegions).autoQueue(autoQueue).fastmode(fastmode).checkMemory(checkMemory).combineStages(combineStages).blockBag(blockBag).eventBus(bus).event(event)); } public EditSession(EditSessionBuilder builder) { - super(builder.) + super(builder.compile().getExtent()); + this.world = builder.getWorld(); + this.worldName = builder.getWorldName(); + this.queue = builder.getQueue(); + this.wrapped = builder.isWrapped(); + this.fastMode = builder.hasFastMode(); + this.history = builder.getHistory(); + this.bypassHistory = builder.getBypassHistory(); + this.bypassAll = builder.getBypassAll(); + this.originalLimit = builder.getLimit(); + this.limit = builder.getLimit().copy(); + this.player = builder.getPlayer(); + this.changeTask = builder.getChangeTask(); + this.maxY = builder.getMaxY(); + this.blockBag = builder.getBlockBag(); + } /** @@ -442,7 +304,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, public void resetLimit() { this.limit.set(this.originalLimit); - ExtentTraverser find = new ExtentTraverser(extent).find(ProcessedWEExtent.class); + ExtentTraverser find = new ExtentTraverser(this).find(ProcessedWEExtent.class); if (find != null && find.get() != null) { find.get().setLimit(this.limit); } @@ -481,7 +343,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @return FaweRegionExtent (may be null) */ public FaweRegionExtent getRegionExtent() { - ExtentTraverser traverser = new ExtentTraverser(this.extent).find(FaweRegionExtent.class); + ExtentTraverser traverser = new ExtentTraverser(this).find(FaweRegionExtent.class); return traverser == null ? null : traverser.get(); } @@ -504,18 +366,17 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, } public boolean cancel() { - ExtentTraverser traverser = new ExtentTraverser(this.extent); + ExtentTraverser traverser = new ExtentTraverser(this); NullExtent nullExtent = new NullExtent(world, BBC.WORLDEDIT_CANCEL_REASON_MANUAL); while (traverser != null) { - ExtentTraverser next = traverser.next(); Extent get = traverser.get(); if (get instanceof AbstractDelegateExtent && !(get instanceof NullExtent)) { traverser.setNext(nullExtent); } + ExtentTraverser next = traverser.next(); traverser = next; } bypassHistory = nullExtent; - this.extent = nullExtent; bypassAll = nullExtent; dequeue(); if (!queue.isEmpty()) { @@ -569,46 +430,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, return queue; } - @Deprecated - private AbstractDelegateExtent wrapExtent(final AbstractDelegateExtent extent, final EventBus eventBus, EditSessionEvent event, final Stage stage) { - event = event.clone(stage); - event.setExtent(extent); - eventBus.post(event); - if (event.isCancelled()) { - return new NullExtent(extent, BBC.WORLDEDIT_CANCEL_REASON_MANUAL); - } - final Extent toReturn = event.getExtent(); - if(toReturn instanceof com.sk89q.worldedit.extent.NullExtent) { - return new NullExtent(toReturn, null); - } - if (!(toReturn instanceof AbstractDelegateExtent)) { - Fawe.debug("Extent " + toReturn + " must be AbstractDelegateExtent"); - return extent; - } - if (toReturn != extent) { - String className = toReturn.getClass().getName().toLowerCase(); - for (String allowed : Settings.IMP.EXTENT.ALLOWED_PLUGINS) { - if (className.contains(allowed.toLowerCase())) { - this.wrapped = true; - return (AbstractDelegateExtent) toReturn; - } - } - if (Settings.IMP.EXTENT.DEBUG) { - Fawe.debug("&cPotentially unsafe extent blocked: " + toReturn.getClass().getName()); - Fawe.debug("&8 - &7For area restrictions, it is recommended to use the FaweAPI"); - Fawe.debug("&8 - &7For block logging, it is recommended to use use BlocksHub"); - Fawe.debug("&8 - &7To allow this plugin add it to the FAWE `allowed-plugins` list"); - Fawe.debug("&8 - &7To hide this message set `debug` to false in the FAWE config.yml"); - if (toReturn.getClass().getName().contains("CoreProtect")) { - Fawe.debug("Note on CoreProtect: "); - Fawe.debug(" - If you disable CP's WE logger (CP config) and this still shows, please update CP"); - Fawe.debug(" - Use BlocksHub and set `debug` false in the FAWE config"); - } - } - } - return extent; - } - // pkg private for TracedEditSession only, may later become public API boolean commitRequired() { return false; @@ -910,20 +731,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, return this.blockBag; } - /** - * Set a {@link BlockBag} to use. - * - * @param blockBag the block bag to set, or null to use none - */ - public void setBlockBag(final BlockBag blockBag) { - this.blockBag = blockBag; - } - - @Override - public String toString() { - return super.toString() + ":" + extent; - } - /** * Gets the list of missing blocks and clears the list for the next * operation. @@ -1005,19 +812,19 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, @Override public BiomeType getBiome(final BlockVector2 position) { - return this.extent.getBiome(position); + return this.getExtent().getBiome(position); } @Override public boolean setBiome(final BlockVector2 position, final BiomeType biome) { this.changes++; - return this.extent.setBiome(position, biome); + return this.getExtent().setBiome(position, biome); } @Override public boolean setBiome(int x, int y, int z, BiomeType biome) { this.changes++; - return this.extent.setBiome(x, y, z, biome); + return this.getExtent().setBiome(x, y, z, biome); } @Override @@ -1046,17 +853,17 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, } public BlockState getBlock(int x, int y, int z) { - return extent.getBlock(x, y, z); + return getExtent().getBlock(x, y, z); } @Override public BlockState getBlock(BlockVector3 position) { - return extent.getBlock(position); + return getExtent().getBlock(position); } @Override public BaseBlock getFullBlock(BlockVector3 position) { - return extent.getFullBlock(position); + return getExtent().getFullBlock(position); } /** @@ -1131,7 +938,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, this.changes++; switch (stage) { case BEFORE_HISTORY: - return this.extent.setBlock(position, block); + return this.getExtent().setBlock(position, block); case BEFORE_CHANGE: return this.bypassHistory.setBlock(position, block); case BEFORE_REORDER: @@ -1177,7 +984,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, public > boolean setBlock(BlockVector3 position, B block) throws MaxChangedBlocksException { this.changes++; try { - return this.extent.setBlock(position, block); + return this.getExtent().setBlock(position, block); } catch (MaxChangedBlocksException e) { throw e; } catch (WorldEditException e) { @@ -1188,7 +995,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, public > boolean setBlock(int x, int y, int z, B block) { this.changes++; try { - return this.extent.setBlock(x, y, z, block); + return this.getExtent().setBlock(x, y, z, block); } catch (WorldEditException e) { throw new RuntimeException("Unexpected exception", e); } @@ -1198,7 +1005,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, this.changes++; try { BlockVector3 bv = mutablebv.setComponents(x, y, z); - return pattern.apply(extent, bv, bv); + return pattern.apply(getExtent(), bv, bv); } catch (WorldEditException e) { throw new RuntimeException("Unexpected exception", e); } @@ -1208,7 +1015,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, public boolean setBlock(final BlockVector3 position, final Pattern pattern) { this.changes++; try { - return pattern.apply(this.extent, position, position); + return pattern.apply(this.getExtent(), position, position); } catch (WorldEditException e) { throw new RuntimeException(e); } @@ -1216,7 +1023,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, @SuppressWarnings("deprecation") public int setBlocks(final Set vset, final Pattern pattern) { - RegionVisitor visitor = new RegionVisitor(vset, new BlockReplace(extent, pattern), this); + RegionVisitor visitor = new RegionVisitor(vset, new BlockReplace(getExtent(), pattern), this); Operations.completeBlindly(visitor); changes += visitor.getAffected(); return changes; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java index 269d9b7b5..960be3c95 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java @@ -602,15 +602,19 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool Brush brush = current.getBrush(); if (brush == null) return; FawePlayer fp = FawePlayer.wrap(player); - EditSession editSession = new EditSessionBuilder(player.getWorld()) + EditSessionBuilder builder = new EditSessionBuilder(player.getWorld()) .player(fp) .allowedRegionsEverywhere() .autoQueue(false) .blockBag(null) .changeSetNull() - .combineStages(false) - .build(); - VisualExtent newVisualExtent = new VisualExtent(editSession.getExtent(), editSession.getQueue()); + .combineStages(false); + + builder.commit(); + + EditSession editSession = builder.build(); + + VisualExtent newVisualExtent = new VisualExtent(builder.getExtent(), builder.getQueue()); BlockVector3 position = getPosition(editSession, player); if (position != null) { editSession.setExtent(newVisualExtent); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java index 93b541b2f..3bbaa8ca0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java @@ -100,8 +100,8 @@ public class AbstractDelegateExtent implements Extent, LightingExtent { } @Override - public boolean setBiome(int x, int z, BiomeType biome) { - return extent.setBiome(x, z, biome); + public boolean setBiome(int x, int y, int z, BiomeType biome) { + return extent.setBiome(x, y, z, biome); } /* From da034f9ac4d126498f388b80f392602eaa94ad50 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Mon, 13 May 2019 00:28:48 +1000 Subject: [PATCH 22/54] Use mask for hollow Closes #1298 --- .../java/com/sk89q/worldedit/EditSession.java | 22 +++++++++++-------- .../worldedit/command/RegionCommands.java | 10 +++++++-- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index 8fb6178f7..b4390ec65 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -100,6 +100,7 @@ import com.sk89q.worldedit.function.mask.MaskUnion; import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.function.mask.NoiseFilter2D; import com.sk89q.worldedit.function.mask.RegionMask; +import com.sk89q.worldedit.function.mask.SolidBlockMask; import com.sk89q.worldedit.function.operation.ChangeSetExecutor; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.Operation; @@ -2856,6 +2857,10 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public int hollowOutRegion(final Region region, final int thickness, final Pattern pattern) { + return hollowOutRegion(region, thickness, pattern, new SolidBlockMask(this)); + } + + public int hollowOutRegion(final Region region, final int thickness, final Pattern pattern, Mask mask) { try { final Set outside = new LocalBlockVectorSet(); @@ -2871,22 +2876,22 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, for (int x = minX; x <= maxX; ++x) { for (int y = minY; y <= maxY; ++y) { - recurseHollow(region, BlockVector3.at(x, y, minZ), outside); - recurseHollow(region, BlockVector3.at(x, y, maxZ), outside); + recurseHollow(region, BlockVector3.at(x, y, minZ), outside, mask); + recurseHollow(region, BlockVector3.at(x, y, maxZ), outside, mask); } } for (int y = minY; y <= maxY; ++y) { for (int z = minZ; z <= maxZ; ++z) { - recurseHollow(region, BlockVector3.at(minX, y, z), outside); - recurseHollow(region, BlockVector3.at(maxX, y, z), outside); + recurseHollow(region, BlockVector3.at(minX, y, z), outside, mask); + recurseHollow(region, BlockVector3.at(maxX, y, z), outside, mask); } } for (int z = minZ; z <= maxZ; ++z) { for (int x = minX; x <= maxX; ++x) { - recurseHollow(region, BlockVector3.at(x, minY, z), outside); - recurseHollow(region, BlockVector3.at(x, maxY, z), outside); + recurseHollow(region, BlockVector3.at(x, minY, z), outside, mask); + recurseHollow(region, BlockVector3.at(x, maxY, z), outside, mask); } } @@ -3120,15 +3125,14 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, return returnset; } - private void recurseHollow(Region region, BlockVector3 origin, Set outside) { + private void recurseHollow(Region region, BlockVector3 origin, Set outside, Mask mask) { final LocalBlockVectorSet queue = new LocalBlockVectorSet(); while (!queue.isEmpty()) { Iterator iter = queue.iterator(); while (iter.hasNext()) { BlockVector3 current = iter.next(); iter.remove(); - final BlockState block = getBlock(current); - if (block.getBlockType().getMaterial().isMovementBlocker()) { + if (mask.test(current)) { continue; } 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 9b9939ede..43fdf40df 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 @@ -51,6 +51,7 @@ import com.sk89q.worldedit.function.generator.FloraGenerator; import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.NoiseFilter2D; +import com.sk89q.worldedit.function.mask.SolidBlockMask; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.visitor.LayerVisitor; @@ -784,7 +785,10 @@ public class RegionCommands extends MethodCommands { help = "Hollows out the object contained in this selection.\n" + "Optionally fills the hollowed out part with the given block.\n" + - "Thickness is measured in manhattan distance.", + "Thickness is measured in manhattan distance.\n" + + "Flags:\n" + + " -m Mask, uses a mask to hollow", + min = 0, max = 2 ) @@ -794,9 +798,11 @@ public class RegionCommands extends MethodCommands { @Selection Region region, @Optional("0") @Range(min = 0) int thickness, @Optional("air") Pattern pattern, + @Switch('m') Mask mask, CommandContext context) throws WorldEditException { + Mask finalMask = mask == null ? new SolidBlockMask(editSession) : mask; player.checkConfirmationRegion(() -> { - int affected = editSession.hollowOutRegion(region, thickness, pattern); + int affected = editSession.hollowOutRegion(region, thickness, pattern, finalMask); BBC.VISITOR_BLOCK.send(player, affected); }, getArguments(context), region, context); } From 6bc5b4a823b8ea07358395b830290abf9345adf6 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Wed, 29 May 2019 06:31:22 +1000 Subject: [PATCH 23/54] . --- .../sk89q/worldedit/bukkit/BukkitWorld.java | 5 - .../main/java/com/boydti/fawe/FaweCache.java | 24 + .../boydti/fawe/beta/ArrayFilterBlock.java | 17 +- .../com/boydti/fawe/beta/CharFilterBlock.java | 234 +++--- .../boydti/fawe/beta/ChunkFilterBlock.java | 2 +- .../boydti/fawe/beta/DelegateFilterBlock.java | 697 ++++++++++++++++++ .../com/boydti/fawe/beta/FilterBlock.java | 117 ++- .../java/com/boydti/fawe/beta/IChunk.java | 2 +- .../java/com/boydti/fawe/beta/IChunkSet.java | 10 +- .../com/boydti/fawe/beta/IDelegateChunk.java | 6 +- .../com/boydti/fawe/beta/NorthVector.java | 93 +++ .../boydti/fawe/beta/SimpleFilterBlock.java | 56 +- .../boydti/fawe/beta/SingleFilterBlock.java | 98 +++ .../boydti/fawe/beta/filters/SetFilter.java | 2 +- .../beta/implementation/QueueHandler.java | 3 +- .../implementation/SimpleCharQueueExtent.java | 3 +- .../implementation/holder/ChunkHolder.java | 2 +- .../implementation/holder/DelegateChunk.java | 6 + .../com/boydti/fawe/command/CFICommands.java | 15 +- .../com/boydti/fawe/jnbt/anvil/MCAWorld.java | 2 +- .../fawe/jnbt/anvil/generator/CavesGen.java | 8 +- .../boydti/fawe/object/DataAnglePattern.java | 16 +- .../boydti/fawe/object/brush/LayerBrush.java | 46 +- .../fawe/object/clipboard/EmptyClipboard.java | 2 +- .../object/extent/BlockTranslateExtent.java | 11 +- .../fawe/object/extent/EmptyExtent.java | 2 +- .../object/extent/FastWorldEditExtent.java | 13 +- .../boydti/fawe/object/extent/NullExtent.java | 20 +- .../extent/PositionTransformExtent.java | 11 +- .../fawe/object/extent/ProcessedWEExtent.java | 8 +- .../fawe/object/extent/TemporalExtent.java | 12 +- .../fawe/object/extent/TransformExtent.java | 65 +- .../function/mask/AbstractDelegateMask.java | 1 + .../fawe/object/mask/AdjacentAnyMask2.java | 11 + .../com/boydti/fawe/object/mask/DataMask.java | 4 +- .../boydti/fawe/object/mask/IdDataMask.java | 4 +- .../com/boydti/fawe/object/mask/IdMask.java | 4 +- .../boydti/fawe/object/mask/SurfaceMask.java | 3 - .../object/pattern/AbstractExtentPattern.java | 2 + .../object/pattern/AngleColorPattern.java | 44 +- .../object/pattern/AverageColorPattern.java | 16 +- .../fawe/object/pattern/BiomePattern.java | 11 +- .../fawe/object/pattern/BufferedPattern.java | 39 +- .../fawe/object/pattern/DataPattern.java | 30 +- .../object/pattern/DesaturatePattern.java | 42 +- .../fawe/object/pattern/ExistingPattern.java | 10 +- .../object/pattern/ExpressionPattern.java | 15 +- .../object/pattern/FullClipboardPattern.java | 5 +- .../object/pattern/Linear2DBlockPattern.java | 5 +- .../object/pattern/Linear3DBlockPattern.java | 5 +- .../object/pattern/LinearBlockPattern.java | 4 +- .../fawe/object/pattern/MaskedPattern.java | 24 +- .../fawe/object/pattern/NoXPattern.java | 24 +- .../fawe/object/pattern/NoYPattern.java | 24 +- .../fawe/object/pattern/NoZPattern.java | 23 +- .../fawe/object/pattern/OffsetPattern.java | 28 +- .../fawe/object/pattern/PatternExtent.java | 134 ---- .../fawe/object/pattern/PropertyPattern.java | 12 +- .../pattern/RandomFullClipboardPattern.java | 6 +- .../object/pattern/RandomOffsetPattern.java | 20 +- .../fawe/object/pattern/RelativePattern.java | 22 +- .../fawe/object/pattern/SaturatePattern.java | 18 +- .../fawe/object/pattern/ShadePattern.java | 20 +- .../pattern/SolidRandomOffsetPattern.java | 40 +- .../pattern/SurfaceRandomOffsetPattern.java | 20 +- .../object/queue/FaweQueueDelegateExtent.java | 2 +- .../fawe/object/queue/IDelegateFaweQueue.java | 9 +- .../com/boydti/fawe/util/TextureUtil.java | 33 +- .../com/sk89q/worldedit/CuboidClipboard.java | 4 +- .../java/com/sk89q/worldedit/EditSession.java | 101 ++- .../worldedit/blocks/TileEntityBlock.java | 16 +- .../worldedit/command/PatternCommands.java | 37 +- .../worldedit/command/SelectionCommands.java | 3 +- .../worldedit/command/tool/BrushTool.java | 3 - .../extent/AbstractDelegateExtent.java | 2 +- .../sk89q/worldedit/extent/NullExtent.java | 5 - .../extent/clipboard/BlockArrayClipboard.java | 9 +- .../extent/inventory/BlockBagExtent.java | 2 +- .../transform/BlockTransformExtent.java | 9 +- .../worldedit/function/mask/ABlockMask.java | 84 +++ .../function/mask/AbstractExtentMask.java | 2 +- .../function/mask/BlockCategoryMask.java | 3 +- .../worldedit/function/mask/BlockMask.java | 350 ++++----- .../function/mask/BlockMaskBuilder.java | 93 ++- .../function/mask/BlockStateMask.java | 7 +- .../function/mask/BlockTypeMask.java | 15 +- .../function/mask/BoundedHeightMask.java | 1 + .../function/mask/ExistingBlockMask.java | 3 +- .../function/mask/ExpressionMask.java | 1 + .../worldedit/function/mask/InverseMask.java | 1 + .../mask/InverseSingleBlockStateMask.java | 38 + .../mask/InverseSingleBlockTypeMask.java | 37 + .../sk89q/worldedit/function/mask/Mask.java | 2 - .../function/mask/MaskIntersection.java | 5 +- .../worldedit/function/mask/MaskUnion.java | 1 + .../sk89q/worldedit/function/mask/Masks.java | 4 +- .../worldedit/function/mask/NoiseFilter.java | 6 +- .../worldedit/function/mask/OffsetMask.java | 1 + .../worldedit/function/mask/RegionMask.java | 1 + .../mask/SingleBlockStateBitMask.java | 19 - .../function/mask/SingleBlockStateMask.java | 35 +- .../function/mask/SingleBlockTypeMask.java | 13 +- .../function/mask/SolidBlockMask.java | 33 +- .../function/pattern/BlockPattern.java | 2 +- .../worldedit/function/pattern/Pattern.java | 8 +- .../function/pattern/RandomPattern.java | 5 +- .../pattern/RepeatingExtentPattern.java | 1 + .../sk89q/worldedit/math/BlockVector3.java | 105 +++ .../sk89q/worldedit/math/BlockVector3Imp.java | 7 +- .../worldedit/math/MutableBlockVector3.java | 11 +- .../sk89q/worldedit/math/MutableVector3.java | 11 + .../sk89q/worldedit/world/AbstractWorld.java | 3 +- .../com/sk89q/worldedit/world/NullWorld.java | 17 +- .../sk89q/worldedit/world/SimpleWorld.java | 4 +- .../java/com/sk89q/worldedit/world/World.java | 4 +- .../worldedit/world/block/BaseBlock.java | 22 +- .../worldedit/world/block/BlockState.java | 27 +- .../worldedit/world/block/BlockType.java | 11 +- .../world/block/ImmutableBaseBlock.java | 7 +- 119 files changed, 2184 insertions(+), 1329 deletions(-) create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilterBlock.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/NorthVector.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/SingleFilterBlock.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/object/mask/AdjacentAnyMask2.java delete mode 100644 worldedit-core/src/main/java/com/boydti/fawe/object/pattern/PatternExtent.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ABlockMask.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockStateMask.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockTypeMask.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockStateBitMask.java 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 7d5599ac3..0afe73a47 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 @@ -440,11 +440,6 @@ public class BukkitWorld extends AbstractWorld { } } - @Override - public com.sk89q.worldedit.world.block.BlockState getLazyBlock(BlockVector3 position) { - return getBlock(position); - } - @Override public BaseBlock getFullBlock(BlockVector3 position) { BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); 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 7dba8eb3e..7aac89cdc 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java @@ -6,6 +6,8 @@ import com.boydti.fawe.jnbt.anvil.BitArray4096; import com.boydti.fawe.object.collection.IterableThreadLocal; import com.boydti.fawe.util.MathMan; import com.sk89q.jnbt.*; +import com.sk89q.worldedit.math.MutableBlockVector3; +import com.sk89q.worldedit.math.MutableVector3; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; @@ -33,6 +35,10 @@ public class FaweCache implements Trimable { BLOCK_STATES.clean(); SECTION_BLOCKS.clean(); PALETTE_CACHE.clean(); + PALETTE_TO_BLOCK_CHAR.clean(); + + MUTABLE_VECTOR3.clean(); + MUTABLE_BLOCKVECTOR3.clean(); return false; } @@ -189,6 +195,24 @@ public class FaweCache implements Trimable { } } + /* + * Vector cache + */ + + public static IterableThreadLocal MUTABLE_BLOCKVECTOR3 = new IterableThreadLocal() { + @Override + public MutableBlockVector3 init() { + return new MutableBlockVector3(); + } + }; + + public static IterableThreadLocal MUTABLE_VECTOR3 = new IterableThreadLocal() { + @Override + public MutableVector3 init() { + return new MutableVector3(); + } + }; + /* Conversion methods between JNBT tags and raw values */ diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/ArrayFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/ArrayFilterBlock.java index c005b82f8..8e29eecd2 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/ArrayFilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/ArrayFilterBlock.java @@ -2,13 +2,11 @@ package com.boydti.fawe.beta; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; -import java.awt.image.BufferedImage; -import java.util.concurrent.ThreadLocalRandom; +import javax.annotation.Nullable; public class ArrayFilterBlock extends SimpleFilterBlock { private final char[] blocks; @@ -42,7 +40,7 @@ public class ArrayFilterBlock extends SimpleFilterBlock { } @Override - public void setState(BlockState state) { + public void setBlock(BlockState state) { blocks[index] = state.getOrdinalChar(); } @@ -57,20 +55,23 @@ public class ArrayFilterBlock extends SimpleFilterBlock { } @Override - public BlockState getState() { + public BlockState getBlock() { return BlockTypes.states[ordinal]; } @Override - public BaseBlock getBaseBlock() { - return getState().toBaseBlock(); + public BaseBlock getFullBlock() { + return getBlock().toBaseBlock(); } @Override - public CompoundTag getTag() { + public CompoundTag getNbtData() { return null; } + @Override + public void setNbtData(@Nullable CompoundTag nbtData) {} + @Override public int getX() { return x; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java index 6fcfbea45..15d16d5ff 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java @@ -2,6 +2,7 @@ package com.boydti.fawe.beta; import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.biome.BiomeType; @@ -166,13 +167,18 @@ public class CharFilterBlock extends ChunkFilterBlock { } } + @Override + public void setBiome(BiomeType biome) { + set.setBiome(x, y, z, biome); + } + @Override public void setOrdinal(final int ordinal) { delegate.set(this, (char) ordinal); } @Override - public void setState(final BlockState state) { + public void setBlock(final BlockState state) { delegate.set(this, state.getOrdinalChar()); } @@ -235,28 +241,81 @@ public class CharFilterBlock extends ChunkFilterBlock { } @Override - public final BlockState getState() { + public final BlockState getBlock() { final int ordinal = getArr[index]; return BlockTypes.states[ordinal]; } @Override - public final BaseBlock getBaseBlock() { - final BlockState state = getState(); + public final BaseBlock getFullBlock() { + final BlockState state = getBlock(); final BlockMaterial material = state.getMaterial(); if (material.hasContainer()) { - final CompoundTag tag = get.getTag(x, y + (layer << 4), z); + final CompoundTag tag = get.getTag(x, y + yy, z); return state.toBaseBlock(tag); } return state.toBaseBlock(); } @Override - public final CompoundTag getTag() { + public final CompoundTag getNbtData() { return get.getTag(x, y + (layer << 4), z); } - public final BlockState getOrdinalBelow() { + @Override + public void setNbtData(CompoundTag tag) { + if (tag != null) { + set.setTile(x, y + yy, z, tag); + } + } + + @Override + public boolean hasNbtData() { + final BlockState state = getBlock(); + final BlockMaterial material = state.getMaterial(); + return material.hasContainer(); + } + /* + NORTH(Vector3.at(0, 0, -1), Flag.CARDINAL, 3, 1), + EAST(Vector3.at(1, 0, 0), Flag.CARDINAL, 0, 2), + SOUTH(Vector3.at(0, 0, 1), Flag.CARDINAL, 1, 3), + WEST(Vector3.at(-1, 0, 0), Flag.CARDINAL, 2, 0), + */ + + @Override + public final BlockState getBlockNorth() { + if (z > 0) { + return states[getArr[index - 16]]; + } + return getExtent().getBlock(getX(), getY(), getZ() - 1); + } + + @Override + public final BlockState getBlockEast() { + if (x < 15) { + return states[getArr[index + 1]]; + } + return getExtent().getBlock(getX() + 1, getY(), getZ()); + } + + @Override + public final BlockState getBlockSouth() { + if (z < 15) { + return states[getArr[index + 16]]; + } + return getExtent().getBlock(getX(), getY(), getZ() + 1); + } + + @Override + public final BlockState getBlockWest() { + if (x > 0) { + return states[getArr[index - 1]]; + } + return getExtent().getBlock(getX() - 1, getY(), getZ()); + } + + @Override + public final BlockState getBlockBelow() { if (y > 0) { return states[getArr[index - 256]]; } @@ -268,7 +327,8 @@ public class CharFilterBlock extends ChunkFilterBlock { return BlockTypes.__RESERVED__.getDefaultState(); } - public final BlockState getStateAbove() { + @Override + public final BlockState getBlockAbove() { if (y < 16) { return states[getArr[index + 256]]; } @@ -280,7 +340,8 @@ public class CharFilterBlock extends ChunkFilterBlock { return BlockTypes.__RESERVED__.getDefaultState(); } - public final BlockState getStateRelativeY(final int y) { + @Override + public final BlockState getBlockRelativeY(final int y) { final int newY = this.y + y; final int layerAdd = newY >> 4; switch (layerAdd) { @@ -334,135 +395,34 @@ public class CharFilterBlock extends ChunkFilterBlock { return BlockTypes.__RESERVED__.getDefaultState(); } - public final BlockState getStateRelative(final int x, final int y, final int z) { - final int newX = this.x + x; - final int newZ = this.z + z; - if (newX >> 4 == 0 && newZ >> 4 == 0) { - final int newY = this.y + y; - final int layerAdd = newY >> 4; - switch (layerAdd) { - case 0: - return states[getArr[this.index + ((y << 8) + (z << 4) + x)]]; - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: { - final int newLayer = layer + layerAdd; - if (newLayer < 16) { - final int index = ((newY & 15) << 8) + (newZ << 4) + newX; - return states[get.sections[newLayer].get(get, newLayer, index)]; - } - break; - } - case -1: - case -2: - case -3: - case -4: - case -5: - case -6: - case -7: - case -8: - case -9: - case -10: - case -11: - case -12: - case -13: - case -14: - case -15: { - final int newLayer = layer + layerAdd; - if (newLayer >= 0) { - final int index = ((newY & 15) << 8) + (newZ << 4) + newX; - return states[get.sections[newLayer].get(get, newLayer, index)]; - } - break; - } - } - return BlockTypes.__RESERVED__.getDefaultState(); - } - final int newY = this.y + y + yy; - if (newY >= 0 && newY <= 256) { - return getExtent().getBlock(xx + newX, newY, this.zz + newZ); - } - return BlockTypes.__RESERVED__.getDefaultState(); + + + @Override + public BlockVector3 north() { + return this.north; } - public final BaseBlock getFullBlockRelative(final int x, final int y, final int z) { - final int newX = this.x + x; - final int newZ = this.z + z; - if (newX >> 4 == 0 && newZ >> 4 == 0) { - final int newY = this.y + y; - final int layerAdd = newY >> 4; - BlockState state = BlockTypes.__RESERVED__.getDefaultState(); - switch (layerAdd) { - case 0: - state = states[getArr[this.index + ((y << 8) + (z << 4) + x)]]; - break; - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: { - final int newLayer = layer + layerAdd; - if (newLayer < 16) { - final int index = ((newY & 15) << 8) + (newZ << 4) + newX; - state = states[get.sections[newLayer].get(get, newLayer, index)]; - } - break; - } - case -1: - case -2: - case -3: - case -4: - case -5: - case -6: - case -7: - case -8: - case -9: - case -10: - case -11: - case -12: - case -13: - case -14: - case -15: { - final int newLayer = layer + layerAdd; - if (newLayer >= 0) { - final int index = ((newY & 15) << 8) + (newZ << 4) + newX; - state = states[get.sections[newLayer].get(get, newLayer, index)]; - } - break; - } - } - if (state.getMaterial().hasContainer()) { - final CompoundTag tag = get.getTag(x, y + (layer << 4), z); - return state.toBaseBlock(tag); - } - } - final int newY = this.y + y + yy; - if (newY >= 0 && newY <= 256) { - return getExtent().getFullBlock(xx + newX, newY, this.zz + newZ); - } - return BlockTypes.__RESERVED__.getDefaultState().toBaseBlock(); + @Override + public BlockVector3 east() { + return super.east(); + } + + @Override + public BlockVector3 south() { + return super.south(); + } + + @Override + public BlockVector3 west() { + return super.west(); + } + + /* + Extent + */ + @Override + public char getOrdinalChar(Extent orDefault) { + return getOrdinalChar(); } /* @@ -484,7 +444,7 @@ public class CharFilterBlock extends ChunkFilterBlock { @Override public boolean setBiome(int x, int y, int z, BiomeType biome) { if ((x >> 4) == X && (z >> 4) == Z) { - return set.setBiome(x & 15, z & 15, biome); + return set.setBiome(x & 15, y, z & 15, biome); } return getExtent().setBiome(x, y, z, biome); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFilterBlock.java index 59560279b..8dd9f95f8 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFilterBlock.java @@ -6,7 +6,7 @@ import com.sk89q.worldedit.regions.Region; import javax.annotation.Nullable; -public abstract class ChunkFilterBlock extends FilterBlock { +public abstract class ChunkFilterBlock extends SimpleFilterBlock { public ChunkFilterBlock(Extent extent) { super(extent); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilterBlock.java new file mode 100644 index 000000000..88e1f9340 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilterBlock.java @@ -0,0 +1,697 @@ +package com.boydti.fawe.beta; + +import com.boydti.fawe.jnbt.anvil.generator.GenBase; +import com.boydti.fawe.jnbt.anvil.generator.Resource; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MutableBlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.util.Countable; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; + +import javax.annotation.Nullable; +import java.util.Comparator; +import java.util.List; + +public class DelegateFilterBlock extends FilterBlock { + private final FilterBlock parent; + + public DelegateFilterBlock(FilterBlock parent) { + this.parent = parent; + } + + @Override + public Extent getExtent() { + return parent.getExtent(); + } + + @Override + public void setOrdinal(int ordinal) { + parent.setOrdinal(ordinal); + } + + @Override + public void setBlock(BlockState state) { + parent.setBlock(state); + } + + @Override + public void setFullBlock(BaseBlock block) { + parent.setFullBlock(block); + } + + @Override + public void setNbtData(@Nullable CompoundTag nbtData) { + parent.setNbtData(nbtData); + } + + @Override + public boolean hasNbtData() { + return parent.hasNbtData(); + } + + @Override + public void setBiome(BiomeType biome) { + parent.setBiome(biome); + } + + @Override + public int getOrdinal() { + return parent.getOrdinal(); + } + + @Override + public BlockState getBlock() { + return parent.getBlock(); + } + + @Override + public BaseBlock getFullBlock() { + return parent.getFullBlock(); + } + + @Override + public CompoundTag getNbtData() { + return parent.getNbtData(); + } + + @Override + public BlockVector3 getMinimumPoint() { + return parent.getMinimumPoint(); + } + + @Override + public BlockVector3 getMaximumPoint() { + return parent.getMaximumPoint(); + } + + @Override + public BlockState getBlock(int x, int y, int z) { + return parent.getBlock(x, y, z); + } + + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + return parent.getFullBlock(x, y, z); + } + + @Override + public BlockState getBlockBelow() { + return parent.getBlockBelow(); + } + + @Override + public BlockState getBlockAbove() { + return parent.getBlockAbove(); + } + + @Override + public BlockState getBlockNorth() { + return parent.getBlockNorth(); + } + + @Override + public BlockState getBlockEast() { + return parent.getBlockEast(); + } + + @Override + public BlockState getBlockSouth() { + return parent.getBlockSouth(); + } + + @Override + public BlockState getBlockWest() { + return parent.getBlockWest(); + } + + @Override + public BlockState getBlockRelativeY(int y) { + return parent.getBlockRelativeY(y); + } + + @Override + public int getX() { + return parent.getX(); + } + + @Override + public int getY() { + return parent.getY(); + } + + @Override + public int getZ() { + return parent.getZ(); + } + + @Override + public int getLocalX() { + return parent.getLocalX(); + } + + @Override + public int getLocalY() { + return parent.getLocalY(); + } + + @Override + public int getLocalZ() { + return parent.getLocalZ(); + } + + @Override + public int getChunkX() { + return parent.getChunkX(); + } + + @Override + public int getChunkZ() { + return parent.getChunkZ(); + } + + @Override + public boolean setOrdinal(Extent orDefault, int ordinal) { + return parent.setOrdinal(orDefault, ordinal); + } + + @Override + public boolean setBlock(Extent orDefault, BlockState state) { + return parent.setBlock(orDefault, state); + } + + @Override + public boolean setFullBlock(Extent orDefault, BaseBlock block) { + return parent.setFullBlock(orDefault, block); + } + + @Override + public boolean setBiome(Extent orDefault, BiomeType biome) { + return parent.setBiome(orDefault, biome); + } + + @Override + public int getOrdinal(Extent orDefault) { + return parent.getOrdinal(orDefault); + } + + @Override + public BlockState getBlock(Extent orDefault) { + return parent.getBlock(orDefault); + } + + @Override + public BaseBlock getFullBlock(Extent orDefault) { + return parent.getFullBlock(orDefault); + } + + @Override + public CompoundTag getNbtData(Extent orDefault) { + return parent.getNbtData(orDefault); + } + + @Override + public BlockState getOrdinalBelow(Extent orDefault) { + return parent.getOrdinalBelow(orDefault); + } + + @Override + public BlockState getStateAbove(Extent orDefault) { + return parent.getStateAbove(orDefault); + } + + @Override + public BlockState getStateRelativeY(Extent orDefault, int y) { + return parent.getStateRelativeY(orDefault, y); + } + + public static BlockVector3 at(double x, double y, double z) { + return BlockVector3.at(x, y, z); + } + + public static BlockVector3 at(int x, int y, int z) { + return BlockVector3.at(x, y, z); + } + + public static Comparator sortByCoordsYzx() { + return BlockVector3.sortByCoordsYzx(); + } + + @Override + public MutableBlockVector3 setComponents(double x, double y, double z) { + return parent.setComponents(x, y, z); + } + + @Override + public MutableBlockVector3 setComponents(int x, int y, int z) { + return parent.setComponents(x, y, z); + } + + @Override + public MutableBlockVector3 mutX(double x) { + return parent.mutX(x); + } + + @Override + public MutableBlockVector3 mutY(double y) { + return parent.mutY(y); + } + + @Override + public MutableBlockVector3 mutZ(double z) { + return parent.mutZ(z); + } + + @Override + public MutableBlockVector3 mutX(int x) { + return parent.mutX(x); + } + + @Override + public MutableBlockVector3 mutY(int y) { + return parent.mutY(y); + } + + @Override + public MutableBlockVector3 mutZ(int z) { + return parent.mutZ(z); + } + + @Override + public BlockVector3 toImmutable() { + return parent.toImmutable(); + } + + @Override + public BlockVector3 north() { + return parent.north(); + } + + @Override + public BlockVector3 east() { + return parent.east(); + } + + @Override + public BlockVector3 south() { + return parent.south(); + } + + @Override + public BlockVector3 west() { + return parent.west(); + } + + @Override + public int getBlockX() { + return parent.getBlockX(); + } + + @Override + public BlockVector3 withX(int x) { + return parent.withX(x); + } + + @Override + public int getBlockY() { + return parent.getBlockY(); + } + + @Override + public BlockVector3 withY(int y) { + return parent.withY(y); + } + + @Override + public int getBlockZ() { + return parent.getBlockZ(); + } + + @Override + public BlockVector3 withZ(int z) { + return parent.withZ(z); + } + + @Override + public BlockVector3 add(BlockVector3 other) { + return parent.add(other); + } + + @Override + public BlockVector3 add(int x, int y, int z) { + return parent.add(x, y, z); + } + + @Override + public BlockVector3 add(BlockVector3... others) { + return parent.add(others); + } + + @Override + public BlockVector3 subtract(BlockVector3 other) { + return parent.subtract(other); + } + + @Override + public BlockVector3 subtract(int x, int y, int z) { + return parent.subtract(x, y, z); + } + + @Override + public BlockVector3 subtract(BlockVector3... others) { + return parent.subtract(others); + } + + @Override + public BlockVector3 multiply(BlockVector3 other) { + return parent.multiply(other); + } + + @Override + public BlockVector3 multiply(int x, int y, int z) { + return parent.multiply(x, y, z); + } + + @Override + public BlockVector3 multiply(BlockVector3... others) { + return parent.multiply(others); + } + + @Override + public BlockVector3 multiply(int n) { + return parent.multiply(n); + } + + @Override + public BlockVector3 divide(BlockVector3 other) { + return parent.divide(other); + } + + @Override + public BlockVector3 divide(int x, int y, int z) { + return parent.divide(x, y, z); + } + + @Override + public BlockVector3 divide(int n) { + return parent.divide(n); + } + + @Override + public double length() { + return parent.length(); + } + + @Override + public int lengthSq() { + return parent.lengthSq(); + } + + @Override + public double distance(BlockVector3 other) { + return parent.distance(other); + } + + @Override + public int distanceSq(BlockVector3 other) { + return parent.distanceSq(other); + } + + @Override + public BlockVector3 normalize() { + return parent.normalize(); + } + + @Override + public double dot(BlockVector3 other) { + return parent.dot(other); + } + + @Override + public BlockVector3 cross(BlockVector3 other) { + return parent.cross(other); + } + + @Override + public boolean containedWithin(BlockVector3 min, BlockVector3 max) { + return parent.containedWithin(min, max); + } + + @Override + public BlockVector3 clampY(int min, int max) { + return parent.clampY(min, max); + } + + @Override + public BlockVector3 floor() { + return parent.floor(); + } + + @Override + public BlockVector3 ceil() { + return parent.ceil(); + } + + @Override + public BlockVector3 round() { + return parent.round(); + } + + @Override + public BlockVector3 abs() { + return parent.abs(); + } + + @Override + public BlockVector3 transform2D(double angle, double aboutX, double aboutZ, double translateX, double translateZ) { + return parent.transform2D(angle, aboutX, aboutZ, translateX, translateZ); + } + + @Override + public double toPitch() { + return parent.toPitch(); + } + + @Override + public double toYaw() { + return parent.toYaw(); + } + + @Override + public BlockVector3 getMinimum(BlockVector3 v2) { + return parent.getMinimum(v2); + } + + @Override + public BlockVector3 getMaximum(BlockVector3 v2) { + return parent.getMaximum(v2); + } + + @Override + public char getOrdinalChar(Extent orDefault) { + return parent.getOrdinalChar(orDefault); + } + + @Override + public BlockVector2 toBlockVector2() { + return parent.toBlockVector2(); + } + + @Override + public Vector3 toVector3() { + return parent.toVector3(); + } + + @Override + public int hashCode() { + return parent.hashCode(); + } + + @Override + public String toString() { + return parent.toString(); + } + + @Override + public List getEntities(Region region) { + return parent.getEntities(region); + } + + @Override + public List getEntities() { + return parent.getEntities(); + } + + @Override + @Nullable + public Entity createEntity(Location location, BaseEntity entity) { + return parent.createEntity(location, entity); + } + + @Override + public int getHighestTerrainBlock(int x, int z, int minY, int maxY) { + return parent.getHighestTerrainBlock(x, z, minY, maxY); + } + + @Override + public int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) { + return parent.getHighestTerrainBlock(x, z, minY, maxY, filter); + } + + @Override + public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) { + return parent.getNearestSurfaceLayer(x, z, y, minY, maxY); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) { + return parent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) { + return parent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) { + return parent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) { + return parent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, boolean ignoreAir) { + return parent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir); + } + + @Override + public void addCaves(Region region) throws WorldEditException { + parent.addCaves(region); + } + + @Override + public void generate(Region region, GenBase gen) throws WorldEditException { + parent.generate(region, gen); + } + + @Override + public void addSchems(Region region, Mask mask, List clipboards, int rarity, boolean rotate) throws WorldEditException { + parent.addSchems(region, mask, clipboards, rarity, rotate); + } + + @Override + public void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException { + parent.spawnResource(region, gen, rarity, frequency); + } + + @Override + public boolean contains(BlockVector3 pt) { + return parent.contains(pt); + } + + @Override + public void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException { + parent.addOre(region, mask, material, size, frequency, rarity, minY, maxY); + } + + @Override + public void addOres(Region region, Mask mask) throws WorldEditException { + parent.addOres(region, mask); + } + + @Override + public List> getBlockDistribution(Region region) { + return parent.getBlockDistribution(region); + } + + @Override + public List> getBlockDistributionWithData(Region region) { + return parent.getBlockDistributionWithData(region); + } + + @Override + public BlockArrayClipboard lazyCopy(Region region) { + return parent.lazyCopy(region); + } + + @Override + @Nullable + public Operation commit() { + return parent.commit(); + } + + @Override + public int getMaxY() { + return parent.getMaxY(); + } + + @Override + public BlockState getBlock(BlockVector3 position) { + return parent.getBlock(position); + } + + @Override + public BlockType getBlockType(BlockVector3 position) { + return parent.getBlockType(position); + } + + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + return parent.getFullBlock(position); + } + + @Override + public BiomeType getBiome(BlockVector2 position) { + return parent.getBiome(position); + } + + @Override + public BiomeType getBiome(int x, int z) { + return parent.getBiome(x, z); + } + + @Override + public > boolean setBlock(BlockVector3 position, T block) throws WorldEditException { + return parent.setBlock(position, block); + } + + @Override + public > boolean setBlock(int x, int y, int z, T block) throws WorldEditException { + return parent.setBlock(x, y, z, block); + } + + @Override + public boolean setBiome(BlockVector2 position, BiomeType biome) { + return parent.setBiome(position, biome); + } + + @Override + public boolean setBiome(int x, int y, int z, BiomeType biome) { + return parent.setBiome(x, y, z, biome); + } + + @Override + public String getNbtId() { + return parent.getNbtId(); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java index 007b25a6d..34fc86323 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java @@ -1,38 +1,43 @@ package com.boydti.fawe.beta; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.blocks.TileEntityBlock; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import javax.annotation.Nullable; -public abstract class FilterBlock extends BlockVector3 implements Extent { - private final Extent extent; +import static com.sk89q.worldedit.world.block.BlockTypes.states; - public FilterBlock(Extent extent) { - this.extent = extent; - } - - public final Extent getExtent() { - return extent; - } +public abstract class FilterBlock extends BlockVector3 implements Extent, TileEntityBlock { + public abstract Extent getExtent(); public abstract void setOrdinal(int ordinal); - public abstract void setState(BlockState state); + public abstract void setBlock(BlockState state); public abstract void setFullBlock(BaseBlock block); + public void setBiome(BiomeType biome) { + setBiome(getX(), getY(), getZ(), biome); + } + public abstract int getOrdinal(); - public abstract BlockState getState(); + public abstract BlockState getBlock(); - public abstract BaseBlock getBaseBlock(); + public abstract BaseBlock getFullBlock(); - public abstract CompoundTag getTag(); + public abstract CompoundTag getNbtData(); + + public abstract void setNbtData(@Nullable CompoundTag nbtData); + + public boolean hasNbtData() { + return getNbtData() != null; + } @Override public BlockVector3 getMinimumPoint() { @@ -46,32 +51,40 @@ public abstract class FilterBlock extends BlockVector3 implements Extent { @Override public BlockState getBlock(int x, int y, int z) { - return getStateRelative(x - getX(), y - getY(), z - getZ()); + return getExtent().getBlock(x, y, z); } @Override public BaseBlock getFullBlock(int x, int y, int z) { - return getFullBlockRelative(x - getX(), y - getY(), z - getZ()); + return getExtent().getFullBlock(x, y, z); } - public BlockState getOrdinalBelow() { - return getStateRelative(0, -1, 0); + public BlockState getBlockBelow() { + return getBlock(getX(), getY() - 1, getZ()); } - public BlockState getStateAbove() { - return getStateRelative(0, 1, 0); + public BlockState getBlockAbove() { + return getBlock(getX(), getY() + 1, getZ()); } - public BlockState getStateRelativeY(final int y) { - return getStateRelative(0, y, 0); + public BlockState getBlockNorth() { + return getBlock(getX(), getY(), getZ() - 1); } - public BlockState getStateRelative(final int x, final int y, final int z) { - return getFullBlockRelative(x, y, z).toBlockState(); + public BlockState getBlockEast() { + return getBlock(getX() + 1, getY(), getZ()); } - public BaseBlock getFullBlockRelative(int x, int y, int z) { - return getExtent().getFullBlock(x + getX(), y + getY(), z + getZ()); + public BlockState getBlockSouth() { + return getBlock(getX(), getY(), getZ() + 1); + } + + public BlockState getBlockWest() { + return getBlock(getX() - 1, getY(), getZ()); + } + + public BlockState getBlockRelativeY(final int y) { + return getBlock(getX(), getY() + y , getZ()); } @Override @@ -102,4 +115,56 @@ public abstract class FilterBlock extends BlockVector3 implements Extent { public int getChunkZ() { return getZ() >> 4; } + + /* + Extent + */ + + public boolean setOrdinal(Extent orDefault, int ordinal) { + setOrdinal(ordinal); + return true; + } + + public boolean setBlock(Extent orDefault, BlockState state) { + setBlock(state); + return true; + } + + public boolean setFullBlock(Extent orDefault, BaseBlock block) { + setFullBlock(block); + return true; + } + + public boolean setBiome(Extent orDefault, BiomeType biome) { + setBiome(biome); + return true; + } + + public int getOrdinal(Extent orDefault) { + return getOrdinal(); + } + + public BlockState getBlock(Extent orDefault) { + return getBlock(); + } + + public BaseBlock getFullBlock(Extent orDefault) { + return getFullBlock(); + } + + public CompoundTag getNbtData(Extent orDefault) { + return getNbtData(); + } + + public BlockState getOrdinalBelow(Extent orDefault) { + return getBlockBelow(); + } + + public BlockState getStateAbove(Extent orDefault) { + return getBlockAbove(); + } + + public BlockState getStateRelativeY(Extent orDefault, final int y) { + return getBlockRelativeY(y); + } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java index bdc17bb47..ed8c080b0 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java @@ -71,7 +71,7 @@ public interface IChunk> extends Trimable, Callable { * @param unitialized a mutable block vector (buffer) * @param unitialized2 a mutable block vector (buffer) */ - void filter(Filter filter, ChunkFilterBlock block, @Nullable Region region, MutableBlockVector3 unitialized, MutableBlockVector3 unitialized2); + void filterBlocks(Filter filter, ChunkFilterBlock block, @Nullable Region region, MutableBlockVector3 unitialized, MutableBlockVector3 unitialized2); void flood(Flood flood, FilterBlockMask mask, ChunkFilterBlock block); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkSet.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkSet.java index 138efc6be..bef4af0bf 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkSet.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkSet.java @@ -2,10 +2,12 @@ package com.boydti.fawe.beta; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.extent.OutputExtent; +import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; +import javax.annotation.Nullable; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -16,7 +18,7 @@ import java.util.UUID; * Interface for setting blocks */ public interface IChunkSet extends IBlocks, OutputExtent { - boolean setBiome(int x, int z, BiomeType biome); + boolean setBiome(int x, int y, int z, BiomeType biome); boolean setBlock(int x, int y, int z, BlockStateHolder holder); @@ -42,4 +44,10 @@ public interface IChunkSet extends IBlocks, OutputExtent { @Override void reset(); + + @Nullable + @Override + default Operation commit() { + return null; + } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java index 9a5f4add1..3862c23c5 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java @@ -27,7 +27,7 @@ public interface IDelegateChunk extends IChunk { } @Override - default void flood(Flood flood, FilterBlockMask mask, FilterBlock block) { + default void flood(Flood flood, FilterBlockMask mask, ChunkFilterBlock block) { getParent().flood(flood, mask, block); } @@ -88,8 +88,8 @@ public interface IDelegateChunk extends IChunk { } @Override - default void filter(Filter filter, FilterBlock block, @Nullable Region region, MutableBlockVector3 unitialized, MutableBlockVector3 unitialized2) { - getParent().filter(filter, block, region, unitialized, unitialized2); + default void filterBlocks(Filter filter, ChunkFilterBlock block, @Nullable Region region, MutableBlockVector3 unitialized, MutableBlockVector3 unitialized2) { + getParent().filterBlocks(filter, block, region, unitialized, unitialized2); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/NorthVector.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/NorthVector.java new file mode 100644 index 000000000..c0b4c8e5e --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/NorthVector.java @@ -0,0 +1,93 @@ +package com.boydti.fawe.beta; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MutableBlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; + +public class NorthVector extends BlockVector3 { + private final BlockVector3 parent; + + public NorthVector(BlockVector3 parent) { + this.parent = parent; + } + + @Override + public BlockVector3 south(BlockVector3 orDefault) { + return parent; + } + + @Override + public int getX() { + return parent.getX(); + } + + @Override + public int getY() { + return parent.getY(); + } + + @Override + public int getZ() { + return parent.getZ(); + } + + public boolean setOrdinal(Extent orDefault, int ordinal) { + return orDefault.setBlock(this, BlockState.getFromOrdinal(ordinal)); + } + + public boolean setBlock(Extent orDefault, BlockState state) { + return orDefault.setBlock(this, state); + } + + public boolean setFullBlock(Extent orDefault, BaseBlock block) { + return orDefault.setBlock(this, block); + } + + public boolean setBiome(Extent orDefault, BiomeType biome) { + return orDefault.setBiome(getX(), getY(), getZ(), biome); + } + + public int getOrdinal(Extent orDefault) { + return getBlock(orDefault).getOrdinal(); + } + + public char getOrdinalChar(Extent orDefault) { + return (char) getOrdinal(orDefault); + } + + public BlockState getBlock(Extent orDefault) { + return orDefault.getBlock(this); + } + + public BaseBlock getFullBlock(Extent orDefault) { + return orDefault.getFullBlock(this); + } + + public CompoundTag getNbtData(Extent orDefault) { + return orDefault.getFullBlock(getX(), getY(), getZ()).getNbtData(); + } + + public BlockState getOrdinalBelow(Extent orDefault) { + return getStateRelative(orDefault, 0, -1, 0); + } + + public BlockState getStateAbove(Extent orDefault) { + return getStateRelative(orDefault, 0, 1, 0); + } + + public BlockState getStateRelativeY(Extent orDefault, final int y) { + return getStateRelative(orDefault, 0, y, 0); + } + + public BlockState getStateRelative(Extent orDefault, final int x, final int y, final int z) { + return getFullBlockRelative(orDefault, x, y, z).toBlockState(); + } + + public BaseBlock getFullBlockRelative(Extent orDefault, int x, int y, int z) { + return orDefault.getFullBlock(x + getX(), y + getY(), z + getZ()); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/SimpleFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/SimpleFilterBlock.java index 34da51861..99ec8e2e6 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/SimpleFilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/SimpleFilterBlock.java @@ -11,60 +11,14 @@ import com.sk89q.worldedit.world.block.BlockTypes; import javax.annotation.Nullable; public abstract class SimpleFilterBlock extends FilterBlock { + private final Extent extent; + public SimpleFilterBlock(Extent extent) { - super(extent); - } - - private int x, y, z, ordinal; - private CompoundTag nbt; - - public void init(int x, int y, int z, int ordinal) { - this.x = x; - this.y = y; - this.z = z; - this.ordinal = ordinal; - } - - public void init(int x, int y, int z, int ordinal, CompoundTag nbt) { - this.x = x; - this.y = y; - this.z = z; - this.ordinal = ordinal; - this.nbt = nbt; + this.extent = extent; } @Override - public int getOrdinal() { - return ordinal; - } - - @Override - public BlockState getState() { - return BlockTypes.states[ordinal]; - } - - @Override - public BaseBlock getBaseBlock() { - return getState().toBaseBlock(nbt); - } - - @Override - public CompoundTag getTag() { - return nbt; - } - - @Override - public int getX() { - return x; - } - - @Override - public int getY() { - return y; - } - - @Override - public int getZ() { - return z; + public final Extent getExtent() { + return extent; } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/SingleFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/SingleFilterBlock.java new file mode 100644 index 000000000..8a7add4b6 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/SingleFilterBlock.java @@ -0,0 +1,98 @@ +package com.boydti.fawe.beta; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; + +import javax.annotation.Nullable; + +public class SingleFilterBlock extends FilterBlock { + + private BaseBlock block; + private int x, y, z; + + public SingleFilterBlock init(int x, int y, int z, BaseBlock block) { + this.x = x; + this.y = y; + this.z = z; + this.block = block; + return this; + } + + @Override + public Extent getExtent() { + return this; + } + + @Override + public void setOrdinal(int ordinal) { + setBlock(BlockState.getFromOrdinal(ordinal)); + } + + @Override + public void setBlock(BlockState state) { + setFullBlock(state.toBaseBlock(block.getNbtData())); + } + + @Override + public void setFullBlock(BaseBlock block) { + this.block = block; + } + + @Override + public void setNbtData(@Nullable CompoundTag nbtData) { + block = block.toBaseBlock(nbtData); + } + + @Override + public int getOrdinal() { + return block.getOrdinal(); + } + + @Override + public BaseBlock getFullBlockRelative(int x, int y, int z) { + return block; + } + + @Override + public BlockState getBlock() { + return block.toBlockState(); + } + + @Override + public BaseBlock getFullBlock() { + return block; + } + + @Override + public CompoundTag getNbtData() { + return block.getNbtData(); + } + + @Override + public int getX() { + return x; + } + + @Override + public int getY() { + return y; + } + + @Override + public int getZ() { + return z; + } + + @Override + public BlockVector3 getMinimumPoint() { + return BlockVector3.at(x, y, z); + } + + @Override + public BlockVector3 getMaximumPoint() { + return BlockVector3.at(x, y, z); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/SetFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/SetFilter.java index 04048d04d..841defd43 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/SetFilter.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/SetFilter.java @@ -13,6 +13,6 @@ public class SetFilter implements Filter { @Override public void applyBlock(final FilterBlock block) { - block.setState(state); + block.setBlock(state); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java index 666ededbf..e7a90b531 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java @@ -4,7 +4,6 @@ import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; import com.boydti.fawe.beta.ChunkFilterBlock; import com.boydti.fawe.beta.Filter; -import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.IQueueExtent; import com.boydti.fawe.beta.Trimable; @@ -186,7 +185,7 @@ public abstract class QueueHandler implements Trimable, Runnable { if (newChunk != null) { chunk = newChunk; if (block == null) block = queue.initFilterBlock(); - chunk.filter(newFilter, block, region, mbv1, mbv2); + chunk.filterBlocks(newFilter, block, region, mbv1, mbv2); } queue.submit(chunk); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java index 80ce0d560..b341c7021 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java @@ -1,11 +1,12 @@ package com.boydti.fawe.beta.implementation; import com.boydti.fawe.beta.CharFilterBlock; +import com.boydti.fawe.beta.ChunkFilterBlock; import com.boydti.fawe.beta.FilterBlock; public abstract class SimpleCharQueueExtent extends SingleThreadQueueExtent { @Override - public FilterBlock initFilterBlock() { + public ChunkFilterBlock initFilterBlock() { return new CharFilterBlock(this); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java index dbf456a72..b1336a480 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java @@ -47,7 +47,7 @@ public abstract class ChunkHolder implements IChunk, Supplier { } @Override - public void filter(final Filter filter, ChunkFilterBlock block, @Nullable Region region, @Nullable final MutableBlockVector3 min, @Nullable final MutableBlockVector3 max) { + public void filterBlocks(final Filter filter, ChunkFilterBlock block, @Nullable Region region, @Nullable final MutableBlockVector3 min, @Nullable final MutableBlockVector3 max) { final IChunkGet get = getOrCreateGet(); final IChunkSet set = getOrCreateSet(); try { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java index 91e28814f..88c6269db 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java @@ -1,10 +1,16 @@ package com.boydti.fawe.beta.implementation.holder; +import com.boydti.fawe.beta.ChunkFilterBlock; +import com.boydti.fawe.beta.Filter; import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.beta.FilterBlockMask; import com.boydti.fawe.beta.Flood; import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.IDelegateChunk; +import com.sk89q.worldedit.math.MutableBlockVector3; +import com.sk89q.worldedit.regions.Region; + +import javax.annotation.Nullable; /** * Implementation of IDelegateChunk diff --git a/worldedit-core/src/main/java/com/boydti/fawe/command/CFICommands.java b/worldedit-core/src/main/java/com/boydti/fawe/command/CFICommands.java index 404fef5da..20140ba8d 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/command/CFICommands.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/command/CFICommands.java @@ -2,6 +2,7 @@ package com.boydti.fawe.command; import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweAPI; +import com.boydti.fawe.beta.SingleFilterBlock; import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.Commands; import com.boydti.fawe.jnbt.anvil.HeightMapMCAGenerator; @@ -9,7 +10,6 @@ import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.RunnableVal; import com.boydti.fawe.object.clipboard.MultiClipboardHolder; -import com.boydti.fawe.object.pattern.PatternExtent; import com.boydti.fawe.util.CleanTextureUtil; import com.boydti.fawe.util.FilteredTextureUtil; import com.boydti.fawe.util.ImgurUtility; @@ -37,7 +37,6 @@ import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; @@ -70,7 +69,6 @@ import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.function.Consumer; import java.util.function.Function; import static com.boydti.fawe.util.image.ImageUtil.load; @@ -419,9 +417,7 @@ public class CFICommands extends MethodCommands { } default: { blocks = new HashSet<>(); - BlockPattern pattern = new BlockPattern(BlockTypes.AIR.getDefaultState()); - PatternExtent extent = new PatternExtent(pattern); - + SingleFilterBlock extent = new SingleFilterBlock(); ParserContext parserContext = new ParserContext(); parserContext.setActor(player); parserContext.setWorld(player.getWorld()); @@ -432,9 +428,10 @@ public class CFICommands extends MethodCommands { TextureUtil tu = Fawe.get().getTextureUtil(); for (int typeId : tu.getValidBlockIds()) { BlockType type = BlockTypes.get(typeId); - BlockStateHolder block = type.getDefaultState(); - pattern.setBlock(block); - if (mask.test(BlockVector3.ZERO)) blocks.add(type); + extent.init(0, 0, 0, type.getDefaultState().toBaseBlock()); + if (mask.test(extent)) { + blocks.add(type); + } } break; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAWorld.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAWorld.java index ab6701b0d..4c8926103 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAWorld.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAWorld.java @@ -104,7 +104,7 @@ public class MCAWorld implements SimpleWorld { @Override public BlockState getBlock(BlockVector3 position) { - return extent.getLazyBlock(position); + return extent.getBlock(position); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/CavesGen.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/CavesGen.java index 76cbdb05f..08257fb7f 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/CavesGen.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/CavesGen.java @@ -150,7 +150,7 @@ public class CavesGen extends GenBase { for (int local_z = i3; (!waterFound) && (local_z < i4); local_z++) { for (int local_y = i2 + 1; (!waterFound) && (local_y >= i1 - 1); local_y--) { if (local_y < 255) { - BlockStateHolder material = chunk.getLazyBlock(bx + local_x, local_y, bz + local_z); + BlockStateHolder material = chunk.getBlock(bx + local_x, local_y, bz + local_z); if (material.getBlockType() == BlockTypes.WATER) { waterFound = true; } @@ -174,8 +174,8 @@ public class CavesGen extends GenBase { for (int local_y = i2; local_y > i1; local_y--) { double d11 = ((local_y - 1) + 0.5D - y) / d4; if ((d11 > -0.7D) && (d9 * d9 + d11 * d11 + d10 * d10 < 1.0D)) { - BlockStateHolder material = chunk.getLazyBlock(bx + local_x, local_y, bz + local_z); - BlockStateHolder materialAbove = chunk.getLazyBlock(bx + local_x, local_y + 1, bz + local_z); + BlockStateHolder material = chunk.getBlock(bx + local_x, local_y, bz + local_z); + BlockStateHolder materialAbove = chunk.getBlock(bx + local_x, local_y + 1, bz + local_z); BlockType blockType = material.getBlockType(); switch (blockType.getInternalId()) { case BlockID.MYCELIUM: @@ -192,7 +192,7 @@ public class CavesGen extends GenBase { // If grass was just deleted, try to // move it down if (grassFound) { - BlockStateHolder block = chunk.getLazyBlock(bx + local_x, local_y - 1, bz + local_z); + BlockStateHolder block = chunk.getBlock(bx + local_x, local_y - 1, bz + local_z); if (block.getBlockType() == BlockTypes.DIRT) { chunk.setBlock(bx + local_x, local_y - 1, bz + local_z, BlockTypes.STONE.getDefaultState()); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/DataAnglePattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/DataAnglePattern.java index 323e918e3..48696a6d0 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/DataAnglePattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/DataAnglePattern.java @@ -1,15 +1,14 @@ package com.boydti.fawe.object; -import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.object.extent.ExtentHeightCacher; import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.AbstractPattern; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.block.BlockTypes; public class DataAnglePattern extends AbstractPattern { public final double FACTOR; @@ -24,7 +23,7 @@ public class DataAnglePattern extends AbstractPattern { this.FACTOR = (1D / distance) * (1D / 255); } - public int getSlope(BlockStateHolder block, BlockVector3 vector) { + public int getSlope(BlockStateHolder block, BlockVector3 vector, Extent extent) { int x = vector.getBlockX(); int y = vector.getBlockY(); int z = vector.getBlockZ(); @@ -32,7 +31,6 @@ public class DataAnglePattern extends AbstractPattern { return -1; } int slope; - boolean aboveMin; slope = Math.abs(extent.getNearestSurfaceTerrainBlock(x + distance, z, y, 0, maxY) - extent.getNearestSurfaceTerrainBlock(x - distance, z, y, 0, maxY)) * 7; slope += Math.abs(extent.getNearestSurfaceTerrainBlock(x, z + distance, y, 0, maxY) - extent.getNearestSurfaceTerrainBlock(x, z - distance, y, 0, maxY)) * 7; slope += Math.abs(extent.getNearestSurfaceTerrainBlock(x + distance, z + distance, y, 0, maxY) - extent.getNearestSurfaceTerrainBlock(x - distance, z - distance, y, 0, maxY)) * 5; @@ -42,8 +40,8 @@ public class DataAnglePattern extends AbstractPattern { @Override public BaseBlock apply(BlockVector3 position) { - BlockStateHolder block = extent.getBlock(position); - int slope = getSlope(block, position); + BlockState block = extent.getBlock(position); + int slope = getSlope(block, position, extent); if (slope == -1) return block.toBaseBlock(); int data = (Math.min(slope, 255)) >> 4; return block.withPropertyId(data).toBaseBlock(); @@ -52,7 +50,7 @@ public class DataAnglePattern extends AbstractPattern { @Override public boolean apply(Extent extent, BlockVector3 setPosition, BlockVector3 getPosition) throws WorldEditException { BlockStateHolder block = extent.getBlock(getPosition); - int slope = getSlope(block, getPosition); + int slope = getSlope(block, getPosition, extent); if (slope == -1) return false; int data = (Math.min(slope, 255)) >> 4; return extent.setBlock(setPosition, block.withPropertyId(data)); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/LayerBrush.java b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/LayerBrush.java index fccf2502c..41039fb55 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/LayerBrush.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/LayerBrush.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.brush; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.collection.BlockVectorSet; import com.boydti.fawe.object.mask.AdjacentAnyMask; @@ -7,6 +8,7 @@ import com.boydti.fawe.object.mask.RadiusMask; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.command.tool.brush.Brush; +import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.function.mask.BlockTypeMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.SolidBlockMask; @@ -34,7 +36,7 @@ public class LayerBrush implements Brush { @Override public void build(EditSession editSession, BlockVector3 position, Pattern ignore, double size) throws MaxChangedBlocksException { final FaweQueue queue = editSession.getQueue(); - final AdjacentAnyMask adjacent = new AdjacentAnyMask(new BlockTypeMask(editSession, BlockTypes.AIR, BlockTypes.CAVE_AIR, BlockTypes.VOID_AIR)); + final AdjacentAnyMask adjacent = new AdjacentAnyMask(new BlockMask(editSession).add(BlockTypes.AIR, BlockTypes.CAVE_AIR, BlockTypes.VOID_AIR)); final SolidBlockMask solid = new SolidBlockMask(editSession); final RadiusMask radius = new RadiusMask(0, (int) size); visitor = new RecursiveVisitor(vector -> solid.test(vector) && radius.test(vector) && adjacent.test(vector), function -> true); @@ -42,30 +44,32 @@ public class LayerBrush implements Brush { visitor.setDirections(Arrays.asList(BreadthFirstSearch.DIAGONAL_DIRECTIONS)); Operations.completeBlindly(visitor); BlockVectorSet visited = visitor.getVisited(); - BlockStateHolder firstPattern = layers[0]; - visitor = new RecursiveVisitor((Mask) pos -> { - int depth = visitor.getDepth() + 1; - if (depth > 1) { - boolean found = false; - int previous = layers[depth - 1].getInternalId(); - int previous2 = layers[depth - 2].getInternalId(); - for (BlockVector3 dir : BreadthFirstSearch.DEFAULT_DIRECTIONS) { - mutable.setComponents(pos.getBlockX() + dir.getBlockX(), pos.getBlockY() + dir.getBlockY(), pos.getBlockZ() + dir.getBlockZ()); - if (visitor.isVisited(mutable) && queue.getCachedCombinedId4Data(mutable.getBlockX(), mutable.getBlockY(), mutable.getBlockZ()) == previous) { - mutable.setComponents(pos.getBlockX() + dir.getBlockX() * 2, pos.getBlockY() + dir.getBlockY() * 2, pos.getBlockZ() + dir.getBlockZ() * 2); - if (visitor.isVisited(mutable) && queue.getCachedCombinedId4Data(mutable.getBlockX(), mutable.getBlockY(), mutable.getBlockZ()) == previous2) { - found = true; - break; - } else { - return false; + visitor = new RecursiveVisitor(new Mask() { + @Override + public boolean test(BlockVector3 pos) { + int depth = visitor.getDepth() + 1; + if (depth > 1) { + boolean found = false; + int previous = layers[depth - 1].getInternalId(); + int previous2 = layers[depth - 2].getInternalId(); + for (BlockVector3 dir : BreadthFirstSearch.DEFAULT_DIRECTIONS) { + mutable.setComponents(pos.getBlockX() + dir.getBlockX(), pos.getBlockY() + dir.getBlockY(), pos.getBlockZ() + dir.getBlockZ()); + if (visitor.isVisited(mutable) && queue.getCachedCombinedId4Data(mutable.getBlockX(), mutable.getBlockY(), mutable.getBlockZ()) == previous) { + mutable.setComponents(pos.getBlockX() + dir.getBlockX() * 2, pos.getBlockY() + dir.getBlockY() * 2, pos.getBlockZ() + dir.getBlockZ() * 2); + if (visitor.isVisited(mutable) && queue.getCachedCombinedId4Data(mutable.getBlockX(), mutable.getBlockY(), mutable.getBlockZ()) == previous2) { + found = true; + break; + } else { + return false; + } } } + if (!found) { + return false; + } } - if (!found) { - return false; - } + return !adjacent.test(pos); } - return !adjacent.test(pos); }, pos -> { int depth = visitor.getDepth(); BlockStateHolder currentPattern = layers[depth]; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/EmptyClipboard.java b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/EmptyClipboard.java index 41062cffd..8e953f8eb 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/EmptyClipboard.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/EmptyClipboard.java @@ -79,7 +79,7 @@ public class EmptyClipboard implements Clipboard { } @Override - public BlockState getLazyBlock(BlockVector3 position) { + public BlockState getBlock(BlockVector3 position) { return EditSession.nullBlock; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/BlockTranslateExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/BlockTranslateExtent.java index 625d2687c..1b35bf82f 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/BlockTranslateExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/BlockTranslateExtent.java @@ -52,17 +52,12 @@ public class BlockTranslateExtent extends AbstractDelegateExtent { @Override public BlockState getBlock(BlockVector3 location) { - return getLazyBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + return getBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ()); } @Override - public BlockState getLazyBlock(BlockVector3 location) { - return getLazyBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - } - - @Override - public BlockState getLazyBlock(int x, int y, int z) { - return super.getLazyBlock(x + dx, y + dy, z + dz); + public BlockState getBlock(int x, int y, int z) { + return super.getBlock(x + dx, y + dy, z + dz); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/EmptyExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/EmptyExtent.java index 886c02150..04ff96b56 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/EmptyExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/EmptyExtent.java @@ -50,7 +50,7 @@ public class EmptyExtent implements Extent { } @Override - public BlockState getLazyBlock(BlockVector3 position) { + public BlockState getBlock(int x, int y, int z) { return EditSession.nullBlock; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/FastWorldEditExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/FastWorldEditExtent.java index e8853dda8..fd761b76c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/FastWorldEditExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/FastWorldEditExtent.java @@ -112,8 +112,6 @@ public class FastWorldEditExtent extends AbstractDelegateExtent implements HasFa public > boolean setBlock(final BlockVector3 location, final B block) throws WorldEditException { return setBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ(), block); } - - @Override public > boolean setBlock(int x, int y, int z, final B block) throws WorldEditException { @@ -121,12 +119,12 @@ public class FastWorldEditExtent extends AbstractDelegateExtent implements HasFa } @Override - public BlockState getLazyBlock(BlockVector3 location) { - return getLazyBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + public BlockState getBlock(BlockVector3 location) { + return getBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ()); } @Override - public BlockState getLazyBlock(int x, int y, int z) { + public BlockState getBlock(int x, int y, int z) { int combinedId4Data = queue.getCombinedId4Data(x, y, z, 0); BlockType type = BlockTypes.getFromStateId(combinedId4Data); BlockState state = type.withStateId(combinedId4Data); @@ -157,11 +155,6 @@ public class FastWorldEditExtent extends AbstractDelegateExtent implements HasFa return world.getEntities(region); } - @Override - public BlockState getBlock(final BlockVector3 position) { - return this.getLazyBlock(position); - } - @Override public boolean setBiome(final BlockVector2 position, final BiomeType biome) { queue.setBiome(position.getBlockX(), position.getBlockZ(), biome); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/NullExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/NullExtent.java index ae1d1c7be..75a8955e4 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/NullExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/NullExtent.java @@ -66,7 +66,7 @@ public class NullExtent extends FaweRegionExtent { } @Override - public BlockState getLazyBlock(final BlockVector3 arg0) { + public BlockState getBlock(int x, int y, int z) { if(reason != null) { throw new FaweException(reason); }else { @@ -74,6 +74,15 @@ public class NullExtent extends FaweRegionExtent { } } + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + if(reason != null) { + throw new FaweException(reason); + }else { + return null; + } + } + @Override public boolean setBiome(final BlockVector2 arg0, final BiomeType arg1) { if(reason != null) { @@ -101,15 +110,6 @@ public class NullExtent extends FaweRegionExtent { } } - @Override - public BlockState getLazyBlock(int x, int y, int z) { - if(reason != null) { - throw new FaweException(reason); - }else { - return null; - } - } - @Override public Entity createEntity(final Location arg0, final BaseEntity arg1) { if(reason != null) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/PositionTransformExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/PositionTransformExtent.java index 469a689a1..3e8132a5e 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/PositionTransformExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/PositionTransformExtent.java @@ -47,20 +47,15 @@ public class PositionTransformExtent extends ResettableExtent { } @Override - public BlockState getLazyBlock(int x, int y, int z) { - return super.getLazyBlock(getPos(BlockVector3.at(x, y, z))); - } - - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return super.getLazyBlock(getPos(position)); + public BlockState getBlock(int x, int y, int z) { + return super.getBlock(getPos(BlockVector3.at(x, y, z))); } @Override public BlockState getBlock(BlockVector3 position) { return super.getBlock(getPos(position)); } - + @Override public BaseBlock getFullBlock(BlockVector3 position) { return super.getFullBlock(getPos(position)); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/ProcessedWEExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/ProcessedWEExtent.java index 270792162..a8b7bb6c6 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/ProcessedWEExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/ProcessedWEExtent.java @@ -63,12 +63,12 @@ public class ProcessedWEExtent extends AbstractDelegateExtent { } @Override - public BlockState getLazyBlock(int x, int y, int z) { + public BlockState getBlock(int x, int y, int z) { if (!limit.MAX_CHECKS()) { WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); return EditSession.nullBlock; } else { - return extent.getLazyBlock(x, y, z); + return extent.getBlock(x, y, z); } } @@ -88,8 +88,8 @@ public class ProcessedWEExtent extends AbstractDelegateExtent { } @Override - public BlockState getLazyBlock(BlockVector3 location) { - return getLazyBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + public BlockState getBlock(BlockVector3 location) { + return getBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ()); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/TemporalExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/TemporalExtent.java index d678f7b7f..503286fd6 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/TemporalExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/TemporalExtent.java @@ -58,19 +58,11 @@ public class TemporalExtent extends AbstractDelegateExtent { } @Override - public BlockState getLazyBlock(BlockVector3 position) { - if (position.getX() == x && position.getY() == y && position.getZ() == z) { - return block.toImmutableState(); - } - return super.getLazyBlock(position); - } - - @Override - public BlockState getLazyBlock(int x, int y, int z) { + public BlockState getBlock(int x, int y, int z) { if (this.x == x && this.y == y && this.z == z) { return block.toImmutableState(); } - return super.getLazyBlock(x, y, z); + return super.getBlock(x, y, z); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/TransformExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/TransformExtent.java index 0fae70cb3..a4d33cf8f 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/TransformExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/TransformExtent.java @@ -1,6 +1,7 @@ package com.boydti.fawe.object.extent; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.extent.Extent; @@ -14,7 +15,8 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; public class TransformExtent extends BlockTransformExtent { - private final MutableBlockVector3 mutable = new MutableBlockVector3(); + private final MutableVector3 mutable1 = new MutableVector3(); + private final MutableBlockVector3 mutable2 = new MutableBlockVector3(); private BlockVector3 min; private int maxy; @@ -53,56 +55,45 @@ public class TransformExtent extends BlockTransformExtent { if (min == null) { min = pos; } - mutable.mutX(((pos.getX() - min.getX()))); - mutable.mutY(((pos.getY() - min.getY()))); - mutable.mutZ(((pos.getZ() - min.getZ()))); - MutableVector3 tmp = new MutableVector3(getTransform().apply(mutable.toVector3())); - tmp.mutX((tmp.getX() + min.getX())); - tmp.mutY((tmp.getY() + min.getY())); - tmp.mutZ((tmp.getZ() + min.getZ())); - return tmp.toBlockPoint(); + mutable1.mutX(((pos.getX() - min.getX()))); + mutable1.mutY(((pos.getY() - min.getY()))); + mutable1.mutZ(((pos.getZ() - min.getZ()))); + Vector3 tmp = getTransform().apply(mutable1); + mutable2.mutX((tmp.getX() + min.getX())); + mutable2.mutY((tmp.getY() + min.getY())); + mutable2.mutZ((tmp.getZ() + min.getZ())); + return mutable2; } public BlockVector3 getPos(int x, int y, int z) { if (min == null) { min = BlockVector3.at(x, y, z); } - mutable.mutX(((x - min.getX()))); - mutable.mutY(((y - min.getY()))); - mutable.mutZ(((z - min.getZ()))); - MutableVector3 tmp = new MutableVector3(getTransform().apply(mutable.toVector3())); - tmp.mutX((tmp.getX() + min.getX())); - tmp.mutY((tmp.getY() + min.getY())); - tmp.mutZ((tmp.getZ() + min.getZ())); + mutable1.mutX(((x - min.getX()))); + mutable1.mutY(((y - min.getY()))); + mutable1.mutZ(((z - min.getZ()))); + Vector3 tmp = getTransform().apply(mutable1); + mutable2.mutX((tmp.getX() + min.getX())); + mutable2.mutY((tmp.getY() + min.getY())); + mutable2.mutZ((tmp.getZ() + min.getZ())); return tmp.toBlockPoint(); } @Override - public BlockState getLazyBlock(int x, int y, int z) { - return transform(super.getLazyBlock(getPos(x, y, z))); + public BlockState getBlock(int x, int y, int z) { + BlockVector3 p = getPos(x, y, z); + return transform(super.getBlock(p.getX(), p.getY(), p.getZ())); } - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return transform(super.getLazyBlock(getPos(position))); - } - - @Override - public BlockState getBlock(BlockVector3 position) { - return transform(super.getBlock(getPos(position))); - } - @Override public BaseBlock getFullBlock(BlockVector3 position) { return transform(super.getFullBlock(getPos(position))); } @Override - public BiomeType getBiome(BlockVector2 position) { - mutable.mutX(position.getBlockX()); - mutable.mutZ(position.getBlockZ()); - mutable.mutY(0); - return super.getBiome(getPos(mutable).toBlockVector2()); + public BiomeType getBiome(int x, int z) { + BlockVector3 p = getPos(x, 0, z); + return super.getBiome(p.getX(), p.getZ()); } @Override @@ -117,10 +108,8 @@ public class TransformExtent extends BlockTransformExtent { } @Override - public boolean setBiome(BlockVector2 position, BiomeType biome) { - mutable.mutX(position.getBlockX()); - mutable.mutZ(position.getBlockZ()); - mutable.mutY(0); - return super.setBiome(getPos(mutable).toBlockVector2(), biome); + public boolean setBiome(int x, int y, int z, BiomeType biome) { + BlockVector3 p = getPos(x, y, z); + return super.setBiome(p.getX(), p.getY(), p.getZ(), biome); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/function/mask/AbstractDelegateMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/function/mask/AbstractDelegateMask.java index fd6e472fe..ece6b91db 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/function/mask/AbstractDelegateMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/function/mask/AbstractDelegateMask.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.function.mask; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.function.mask.AbstractMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask2D; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/AdjacentAnyMask2.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/AdjacentAnyMask2.java new file mode 100644 index 000000000..8cb5f6ffc --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/AdjacentAnyMask2.java @@ -0,0 +1,11 @@ +package com.boydti.fawe.object.mask; + +import com.sk89q.worldedit.function.mask.AbstractMask; +import com.sk89q.worldedit.math.BlockVector3; + +public class AdjacentAnyMask2 extends AbstractMask { + @Override + public boolean test(BlockVector3 vector) { + return false; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/DataMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/DataMask.java index 01afbac85..f98776e89 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/DataMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/DataMask.java @@ -19,9 +19,9 @@ public class DataMask extends AbstractExtentMask implements ResettableMask { public boolean test(BlockVector3 vector) { Extent extent = getExtent(); if (data != -1) { - return extent.getLazyBlock(vector).getInternalPropertiesId() == data; + return extent.getBlock(vector).getInternalPropertiesId() == data; } else { - data = extent.getLazyBlock(vector).getInternalPropertiesId(); + data = extent.getBlock(vector).getInternalPropertiesId(); return true; } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdDataMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdDataMask.java index 7b7705172..69274c22f 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdDataMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdDataMask.java @@ -19,9 +19,9 @@ public class IdDataMask extends AbstractExtentMask implements ResettableMask { public boolean test(BlockVector3 vector) { Extent extent = getExtent(); if (combined != -1) { - return extent.getLazyBlock(vector).getInternalId() == combined; + return extent.getBlock(vector).getInternalId() == combined; } else { - combined = extent.getLazyBlock(vector).getInternalId(); + combined = extent.getBlock(vector).getInternalId(); return true; } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdMask.java index e9b36b365..7070f3cbe 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdMask.java @@ -19,9 +19,9 @@ public class IdMask extends AbstractExtentMask implements ResettableMask { public boolean test(BlockVector3 vector) { Extent extent = getExtent(); if (id != -1) { - return extent.getLazyBlock(vector).getInternalBlockTypeId() == id; + return extent.getBlock(vector).getInternalBlockTypeId() == id; } else { - id = extent.getLazyBlock(vector).getInternalBlockTypeId(); + id = extent.getBlock(vector).getInternalBlockTypeId(); return true; } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/SurfaceMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/SurfaceMask.java index cd740f93f..dafc52a9b 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/SurfaceMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/SurfaceMask.java @@ -7,11 +7,8 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockTypes; public class SurfaceMask extends AdjacentAnyMask { - private final transient Extent extent; - public SurfaceMask(Extent extent) { super(getMask(extent)); - this.extent = extent; } public static Mask getMask(Extent extent) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AbstractExtentPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AbstractExtentPattern.java index 1e6a8204f..a6566eb57 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AbstractExtentPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AbstractExtentPattern.java @@ -2,6 +2,8 @@ package com.boydti.fawe.object.pattern; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.AbstractPattern; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AngleColorPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AngleColorPattern.java index 64e3ee009..d94340204 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AngleColorPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AngleColorPattern.java @@ -1,11 +1,8 @@ package com.boydti.fawe.object.pattern; -import com.boydti.fawe.Fawe; -import com.boydti.fawe.FaweCache; import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.object.DataAnglePattern; import com.boydti.fawe.util.TextureHolder; -import com.boydti.fawe.util.TextureUtil; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -14,14 +11,12 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; -import java.io.IOException; - public class AngleColorPattern extends DataAnglePattern { - protected transient TextureUtil util; + protected transient TextureHolder holder; public AngleColorPattern(Extent extent, TextureHolder holder, int distance) { super(extent, distance); - this.util = holder.getTextureUtil(); + this.holder = holder.getTextureUtil(); } public int getColor(int color, int slope) { @@ -33,33 +28,20 @@ public class AngleColorPattern extends DataAnglePattern { return (((color >> 24) & 0xFF) << 24) + (newRed << 16) + (newGreen << 8) + (newBlue << 0); } - @Override - public void apply(FilterBlock block) { - BlockState state = block.getState(); - int slope = getSlope(state, block); - if (slope == -1) return; - int color = util.getColor(state.getBlockType()); - if (color == 0) return; - int newColor = getColor(color, slope); - BlockType newBlock = util.getNearestBlock(newColor); - if (newBlock == null) return; - newBlock.apply(block); - } - @Override public BaseBlock apply(BlockVector3 position) { BaseBlock block = extent.getFullBlock(position); - int slope = getSlope(block, position); + int slope = getSlope(block, position, extent); if (slope == -1) return block; - int color = util.getColor(block.getBlockType()); + int color = holder.getTextureUtil().getColor(block.getBlockType()); if (color == 0) return block; int newColor = getColor(color, slope); - return util.getNearestBlock(newColor).getDefaultState().toBaseBlock(); + return holder.getTextureUtil().getNearestBlock(newColor).getDefaultState().toBaseBlock(); } @Override - public int getSlope(BlockStateHolder block, BlockVector3 vector) { - int slope = super.getSlope(block, vector); + public int getSlope(BlockStateHolder block, BlockVector3 vector, Extent extent) { + int slope = super.getSlope(block, vector, extent); if (slope != -1) { int x = vector.getBlockX(); int y = vector.getBlockY(); @@ -76,15 +58,15 @@ public class AngleColorPattern extends DataAnglePattern { } @Override - public boolean apply(Extent extent, BlockVector3 setPosition, BlockVector3 getPosition) throws WorldEditException { - BlockStateHolder block = extent.getBlock(getPosition); - int slope = getSlope(block, getPosition); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + BlockStateHolder block = get.getBlock(extent); + int slope = getSlope(block, get, extent); if (slope == -1) return false; - int color = util.getColor(block.getBlockType()); + int color = holder.getTextureUtil().getColor(block.getBlockType()); if (color == 0) return false; int newColor = getColor(color, slope); - BlockType newBlock = util.getNearestBlock(newColor); + BlockType newBlock = holder.getTextureUtil().getNearestBlock(newColor); if (newBlock == null) return false; - return extent.setBlock(setPosition, newBlock.getDefaultState()); + return set.setBlock(extent, newBlock.getDefaultState()); } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AverageColorPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AverageColorPattern.java index bb8395a8c..c8637cf70 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AverageColorPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AverageColorPattern.java @@ -1,19 +1,14 @@ package com.boydti.fawe.object.pattern; -import com.boydti.fawe.Fawe; import com.boydti.fawe.util.TextureHolder; import com.boydti.fawe.util.TextureUtil; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.block.BlockTypes; import java.awt.Color; -import java.io.IOException; public class AverageColorPattern extends AbstractExtentPattern { private transient TextureHolder holder; @@ -35,19 +30,14 @@ public class AverageColorPattern extends AbstractExtentPattern { } @Override - public boolean apply(Extent extent, BlockVector3 setPosition, BlockVector3 getPosition) throws WorldEditException { - BlockType blockType = extent.getBlockType(getPosition); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + BlockType blockType = get.getBlock(extent).getBlockType(); TextureUtil util = holder.getTextureUtil(); int currentColor = util.getColor(blockType); if (currentColor == 0) return false; int newColor = util.averageColor(currentColor, color); BlockType newBlock = util.getNearestBlock(newColor); if (newBlock == blockType) return false; - return extent.setBlock(setPosition, newBlock.getDefaultState()); - } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - holder = Fawe.get().getCachedTextureUtil(true, 0, 100); + return set.setBlock(extent, newBlock.getDefaultState()); } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/BiomePattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/BiomePattern.java index ff031dde7..1446feb74 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/BiomePattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/BiomePattern.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -10,7 +11,6 @@ import com.sk89q.worldedit.world.biome.BiomeType; import java.io.IOException; public class BiomePattern extends ExistingPattern { - private transient MutableBlockVector2 mutable = new MutableBlockVector2(); private final BiomeType biome; public BiomePattern(Extent extent, BiomeType biome) { @@ -24,8 +24,8 @@ public class BiomePattern extends ExistingPattern { } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 getPosition) throws WorldEditException { - return extent.setBiome(set.getBlockX(), set.getBlockY(), set.getBlockZ(), biome); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + return set.setBiome(extent, biome); } public class BiomePatternException extends RuntimeException { @@ -45,9 +45,4 @@ public class BiomePattern extends ExistingPattern { return this; } } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - mutable = new MutableBlockVector2(); - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/BufferedPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/BufferedPattern.java index a9b9a5148..9bfafc9c5 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/BufferedPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/BufferedPattern.java @@ -1,6 +1,7 @@ package com.boydti.fawe.object.pattern; import com.boydti.fawe.Fawe; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.collection.LocalBlockVectorSet; import com.boydti.fawe.util.FaweTimer; @@ -17,17 +18,18 @@ import java.io.IOException; import java.util.UUID; public class BufferedPattern extends AbstractPattern implements ResettablePattern { - protected transient LocalBlockVectorSet set = new LocalBlockVectorSet(); - protected transient FaweTimer timer; - protected transient long[] actionTime; + protected final LocalBlockVectorSet set = new LocalBlockVectorSet(); + protected final FaweTimer timer; + protected final long[] actionTime; protected final Pattern pattern; protected final UUID uuid; public BufferedPattern(FawePlayer fp, Pattern parent) { this.uuid = fp.getUUID(); - this.actionTime = fp.getMeta("lastActionTime"); - if (actionTime == null) fp.setMeta("lastActionTime", actionTime = new long[2]); + long[] tmp = fp.getMeta("lastActionTime"); + if (tmp == null) fp.setMeta("lastActionTime", tmp = new long[2]); + actionTime = tmp; this.pattern = parent; this.timer = Fawe.get().getTimer(); } @@ -38,16 +40,12 @@ public class BufferedPattern extends AbstractPattern implements ResettablePatter } @Override - public boolean apply(Extent extent, BlockVector3 setPosition, BlockVector3 getPosition) throws WorldEditException { - long now = timer.getTick(); - try { - if (!set(setPosition)) { - return false; - } - return pattern.apply(extent, setPosition, getPosition); - } catch (UnsupportedOperationException ignore) { + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + actionTime[1] = timer.getTick(); + if (!set(get)) { + return false; } - return false; + return pattern.apply(extent, get, set); } public boolean set(BlockVector3 pos) { @@ -63,17 +61,4 @@ public class BufferedPattern extends AbstractPattern implements ResettablePatter actionTime[1] = actionTime[0]; actionTime[0] = now; } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - set = new LocalBlockVectorSet(); - timer = Fawe.get().getTimer(); - FawePlayer fp = Fawe.get().getCachedPlayer(uuid); - if (fp != null) { - this.actionTime = fp.getMeta("lastActionTime"); - if (actionTime == null) fp.setMeta("lastActionTime", actionTime = new long[2]); - } else { - actionTime = new long[2]; - } - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/DataPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/DataPattern.java index 30c7d85f4..7b3b580d2 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/DataPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/DataPattern.java @@ -1,14 +1,14 @@ package com.boydti.fawe.object.pattern; -import com.boydti.fawe.FaweCache; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; +import com.boydti.fawe.beta.DelegateFilterBlock; +import com.boydti.fawe.beta.FilterBlock; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.block.BlockTypes; - import static com.google.common.base.Preconditions.checkNotNull; @@ -25,6 +25,24 @@ public class DataPattern extends AbstractExtentPattern { public BaseBlock apply(BlockVector3 position) { BaseBlock oldBlock = getExtent().getFullBlock(position); BaseBlock newBlock = pattern.apply(position); - return oldBlock.withPropertyId(newBlock.getInternalPropertiesId()).toBaseBlock(); + return oldBlock.toBlockState().withProperties(newBlock.toBlockState()).toBaseBlock(newBlock.getNbtData()); + } + + @Override + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + BaseBlock oldBlock = get.getFullBlock(extent); + BaseBlock newBlock = pattern.apply(get); + + BlockState oldState = oldBlock.toBlockState(); + BlockState newState = oldState.withProperties(newBlock.toBlockState()); + if (newState != oldState) { + if (oldBlock.hasNbtData()) { + set.setFullBlock(extent, newState.toBaseBlock(oldBlock.getNbtData())); + } else { + set.setBlock(extent, newState); + } + return true; + } + return false; } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/DesaturatePattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/DesaturatePattern.java index 1647b3662..2fa5ba2a3 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/DesaturatePattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/DesaturatePattern.java @@ -1,21 +1,16 @@ package com.boydti.fawe.object.pattern; -import com.boydti.fawe.Fawe; import com.boydti.fawe.util.TextureHolder; import com.boydti.fawe.util.TextureUtil; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.AbstractPattern; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; -import java.io.IOException; - public class DesaturatePattern extends AbstractPattern { - private transient TextureHolder holder; + private final TextureHolder holder; private final Extent extent; private final double value; @@ -29,7 +24,11 @@ public class DesaturatePattern extends AbstractPattern { public BaseBlock apply(BlockVector3 position) { BlockType block = extent.getBlockType(position); TextureUtil util = holder.getTextureUtil(); - int color = util.getColor(block); + int color = getColor(util.getColor(block)); + return util.getNearestBlock(color).getDefaultState().toBaseBlock(); + } + + public int getColor(int color) { int r = (color >> 16) & 0xFF; int g = (color >> 8) & 0xFF; int b = (color >> 0) & 0xFF; @@ -39,35 +38,22 @@ public class DesaturatePattern extends AbstractPattern { int green = (int) (g + value * (l - g)); int blue = (int) (b + value * (l - b)); int newColor = (alpha << 24) + (red << 16) + (green << 8) + (blue << 0); - return util.getNearestBlock(newColor).getDefaultState().toBaseBlock(); + return newColor; } @Override - public boolean apply(Extent extent, BlockVector3 setPosition, BlockVector3 getPosition) throws WorldEditException { - BlockType block = extent.getBlockType(getPosition); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + BlockType type = get.getBlock(extent).getBlockType(); TextureUtil util = holder.getTextureUtil(); - int color = util.getColor(block); - int r = (color >> 16) & 0xFF; - int g = (color >> 8) & 0xFF; - int b = (color >> 0) & 0xFF; - int alpha = (color >> 24) & 0xFF; - double l = 0.3f * r + 0.6f * g + 0.1f * b; - int red = (int) (r + value * (l - r)); - int green = (int) (g + value * (l - g)); - int blue = (int) (b + value * (l - b)); - int newColor = (alpha << 24) + (red << 16) + (green << 8) + (blue << 0); + int color = util.getColor(type); + int newColor = getColor(color); if (newColor == color) { return false; } - BlockType newBlock = util.getNextNearestBlock(newColor); - if (block.equals(newBlock)) { + BlockType newType = util.getNextNearestBlock(newColor); + if (type.equals(newType)) { return false; } - return extent.setBlock(setPosition, newBlock.getDefaultState()); - } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - holder = Fawe.get().getCachedTextureUtil(true, 0, 100); + return set.setBlock(extent, newType.getDefaultState()); } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ExistingPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ExistingPattern.java index e345a1705..35f5299c9 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ExistingPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ExistingPattern.java @@ -1,12 +1,10 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.block.BlockTypes; public class ExistingPattern extends AbstractExtentPattern { public ExistingPattern(Extent extent) { @@ -19,10 +17,10 @@ public class ExistingPattern extends AbstractExtentPattern { } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { - if (set.equals(get)) { + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + if (set == get || set.equals(get)) { return false; } - return extent.setBlock(set, extent.getBlock(get)); + return set.setFullBlock(extent, get.getFullBlock(extent)); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ExpressionPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ExpressionPattern.java index c023f4ff3..50f27aaf2 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ExpressionPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ExpressionPattern.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -23,9 +24,7 @@ import static com.google.common.base.Preconditions.checkNotNull; * greater than {@code 0}.

*/ public class ExpressionPattern extends AbstractPattern { - - public String input; - private transient Expression expression; + private final Expression expression; /** * Create a new instance. @@ -35,7 +34,6 @@ public class ExpressionPattern extends AbstractPattern { */ public ExpressionPattern(String input) throws ExpressionException { checkNotNull(input); - this.input = input; this.expression = Expression.compile(input, "x", "y", "z"); } @@ -65,13 +63,4 @@ public class ExpressionPattern extends AbstractPattern { throw e; } } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - try { - this.expression = Expression.compile(input, "x", "y", "z"); - } catch (ExpressionException e) { - e.printStackTrace(); - } - } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/FullClipboardPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/FullClipboardPattern.java index 015eb990d..8e234a9b4 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/FullClipboardPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/FullClipboardPattern.java @@ -36,9 +36,8 @@ public class FullClipboardPattern extends AbstractExtentPattern { } @Override - public boolean apply(Extent extent, BlockVector3 setPosition, BlockVector3 getPosition) throws WorldEditException { - Region region = clipboard.getRegion(); - ForwardExtentCopy copy = new ForwardExtentCopy(clipboard, clipboard.getRegion(), clipboard.getOrigin(), extent, setPosition); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + ForwardExtentCopy copy = new ForwardExtentCopy(clipboard, clipboard.getRegion(), clipboard.getOrigin(), extent, set); copy.setSourceMask(new ExistingBlockMask(clipboard)); Operations.completeBlindly(copy); return true; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/Linear2DBlockPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/Linear2DBlockPattern.java index 2e2826525..681b96892 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/Linear2DBlockPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/Linear2DBlockPattern.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -27,11 +28,11 @@ public class Linear2DBlockPattern extends AbstractPattern { } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { int index = (get.getBlockX() + get.getBlockZ()) % patternsArray.length; if (index < 0) { index += patternsArray.length; } - return patternsArray[index].apply(extent, set, get); + return patternsArray[index].apply(extent, get, set); } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/Linear3DBlockPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/Linear3DBlockPattern.java index c52c349e9..843d07c8e 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/Linear3DBlockPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/Linear3DBlockPattern.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -27,11 +28,11 @@ public class Linear3DBlockPattern extends AbstractPattern { } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { int index = (get.getBlockX() + get.getBlockY() + get.getBlockZ()) % patternsArray.length; if (index < 0) { index += patternsArray.length; } - return patternsArray[index].apply(extent, set, get); + return patternsArray[index].apply(extent, get, set); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/LinearBlockPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/LinearBlockPattern.java index 2614dde7a..7cfd81991 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/LinearBlockPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/LinearBlockPattern.java @@ -27,11 +27,11 @@ public class LinearBlockPattern extends AbstractPattern implements ResettablePat } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { if (index == patternsArray.length) { index = 0; } - return patternsArray[index++].apply(extent, set, get); + return patternsArray[index++].apply(extent, get, set); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/MaskedPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/MaskedPattern.java index 8f9f72550..4858a92b5 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/MaskedPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/MaskedPattern.java @@ -1,5 +1,7 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; +import com.boydti.fawe.beta.SingleFilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -12,32 +14,30 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; public class MaskedPattern extends AbstractPattern { - private final PatternExtent patternExtent; - private final Pattern secondaryPattern; + private final Pattern primary; + private final Pattern secondary; private Mask mask; - public MaskedPattern(Mask mask, PatternExtent primary, Pattern secondary) { + public MaskedPattern(Mask mask, Pattern primary, Pattern secondary) { this.mask = mask; - this.patternExtent = primary; - this.secondaryPattern = secondary; + this.primary = primary; + this.secondary = secondary; } @Override public BaseBlock apply(BlockVector3 position) { - patternExtent.setTarget(position); if (mask.test(position)) { - return patternExtent.getAndResetTarget().toBaseBlock(); + return primary.apply(position); } - return secondaryPattern.apply(position); + return secondary.apply(position); } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { - patternExtent.setTarget(get); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { if (mask.test(get)) { - return patternExtent.getAndResetTarget(extent, set, get); + return primary.apply(extent, get, set); } - return secondaryPattern.apply(extent, set, get); + return secondary.apply(extent, get, set); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoXPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoXPattern.java index 3accfc1e9..93cf0f550 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoXPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoXPattern.java @@ -1,5 +1,7 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.DelegateFilterBlock; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -15,7 +17,7 @@ import java.io.IOException; public class NoXPattern extends AbstractPattern { private final Pattern pattern; -// private transient MutableBlockVector3 mutable = new MutableBlockVector3(); + private final MutableBlockVector3 mutable = new MutableBlockVector3(); public NoXPattern(Pattern pattern) { this.pattern = pattern; @@ -23,21 +25,15 @@ public class NoXPattern extends AbstractPattern { @Override public BaseBlock apply(BlockVector3 pos) { -// mutable.mutY((pos.getY())); -// mutable.mutZ((pos.getZ())); -// return pattern.apply(mutable); - return pattern.apply(pos); + mutable.mutY((pos.getY())); + mutable.mutZ((pos.getZ())); + return pattern.apply(mutable); } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { -// mutable.mutY((get.getY())); -// mutable.mutZ((get.getZ())); - return pattern.apply(extent, set, get); - } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); -// mutable = new MutableBlockVector3(); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + mutable.mutY((get.getY())); + mutable.mutZ((get.getZ())); + return pattern.apply(extent, mutable, set); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoYPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoYPattern.java index 6c8303cff..62e4de18a 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoYPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoYPattern.java @@ -1,5 +1,7 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.DelegateFilterBlock; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -15,29 +17,23 @@ import java.io.IOException; public class NoYPattern extends AbstractPattern { private final Pattern pattern; + private final MutableBlockVector3 mutable = new MutableBlockVector3(); public NoYPattern(Pattern pattern) { this.pattern = pattern; } -// private transient MutableBlockVector3 mutable = new MutableBlockVector3(); - @Override public BaseBlock apply(BlockVector3 pos) { -// mutable.mutX((pos.getX())); -// mutable.mutZ((pos.getZ())); - return pattern.apply(pos); + mutable.mutX((pos.getX())); + mutable.mutZ((pos.getZ())); + return pattern.apply(mutable); } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { -// mutable.mutX((get.getX())); -// mutable.mutZ((get.getZ())); - return pattern.apply(extent, set, get); - } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); -// mutable = new MutableBlockVector3(); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + mutable.mutX((get.getX())); + mutable.mutZ((get.getZ())); + return pattern.apply(extent, mutable, set); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoZPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoZPattern.java index 2a4e3f362..e01894ae4 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoZPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoZPattern.java @@ -1,5 +1,7 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.DelegateFilterBlock; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -20,24 +22,19 @@ public class NoZPattern extends AbstractPattern { this.pattern = pattern; } -// private transient MutableBlockVector3 mutable = new MutableBlockVector3(); + private transient MutableBlockVector3 mutable = new MutableBlockVector3(); @Override public BaseBlock apply(BlockVector3 pos) { -// mutable.mutX((pos.getX())); -// mutable.mutY((pos.getY())); - return pattern.apply(pos); + mutable.mutX((pos.getX())); + mutable.mutY((pos.getY())); + return pattern.apply(mutable); } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { -// mutable.mutX((get.getX())); -// mutable.mutY((get.getY())); - return pattern.apply(extent, set, get); - } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); -// mutable = new MutableBlockVector3(); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + mutable.mutX((get.getX())); + mutable.mutY((get.getY())); + return pattern.apply(extent, mutable, set); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/OffsetPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/OffsetPattern.java index fd34ba1eb..bc53d1864 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/OffsetPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/OffsetPattern.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -15,7 +16,7 @@ import java.io.IOException; public class OffsetPattern extends AbstractPattern { private final int dx, dy, dz; -// private transient MutableBlockVector3 mutable = new MutableBlockVector3(); + private transient MutableBlockVector3 mutable = new MutableBlockVector3(); private final Pattern pattern; public OffsetPattern(Pattern pattern, int dx, int dy, int dz) { @@ -27,24 +28,17 @@ public class OffsetPattern extends AbstractPattern { @Override public BaseBlock apply(BlockVector3 position) { -// mutable.mutX((position.getX() + dx)); -// mutable.mutY((position.getY() + dy)); -// mutable.mutZ((position.getZ() + dz)); -// return pattern.apply(mutable); - return pattern.apply(BlockVector3.at(position.getX() + dx, position.getY() + dy, position.getZ() + dz)); + mutable.mutX((position.getX() + dx)); + mutable.mutY((position.getY() + dy)); + mutable.mutZ((position.getZ() + dz)); + return pattern.apply(mutable); } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { -// mutable.mutX((get.getX() + dx)); -// mutable.mutY((get.getY() + dy)); -// mutable.mutZ((get.getZ() + dz)); -// return pattern.apply(extent, set, mutable); - return pattern.apply(extent, set, BlockVector3.at(get.getX() + dx, get.getY() + dy, get.getZ() + dz)); - } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); -// mutable = new MutableBlockVector3(); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + mutable.mutX((get.getX() + dx)); + mutable.mutY((get.getY() + dy)); + mutable.mutZ((get.getZ() + dz)); + return pattern.apply(extent, get, mutable); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/PatternExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/PatternExtent.java deleted file mode 100644 index 534c9c694..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/PatternExtent.java +++ /dev/null @@ -1,134 +0,0 @@ -package com.boydti.fawe.object.pattern; - -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.entity.Entity; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.function.operation.Operation; -import com.sk89q.worldedit.function.pattern.AbstractPattern; -import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BlockStateHolder; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import javax.annotation.Nullable; - -public class PatternExtent extends AbstractPattern implements Extent { - private final Pattern pattern; - private transient BlockStateHolder block; - private transient BlockVector3 target = BlockVector3.at(0, 0, 0); - - public PatternExtent(Pattern pattern) { - this.pattern = pattern; - } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - target = BlockVector3.at(0, 0, 0); - } - - @Override - public BlockVector3 getMinimumPoint() { - return BlockVector3.at(Integer.MIN_VALUE, 0, Integer.MIN_VALUE); - } - - @Override - public BlockVector3 getMaximumPoint() { - return BlockVector3.at(Integer.MAX_VALUE, 255, Integer.MAX_VALUE); - } - - @Override - public List getEntities(Region region) { - return new ArrayList<>(); - } - - @Override - public List getEntities() { - return new ArrayList<>(); - } - - @Nullable - @Override - public Entity createEntity(Location location, BaseEntity entity) { - return null; - } - - @Override - public BlockState getBlock(BlockVector3 position) { - BlockStateHolder tmp = pattern.apply(position); - if (position == target || (position.getX() == target.getX() && position.getY() == target.getY() && position.getZ() == target.getZ())) { - block = tmp; - } else { - block = null; - } - return (BlockState) tmp; - } - - public void setTarget(BlockVector3 vector) { - this.target = vector; - } - - public boolean getAndResetTarget(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { - BlockStateHolder result = block; - if (result != null) { - block = null; - return extent.setBlock(set, result); - } else { - return pattern.apply(extent, set, target); - } - } - - public BlockStateHolder getAndResetTarget() { - BlockStateHolder result = block; - if (result != null) { - block = null; - return result; - } else { - return pattern.apply(target); - } - } - - @Override - public BaseBlock getFullBlock(BlockVector3 position) { - return getBlock(position).toBaseBlock(); - } - - @Override - public BiomeType getBiome(BlockVector2 position) { - return null; - } - - @Override - public boolean setBlock(BlockVector3 position, BlockStateHolder block) throws WorldEditException { - return false; - } - - @Override - public boolean setBiome(BlockVector2 position, BiomeType biome) { - return false; - } - - @Nullable - @Override - public Operation commit() { - return null; - } - - @Override - public BaseBlock apply(BlockVector3 position) { - return pattern.apply(position); - } - - @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { - return pattern.apply(extent, set, get); - } -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/PropertyPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/PropertyPattern.java index 2533017a2..cb2ee7301 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/PropertyPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/PropertyPattern.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.object.string.MutableCharSequence; import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.StringMan; @@ -14,7 +15,6 @@ import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.registry.state.PropertyKey; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; @@ -211,11 +211,11 @@ public class PropertyPattern extends AbstractExtentPattern { } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { - BaseBlock block = getExtent().getFullBlock(get); - block = apply(block, null); - if (block != null) { - return extent.setBlock(set, block); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + int ordinal = get.getOrdinal(extent); + int newOrdinal = transformed[ordinal]; + if (newOrdinal != ordinal) { + set.setOrdinal(extent, newOrdinal); } return false; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomFullClipboardPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomFullClipboardPattern.java index 82863af97..77f5d0a3e 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomFullClipboardPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomFullClipboardPattern.java @@ -38,7 +38,7 @@ public class RandomFullClipboardPattern extends AbstractPattern { } @Override - public boolean apply(Extent extent, BlockVector3 setPosition, BlockVector3 getPosition) throws WorldEditException { + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { ClipboardHolder holder = clipboards.get(PseudoRandom.random.random(clipboards.size())); AffineTransform transform = new AffineTransform(); if (randomRotate) { @@ -55,9 +55,9 @@ public class RandomFullClipboardPattern extends AbstractPattern { Schematic schematic = new Schematic(clipboard); Transform newTransform = holder.getTransform(); if (newTransform.isIdentity()) { - schematic.paste(extent, setPosition, false); + schematic.paste(extent, set, false); } else { - schematic.paste(extent, setPosition, false, newTransform); + schematic.paste(extent, set, false, newTransform); } return true; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomOffsetPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomOffsetPattern.java index 904364739..d43d2a416 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomOffsetPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomOffsetPattern.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.extent.Extent; @@ -40,19 +41,10 @@ public class RandomOffsetPattern extends AbstractPattern { } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { - mutable.mutX((get.getX() + r.nextInt(dx2) - dx)); - mutable.mutY((get.getY() + r.nextInt(dy2) - dy)); - mutable.mutZ((get.getZ() + r.nextInt(dz2) - dz)); - return pattern.apply(extent, set, mutable); - } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - this.dx2 = dx * 2 + 1; - this.dy2 = dy * 2 + 1; - this.dz2 = dz * 2 + 1; - this.r = new SplittableRandom(); - this.mutable = new MutableBlockVector3(); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + mutable.mutX((set.getX() + r.nextInt(dx2) - dx)); + mutable.mutY((set.getY() + r.nextInt(dy2) - dy)); + mutable.mutZ((set.getZ() + r.nextInt(dz2) - dz)); + return pattern.apply(extent, get, mutable); } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RelativePattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RelativePattern.java index e8f3f56ea..4900a5317 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RelativePattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RelativePattern.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.extent.Extent; @@ -13,8 +14,8 @@ import java.io.IOException; public class RelativePattern extends AbstractPattern implements ResettablePattern { private final Pattern pattern; - private transient BlockVector3 origin; - private transient MutableBlockVector3 mutable = new MutableBlockVector3(); + private BlockVector3 origin; + private final MutableBlockVector3 mutable = new MutableBlockVector3(); public RelativePattern(Pattern pattern) { this.pattern = pattern; @@ -32,19 +33,14 @@ public class RelativePattern extends AbstractPattern implements ResettablePatter } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { if (origin == null) { - origin = get; + origin = set; } - mutable.mutX((get.getX() - origin.getX())); - mutable.mutY((get.getY() - origin.getY())); - mutable.mutZ((get.getZ() - origin.getZ())); - return pattern.apply(extent, set, mutable); - } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - mutable = new MutableBlockVector3(); + mutable.mutX((set.getX() - origin.getX())); + mutable.mutY((set.getY() - origin.getY())); + mutable.mutZ((set.getZ() - origin.getZ())); + return pattern.apply(extent, get, mutable); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SaturatePattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SaturatePattern.java index 5499b1507..53b04c2c8 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SaturatePattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SaturatePattern.java @@ -1,22 +1,19 @@ package com.boydti.fawe.object.pattern; -import com.boydti.fawe.Fawe; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.util.TextureHolder; import com.boydti.fawe.util.TextureUtil; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.AbstractPattern; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import java.awt.Color; -import java.io.IOException; public class SaturatePattern extends AbstractPattern { - private transient TextureHolder holder; + private final TextureHolder holder; private final int color; private final Extent extent; @@ -37,19 +34,14 @@ public class SaturatePattern extends AbstractPattern { } @Override - public boolean apply(Extent extent, BlockVector3 setPosition, BlockVector3 getPosition) throws WorldEditException { - BlockType block = extent.getBlockType(getPosition); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + BlockType block = get.getBlock(extent).getBlockType(); TextureUtil util = holder.getTextureUtil(); int currentColor = util.getColor(block); if (currentColor == 0) return false; int newColor = util.multiplyColor(currentColor, color); BlockType newBlock = util.getNearestBlock(newColor); if (newBlock.equals(block)) return false; - return extent.setBlock(setPosition, newBlock.getDefaultState()); - } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - holder = Fawe.get().getCachedTextureUtil(true, 0, 100); + return set.setBlock(extent, newBlock.getDefaultState()); } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ShadePattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ShadePattern.java index 5c8a910f2..e91989de5 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ShadePattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ShadePattern.java @@ -1,22 +1,19 @@ package com.boydti.fawe.object.pattern; -import com.boydti.fawe.Fawe; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.util.TextureUtil; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.AbstractPattern; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; -import java.io.IOException; - import static com.google.common.base.Preconditions.checkNotNull; public class ShadePattern extends AbstractPattern { - private transient TextureUtil util; + private final TextureUtil util; private final Extent extent; private final boolean darken; @@ -33,8 +30,13 @@ public class ShadePattern extends AbstractPattern { return (darken ? util.getDarkerBlock(block) : util.getLighterBlock(block)).getDefaultState().toBaseBlock(); } - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - util = Fawe.get().getCachedTextureUtil(true, 0, 100); + @Override + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + BlockType type = get.getBlock(extent).getBlockType(); + BlockType newType = (darken ? util.getDarkerBlock(type) : util.getLighterBlock(type)); + if (type != newType) { + return set.setBlock(extent, newType.getDefaultState()); + } + return false; } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SolidRandomOffsetPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SolidRandomOffsetPattern.java index 3ac516bc7..b5ab2fd4c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SolidRandomOffsetPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SolidRandomOffsetPattern.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.extent.Extent; @@ -9,6 +10,8 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; import java.io.IOException; import java.util.SplittableRandom; @@ -17,25 +20,27 @@ public class SolidRandomOffsetPattern extends AbstractPattern { private final int dx, dy, dz; private final Pattern pattern; - private transient int dx2, dy2, dz2; - private transient MutableBlockVector3 mutable; - private transient boolean[] solid; + private final int dx2, dy2, dz2; + private final MutableBlockVector3 mutable; private SplittableRandom r; + public static boolean[] getTypes() { + boolean[] types = new boolean[BlockTypes.size()]; + for (BlockType type : BlockTypes.values) { + types[type.getInternalId()] = type.getMaterial().isSolid(); + } + return types; + } public SolidRandomOffsetPattern(Pattern pattern, int dx, int dy, int dz) { this.pattern = pattern; this.dx = dx; this.dy = dy; this.dz = dz; - init(); - } - private void init() { this.dx2 = dx * 2 + 1; this.dy2 = dy * 2 + 1; this.dz2 = dz * 2 + 1; - solid = SolidBlockMask.getTypes(); this.r = new SplittableRandom(); this.mutable = new MutableBlockVector3(); } @@ -46,7 +51,7 @@ public class SolidRandomOffsetPattern extends AbstractPattern { mutable.mutY((position.getY() + r.nextInt(dy2) - dy)); mutable.mutZ((position.getZ() + r.nextInt(dz2) - dz)); BaseBlock block = pattern.apply(mutable); - if (solid[block.getInternalBlockTypeId()]) { + if (block.getMaterial().isSolid()) { return block; } else { return pattern.apply(position); @@ -54,20 +59,15 @@ public class SolidRandomOffsetPattern extends AbstractPattern { } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { - mutable.mutX((get.getX() + r.nextInt(dx2) - dx)); - mutable.mutY((get.getY() + r.nextInt(dy2) - dy)); - mutable.mutZ((get.getZ() + r.nextInt(dz2) - dz)); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + mutable.mutX((set.getX() + r.nextInt(dx2) - dx)); + mutable.mutY((set.getY() + r.nextInt(dy2) - dy)); + mutable.mutZ((set.getZ() + r.nextInt(dz2) - dz)); BlockStateHolder block = pattern.apply(mutable); - if (solid[block.getInternalBlockTypeId()]) { - return pattern.apply(extent, set, mutable); + if (block.getMaterial().isSolid()) { + return pattern.apply(extent, get, mutable); } else { - return pattern.apply(extent, set, get); + return pattern.apply(extent, get, set); } } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - init(); - } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SurfaceRandomOffsetPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SurfaceRandomOffsetPattern.java index 92020ef76..36a63f937 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SurfaceRandomOffsetPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SurfaceRandomOffsetPattern.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.function.pattern.AbstractPattern; import com.sk89q.worldedit.function.pattern.Pattern; @@ -13,20 +14,16 @@ import java.util.concurrent.ThreadLocalRandom; public class SurfaceRandomOffsetPattern extends AbstractPattern { private final Pattern pattern; - private int moves; + private final int moves; - private transient MutableBlockVector3 cur; - private transient MutableBlockVector3[] buffer; - private transient MutableBlockVector3[] allowed; - private transient MutableBlockVector3 next; + private final MutableBlockVector3 cur; + private final MutableBlockVector3[] buffer; + private final MutableBlockVector3[] allowed; + private MutableBlockVector3 next; public SurfaceRandomOffsetPattern(Pattern pattern, int distance) { this.pattern = pattern; this.moves = Math.min(255, distance); - init(); - } - - private void init() { cur = new MutableBlockVector3(); this.buffer = new MutableBlockVector3[BreadthFirstSearch.DIAGONAL_DIRECTIONS.length]; for (int i = 0; i < buffer.length; i++) { @@ -110,9 +107,4 @@ public class SurfaceRandomOffsetPattern extends AbstractPattern { BlockStateHolder block = pattern.apply(v); return !block.getBlockType().getMaterial().isMovementBlocker(); } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - init(); - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/queue/FaweQueueDelegateExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/queue/FaweQueueDelegateExtent.java index f2f67ab60..db0c437fe 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/queue/FaweQueueDelegateExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/queue/FaweQueueDelegateExtent.java @@ -49,7 +49,7 @@ public class FaweQueueDelegateExtent extends DelegateFaweQueue { @Override public int getCombinedId4Data(int x, int y, int z) throws FaweException.FaweChunkLoadException { - return getLazyBlock(x, y, z).getInternalId(); + return getBlock(x, y, z).getInternalId(); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/queue/IDelegateFaweQueue.java b/worldedit-core/src/main/java/com/boydti/fawe/object/queue/IDelegateFaweQueue.java index c88cca70b..3404c1553 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/queue/IDelegateFaweQueue.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/queue/IDelegateFaweQueue.java @@ -61,8 +61,8 @@ public interface IDelegateFaweQueue extends FaweQueue { } @Override - default BlockState getLazyBlock(int x, int y, int z) { - return getQueue().getLazyBlock(x, y, z); + default BlockState getBlock(int x, int y, int z) { + return getQueue().getBlock(x, y, z); } @Override @@ -453,11 +453,6 @@ public interface IDelegateFaweQueue extends FaweQueue { return getQueue().createEntity(location, entity); } - @Override - default BlockState getLazyBlock(BlockVector3 position) { - return getQueue().getLazyBlock(position); - } - @Nullable @Override default Operation commit() { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java b/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java index ae0989472..d764cc68d 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java @@ -1,25 +1,18 @@ package com.boydti.fawe.util; import com.boydti.fawe.Fawe; -import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.SingleFilterBlock; import com.boydti.fawe.config.Settings; -import com.boydti.fawe.object.pattern.PatternExtent; import com.boydti.fawe.util.image.ImageUtil; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; - -import com.sk89q.worldedit.util.command.binding.Text; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.registry.BlockMaterial; -import com.sk89q.worldedit.world.registry.BundledBlockData; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntArraySet; @@ -27,12 +20,23 @@ import it.unimi.dsi.fastutil.longs.LongArrayList; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; -import java.io.*; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Pattern; import java.util.zip.ZipEntry; @@ -61,14 +65,15 @@ public class TextureUtil implements TextureHolder { public static TextureUtil fromMask(Mask mask) throws FileNotFoundException { HashSet blocks = new HashSet<>(); - BlockPattern pattern = new BlockPattern(BlockTypes.AIR.getDefaultState()); - PatternExtent extent = new PatternExtent(pattern); + + SingleFilterBlock extent = new SingleFilterBlock(); new MaskTraverser(mask).reset(extent); + TextureUtil tu = Fawe.get().getTextureUtil(); for (int typeId : tu.getValidBlockIds()) { BlockType block = BlockTypes.get(typeId); - pattern.setBlock(block.getDefaultState()); - if (mask.test(BlockVector3.ZERO)) { + extent.init(0, 0, 0, block.getDefaultState().toBaseBlock()); + if (mask.test(extent)) { blocks.add(block); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/CuboidClipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/CuboidClipboard.java index af1392e4a..2e954e9a8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/CuboidClipboard.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/CuboidClipboard.java @@ -151,7 +151,7 @@ public class CuboidClipboard { /* ------------------------------------------------------------------------------------------------------------- */ - public BaseBlock getBlock(BlockVector3 position) { + public BaseBlock getLazyBlock(BlockVector3 position) { return getBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ()); } @@ -161,7 +161,7 @@ public class CuboidClipboard { return clipboard.IMP.getBlock(x, y, z); } - public BaseBlock getLazyBlock(BlockVector3 position) { + public BaseBlock getBlock(BlockVector3 position) { return getBlock(position); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index b4390ec65..035021a68 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -100,6 +100,7 @@ import com.sk89q.worldedit.function.mask.MaskUnion; import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.function.mask.NoiseFilter2D; import com.sk89q.worldedit.function.mask.RegionMask; +import com.sk89q.worldedit.function.mask.SingleBlockTypeMask; import com.sk89q.worldedit.function.mask.SolidBlockMask; import com.sk89q.worldedit.function.operation.ChangeSetExecutor; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; @@ -164,7 +165,9 @@ import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -203,15 +206,15 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, private final World world; private final String worldName; private final FaweQueue queue; - private final boolean wrapped; - private final boolean fastMode; + private boolean wrapped; + private boolean fastMode; private final HistoryExtent history; private AbstractDelegateExtent bypassHistory; private AbstractDelegateExtent bypassAll; private final FaweLimit originalLimit; private final FaweLimit limit; private final FawePlayer player; - private final FaweChangeSet changeTask; + private FaweChangeSet changeTask; private final MutableBlockVector3 mutablebv = new MutableBlockVector3(); @@ -294,6 +297,10 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, this(world, null, null, null, null, null, true, null, null, null, blockBag, eventBus, event); } + public void setExtent(AbstractDelegateExtent extent) { + new ExtentTraverser(this).setNext(extent); + } + /** * The limit for this specific edit (blocks etc) * @@ -552,7 +559,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @return mask, may be null */ public Mask getMask() { - ExtentTraverser maskingExtent = new ExtentTraverser(this.extent).find(MaskingExtent.class); + ExtentTraverser maskingExtent = new ExtentTraverser(getExtent()).find(MaskingExtent.class); return maskingExtent != null ? maskingExtent.get().getMask() : null; } @@ -562,28 +569,19 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @return mask, may be null */ public Mask getSourceMask() { - ExtentTraverser maskingExtent = new ExtentTraverser(this.extent).find(SourceMaskExtent.class); + ExtentTraverser maskingExtent = new ExtentTraverser(getExtent()).find(SourceMaskExtent.class); return maskingExtent != null ? maskingExtent.get().getMask() : null; } public void addTransform(ResettableExtent transform) { + checkNotNull(transform); wrapped = true; - if (transform == null) { - ExtentTraverser traverser = new ExtentTraverser(this.extent).find(ResettableExtent.class); - AbstractDelegateExtent next = extent; - while (traverser != null && traverser.get() instanceof ResettableExtent) { - traverser = traverser.next(); - next = traverser.get(); - } - this.extent = next; - return; - } else { - this.extent = transform.setExtent(extent); - } + transform.setExtent(getExtent()); + new ExtentTraverser(this).setNext(transform); } public @Nullable ResettableExtent getTransform() { - ExtentTraverser traverser = new ExtentTraverser(this.extent).find(ResettableExtent.class); + ExtentTraverser traverser = new ExtentTraverser(getExtent()).find(ResettableExtent.class); if (traverser != null) { return (ResettableExtent) traverser.get(); } @@ -601,7 +599,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, } else { new MaskTraverser(mask).reset(this); } - ExtentTraverser maskingExtent = new ExtentTraverser(this.extent).find(SourceMaskExtent.class); + ExtentTraverser maskingExtent = new ExtentTraverser(getExtent()).find(SourceMaskExtent.class); if (maskingExtent != null && maskingExtent.get() != null) { Mask oldMask = maskingExtent.get().getMask(); if (oldMask instanceof ResettableMask) { @@ -609,7 +607,8 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, } maskingExtent.get().setMask(mask); } else if (mask != Masks.alwaysTrue()) { - this.extent = new SourceMaskExtent(this.extent, mask); + SourceMaskExtent next = new SourceMaskExtent(getExtent(), mask); + new ExtentTraverser(this).setNext(next); } } @@ -618,13 +617,13 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, Mask existing = getSourceMask(); if (existing != null) { if (existing instanceof MaskIntersection) { - ((MaskIntersection) existing).add(mask); - return; + Collection masks = new HashSet<>(((MaskIntersection) existing).getMasks()); + masks.add(mask); + mask = new MaskIntersection(masks); } else { - MaskIntersection intersection = new MaskIntersection(existing); - intersection.add(mask); - mask = intersection; + mask = new MaskIntersection(existing, mask); } + mask = mask.optimize(); } setSourceMask(mask); } @@ -640,7 +639,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, } else { new MaskTraverser(mask).reset(this); } - ExtentTraverser maskingExtent = new ExtentTraverser(this.extent).find(MaskingExtent.class); + ExtentTraverser maskingExtent = new ExtentTraverser(getExtent()).find(MaskingExtent.class); if (maskingExtent != null && maskingExtent.get() != null) { Mask oldMask = maskingExtent.get().getMask(); if (oldMask instanceof ResettableMask) { @@ -648,7 +647,8 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, } maskingExtent.get().setMask(mask); } else if (mask != Masks.alwaysTrue()) { - this.extent = new MaskingExtent(this.extent, mask); + MaskingExtent next = new MaskingExtent(getExtent(), mask); + new ExtentTraverser(this).setNext(next); } } @@ -658,13 +658,12 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @return the survival simulation extent */ public SurvivalModeExtent getSurvivalExtent() { - ExtentTraverser survivalExtent = new ExtentTraverser(this.extent).find(SurvivalModeExtent.class); + ExtentTraverser survivalExtent = new ExtentTraverser(getExtent()).find(SurvivalModeExtent.class); if (survivalExtent != null) { return survivalExtent.get(); } else { - AbstractDelegateExtent extent = this.extent; - SurvivalModeExtent survival = new SurvivalModeExtent(extent.getExtent(), getWorld()); - new ExtentTraverser(extent).setNext(survival); + SurvivalModeExtent survival = new SurvivalModeExtent(bypassAll.getExtent(), getWorld()); + new ExtentTraverser(bypassAll).setNext(survival); return survival; } } @@ -691,7 +690,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, if (history == null) { return; } - ExtentTraverser traverseHistory = new ExtentTraverser(this.extent).find(HistoryExtent.class); + ExtentTraverser traverseHistory = new ExtentTraverser(getExtent()).find(HistoryExtent.class); if (disableHistory) { if (traverseHistory != null && traverseHistory.exists()) { ExtentTraverser beforeHistory = traverseHistory.previous(); @@ -699,11 +698,11 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, if (beforeHistory != null && beforeHistory.exists()) { beforeHistory.setNext(afterHistory.get()); } else { - extent = (AbstractDelegateExtent) afterHistory.get(); + new ExtentTraverser(this).setNext(afterHistory.get()); } } } else if (traverseHistory == null || !traverseHistory.exists()) { - ExtentTraverser traverseBypass = new ExtentTraverser(this.extent).find(bypassHistory); + ExtentTraverser traverseBypass = new ExtentTraverser(getExtent()).find(bypassHistory); if (traverseBypass != null) { ExtentTraverser beforeHistory = traverseBypass.previous(); beforeHistory.setNext(history); @@ -750,7 +749,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, if (changeSet instanceof BlockBagChangeSet) { missingBlocks = ((BlockBagChangeSet) changeSet).popMissing(); } else { - ExtentTraverser find = new ExtentTraverser(extent).find(BlockBagExtent.class); + ExtentTraverser find = new ExtentTraverser(getExtent()).find(BlockBagExtent.class); if (find != null && find.get() != null) { missingBlocks = find.get().popMissing(); } else { @@ -1068,7 +1067,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, @Override @Nullable public Entity createEntity(final com.sk89q.worldedit.util.Location location, final BaseEntity entity) { - Entity result = this.extent.createEntity(location, entity); + Entity result = getExtent().createEntity(location, entity); return result; } @@ -1142,30 +1141,22 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, @Override public BlockVector3 getMinimumPoint() { - if (extent != null) { - return this.extent.getMinimumPoint(); - } else { - return BlockVector3.at(-30000000, 0, -30000000); - } + return getExtent().getMinimumPoint(); } @Override public BlockVector3 getMaximumPoint() { - if (extent != null) { - return this.extent.getMaximumPoint(); - } else { - return BlockVector3.at(30000000, 255, 30000000); - } + return getExtent().getMaximumPoint(); } @Override public List getEntities(final Region region) { - return this.extent.getEntities(region); + return getExtent().getEntities(region); } @Override public List getEntities() { - return this.extent.getEntities(); + return getExtent().getEntities(); } /** @@ -1186,7 +1177,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, @Override public @Nullable Operation commit() { - return extent.commit(); + return getExtent().commit(); } /** @@ -1285,7 +1276,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @return the number of blocks that matched the pattern */ public int countBlocks(final Region region, final Set searchBlocks) { - Mask mask = new BlockMaskBuilder().addBlocks(searchBlocks).build(extent); + Mask mask = new BlockMaskBuilder().addBlocks(searchBlocks).build(getExtent()); RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() { @Override public boolean apply(BlockVector3 position) throws WorldEditException { @@ -1514,7 +1505,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, checkNotNull(position); checkArgument(apothem >= 1, "apothem >= 1"); - Mask mask = new BlockTypeMask(this, blockType); + Mask mask = new SingleBlockTypeMask(this, blockType); BlockVector3 adjustment = BlockVector3.ONE.multiply(apothem - 1); Region region = new CuboidRegion( getWorld(), // Causes clamping of Y range @@ -1542,12 +1533,12 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, } try { if (hasExtraExtents()) { - RegionVisitor visitor = new RegionVisitor(region, new BlockReplace(extent, (block)), this); + RegionVisitor visitor = new RegionVisitor(region, new BlockReplace(getExtent(), (block)), this); Operations.completeBlindly(visitor); this.changes += visitor.getAffected(); } else { for (BlockVector3 blockVector3 : region) { - if (this.extent.setBlock(blockVector3, block)) { + if (getExtent().setBlock(blockVector3, block)) { changes++; } } @@ -2004,7 +1995,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, new RegionMask(new EllipsoidRegion(null, origin, Vector3.at(radius, radius, radius))), blockMask); - BlockReplace replace = new BlockReplace(this, new BlockPattern(fluid.getDefaultState())); + BlockReplace replace = new BlockReplace(this, fluid.getDefaultState()); NonRisingVisitor visitor = new NonRisingVisitor(mask, replace); // Around the origin in a 3x3 block @@ -2917,7 +2908,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, } } this.changes++; - pattern.apply(this.extent, position, position); + pattern.apply(getExtent(), position, position); } } catch (WorldEditException e) { throw new RuntimeException(e); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/TileEntityBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/TileEntityBlock.java index 3c67bf0e8..c193e5f4c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/TileEntityBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/TileEntityBlock.java @@ -19,6 +19,9 @@ package com.sk89q.worldedit.blocks; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.world.NbtValued; /** @@ -34,6 +37,17 @@ public interface TileEntityBlock extends NbtValued { * * @return tile entity ID, non-null string */ - String getNbtId(); + default String getNbtId() { + CompoundTag nbtData = getNbtData(); + if (nbtData == null) { + return ""; + } + Tag idTag = nbtData.getValue().get("id"); + if (idTag instanceof StringTag) { + return ((StringTag) idTag).getValue(); + } else { + return ""; + } + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java index 4d222a1d5..fa09aa1a7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java @@ -235,7 +235,7 @@ public class PatternCommands extends MethodCommands { min = 2, max = 2 ) - public Pattern iddatamask(Actor actor, LocalSession session, Extent extent, @Range(min = 0, max = 15) int bitmask, Pattern pattern) { + public Pattern iddatamask(Extent extent, @Range(min = 0, max = 15) int bitmask, Pattern pattern) { return new IdDataMaskPattern(extent, pattern, bitmask); } @@ -246,7 +246,7 @@ public class PatternCommands extends MethodCommands { min = 1, max = 1 ) - public Pattern id(Actor actor, LocalSession session, Extent extent, Pattern pattern) { + public Pattern id(Extent extent, Pattern pattern) { return new IdPattern(extent, pattern); } @@ -257,7 +257,7 @@ public class PatternCommands extends MethodCommands { min = 1, max = 1 ) - public Pattern data(Actor actor, LocalSession session, Extent extent, Pattern pattern) { + public Pattern data(Extent extent, Pattern pattern) { return new DataPattern(extent, pattern); } @@ -268,7 +268,7 @@ public class PatternCommands extends MethodCommands { min = 1, max = 1 ) - public Pattern biome(Actor actor, LocalSession session, Extent extent, BiomeType biome) { + public Pattern biome(Extent extent, BiomeType biome) { return new BiomePattern(extent, biome); } @@ -279,7 +279,7 @@ public class PatternCommands extends MethodCommands { min = 1, max = 1 ) - public Pattern relative(Actor actor, LocalSession session, Extent extent, Pattern pattern) { + public Pattern relative(Pattern pattern) { return new RelativePattern(pattern); } @@ -292,7 +292,7 @@ public class PatternCommands extends MethodCommands { min = 1, max = 1 ) - public Pattern nox(Actor actor, LocalSession session, Extent extent, Pattern pattern) { + public Pattern nox(Pattern pattern) { return new NoXPattern(pattern); } @@ -303,7 +303,7 @@ public class PatternCommands extends MethodCommands { min = 1, max = 1 ) - public Pattern noy(Actor actor, LocalSession session, Extent extent, Pattern pattern) { + public Pattern noy(Pattern pattern) { return new NoYPattern(pattern); } @@ -314,7 +314,7 @@ public class PatternCommands extends MethodCommands { min = 1, max = 1 ) - public Pattern noz(Actor actor, LocalSession session, Extent extent, Pattern pattern) { + public Pattern noz(Pattern pattern) { return new NoZPattern(pattern); } @@ -325,9 +325,8 @@ public class PatternCommands extends MethodCommands { min = 3, max = 3 ) - public Pattern mask(Actor actor, LocalSession session, Mask mask, Pattern pass, Pattern fail) { - PatternExtent extent = new PatternExtent(pass); - return new MaskedPattern(mask, extent, fail); + public Pattern mask(Mask mask, Pattern pass, @Optional Pattern fail) { + return new MaskedPattern(mask, pass, fail); } @Command( @@ -337,7 +336,7 @@ public class PatternCommands extends MethodCommands { min = 4, max = 4 ) - public Pattern offset(Actor actor, LocalSession session, double x, double y, double z, Pattern pattern) { + public Pattern offset(double x, double y, double z, Pattern pattern) { return new OffsetPattern(pattern, (int) x, (int) y, (int) z); } @@ -348,7 +347,7 @@ public class PatternCommands extends MethodCommands { min = 2, max = 2 ) - public Pattern surfacespread(Actor actor, LocalSession session, double distance, Pattern pattern) { + public Pattern surfacespread(double distance, Pattern pattern) { return new SurfaceRandomOffsetPattern(pattern, (int) distance); } @@ -359,7 +358,7 @@ public class PatternCommands extends MethodCommands { min = 4, max = 4 ) - public Pattern solidspread(Actor actor, LocalSession session, double x, double y, double z, Pattern pattern) { + public Pattern solidspread(double x, double y, double z, Pattern pattern) { return new SolidRandomOffsetPattern(pattern, (int) x, (int) y, (int) z); } @@ -370,7 +369,7 @@ public class PatternCommands extends MethodCommands { min = 4, max = 4 ) - public Pattern spread(Actor actor, LocalSession session, double x, double y, double z, Pattern pattern) { + public Pattern spread(double x, double y, double z, Pattern pattern) { return new RandomOffsetPattern(pattern, (int) x, (int) y, (int) z); } @@ -381,7 +380,7 @@ public class PatternCommands extends MethodCommands { min = 1, max = 1 ) - public Pattern linear(Actor actor, LocalSession session, Pattern other) { + public Pattern linear(Pattern other) { if (other instanceof RandomPattern) { Set patterns = ((RandomPattern) other).getPatterns(); return new LinearBlockPattern(patterns.toArray(new Pattern[patterns.size()])); @@ -396,7 +395,7 @@ public class PatternCommands extends MethodCommands { min = 1, max = 1 ) - public Pattern linear3d(Actor actor, LocalSession session, Pattern other) { + public Pattern linear3d(Pattern other) { if (other instanceof RandomPattern) { Set patterns = ((RandomPattern) other).getPatterns(); return new Linear3DBlockPattern(patterns.toArray(new Pattern[patterns.size()])); @@ -411,7 +410,7 @@ public class PatternCommands extends MethodCommands { min = 1, max = 1 ) - public Pattern linear2d(Actor actor, LocalSession session, Pattern other) { + public Pattern linear2d(Pattern other) { if (other instanceof RandomPattern) { Set patterns = ((RandomPattern) other).getPatterns(); return new Linear2DBlockPattern(patterns.toArray(new Pattern[patterns.size()])); @@ -426,7 +425,7 @@ public class PatternCommands extends MethodCommands { min = 1, max = 1 ) - public Pattern expression(Actor actor, LocalSession session, Extent extent, String input) throws ExpressionException { + public Pattern expression(Extent extent, String input) throws ExpressionException { Expression exp = Expression.compile(input, "x", "y", "z"); WorldEditExpressionEnvironment env = new WorldEditExpressionEnvironment(extent, Vector3.ONE, Vector3.ZERO); exp.setEnvironment(env); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index 27d4d33a6..09ff62c4f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -25,6 +25,7 @@ import com.boydti.fawe.object.clipboard.URIClipboardHolder; import com.boydti.fawe.object.mask.IdMask; import com.boydti.fawe.object.regions.selector.FuzzyRegionSelector; import com.boydti.fawe.object.regions.selector.PolyhedralRegionSelector; +import com.boydti.fawe.util.ExtentTraverser; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandException; @@ -702,7 +703,7 @@ public class SelectionCommands { // TODO multi clipboard distribution Clipboard clipboard = session.getClipboard().getClipboard(); region = clipboard.getRegion(); - editSession.setExtent(new AbstractDelegateExtent(clipboard)); + new ExtentTraverser(editSession).setNext(new AbstractDelegateExtent(clipboard)); } else { region = session.getSelection(player.getWorld()); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java index 960be3c95..985f3f671 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java @@ -609,9 +609,6 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool .blockBag(null) .changeSetNull() .combineStages(false); - - builder.commit(); - EditSession editSession = builder.build(); VisualExtent newVisualExtent = new VisualExtent(builder.getExtent(), builder.getQueue()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java index 3bbaa8ca0..7c59cf4ea 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java @@ -57,7 +57,7 @@ public class AbstractDelegateExtent implements Extent, LightingExtent { * * @return the extent */ - public final Extent getExtent() { + public Extent getExtent() { return extent; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/NullExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/NullExtent.java index ec4c276a7..ac980a52f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/NullExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/NullExtent.java @@ -72,15 +72,10 @@ public class NullExtent implements Extent { return null; } - @Override public BlockState getBlock(BlockVector3 position) { return BlockTypes.AIR.getDefaultState(); } - public BlockState getLazyBlock(BlockVector3 position) { - return BlockTypes.AIR.getDefaultState(); - } - @Override public BaseBlock getFullBlock(BlockVector3 position) { return getBlock(position).toBaseBlock(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java index 819329d64..0765ad86c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java @@ -208,11 +208,6 @@ public class BlockArrayClipboard implements Clipboard, LightingExtent, Closeable return IMP.getBlock(x, y, z).toImmutableState(); } - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return getBlock(position); - } - @Override public BaseBlock getFullBlock(BlockVector3 position) { if(region.contains(position)) { @@ -290,11 +285,11 @@ public class BlockArrayClipboard implements Clipboard, LightingExtent, Closeable @Override public int getOpacity(int x, int y, int z) { - return getBlock(BlockVector3.at(x, y, z)).getBlockType().getMaterial().getLightOpacity(); + return getBlock(x, y, z).getBlockType().getMaterial().getLightOpacity(); } @Override public int getBrightness(int x, int y, int z) { - return getBlock(BlockVector3.at(x, y, z)).getBlockType().getMaterial().getLightValue(); + return getBlock(x, y, z).getBlockType().getMaterial().getLightValue(); } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java index 04ec91136..3e1641446 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java @@ -93,7 +93,7 @@ public class BlockBagExtent extends AbstractDelegateExtent { @Override public > boolean setBlock(int x, int y, int z, B block) throws WorldEditException { if(blockBag != null) { - BlockStateHolder lazyBlock = getExtent().getLazyBlock(x, y, z); + BlockStateHolder lazyBlock = getExtent().getBlock(x, y, z); BlockType fromType = lazyBlock.getBlockType(); if(!block.getBlockType().equals(fromType)) { BlockType type = block.getBlockType(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java index 1c1a9cdb4..0925430fa 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java @@ -442,8 +442,8 @@ public class BlockTransformExtent extends ResettableExtent { } @Override - public BlockState getLazyBlock(int x, int y, int z) { - return transform(super.getLazyBlock(x, y, z)); + public BlockState getBlock(int x, int y, int z) { + return transform(super.getBlock(x, y, z)); } @Override @@ -451,11 +451,6 @@ public class BlockTransformExtent extends ResettableExtent { return transform(super.getFullBlock(position)); } - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return transform(super.getLazyBlock(position)); - } - @Override public BlockState getBlock(BlockVector3 position) { return transform(super.getBlock(position)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ABlockMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ABlockMask.java new file mode 100644 index 000000000..5f26ef942 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ABlockMask.java @@ -0,0 +1,84 @@ +package com.sk89q.worldedit.function.mask; + +import com.boydti.fawe.util.StringMan; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.util.command.parametric.Optional; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +public abstract class ABlockMask extends AbstractExtentMask { + public ABlockMask(Extent extent) { + super(extent); + } + + public abstract boolean test(BlockState state); + + @Override + public String toString() { + List strings = new ArrayList<>(); + for (BlockType type : BlockTypes.values) { + if (type != null) { + boolean hasAll = true; + boolean hasAny = false; + List all = type.getAllStates(); + for (BlockState state : all) { + hasAll &= test(state); + hasAny = true; + } + if (hasAll) { + strings.add(type.getId()); + } else if (hasAny) { + for (BlockState state : all) { + if (test(state)) { + strings.add(state.getAsString()); + } + } + } + } + } + return StringMan.join(strings, ","); + } + + @Override + public Mask and(Mask mask) { + if (mask instanceof ABlockMask) { + ABlockMask other = (ABlockMask) mask; + BlockMask newMask = new BlockMask(getExtent()); + for (BlockState state : BlockTypes.states) { + if (state != null) { + if (test(state) && other.test(state)) { + newMask.add(state); + } + } + } + Mask tmp = newMask.optimize(); + if (tmp == null) tmp = newMask; + return tmp; + } + return null; + } + + @Override + public Mask or(Mask mask) { + if (mask instanceof ABlockMask) { + ABlockMask other = (ABlockMask) mask; + BlockMask newMask = new BlockMask(getExtent()); + for (BlockState state : BlockTypes.states) { + if (state != null) { + if (test(state) || other.test(state)) { + newMask.add(state); + } + } + } + Mask tmp = newMask.optimize(); + if (tmp == null) tmp = newMask; + return tmp; + } + return null; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/AbstractExtentMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/AbstractExtentMask.java index dbb3f28cc..a5478156c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/AbstractExtentMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/AbstractExtentMask.java @@ -44,7 +44,7 @@ public abstract class AbstractExtentMask extends AbstractMask { * * @return the extent */ - public Extent getExtent() { + public final Extent getExtent() { return extent; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java index 625d8b781..024630cd0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.function.mask; import static com.google.common.base.Preconditions.checkNotNull; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockCategory; @@ -42,7 +43,7 @@ public class BlockCategoryMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - return category.contains(getExtent().getBlock(vector)); + return category.contains(vector.getBlock(getExtent())); } @Nullable diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java index 1e5a2e8e3..6e3598513 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java @@ -1,250 +1,194 @@ package com.sk89q.worldedit.function.mask; -import com.boydti.fawe.object.collection.FastBitSet; -import com.boydti.fawe.util.MainUtil; -import com.boydti.fawe.util.StringMan; -import com.sk89q.worldedit.extent.NullExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.registry.state.AbstractProperty; -import com.sk89q.worldedit.registry.state.Property; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; + import java.util.Arrays; import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -import javax.annotation.Nullable; -import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; +import java.util.function.Predicate; -/** - * A mask that checks whether blocks at the given positions are matched by - * a block in a list. - * - *

This mask checks for both an exact block type and state value match, - * respecting fuzzy status of the BlockState.

- */ -public class BlockMask extends AbstractExtentMask { +public class BlockMask extends ABlockMask { + private final boolean[] ordinals; - private final long[][] bitSets; - protected final static long[] ALL = new long[0]; + public BlockMask(Extent extent) { + this(extent, new boolean[BlockTypes.states.length]); + } + public BlockMask(Extent extent, boolean[] ordinals) { + super(extent); + this.ordinals = ordinals; + } + + /** + * @deprecated NBT not supported by this mask + */ @Deprecated public BlockMask(Extent extent, Collection blocks) { - super(extent); - MainUtil.warnDeprecated(BlockMaskBuilder.class); - this.bitSets = new BlockMaskBuilder().addBlocks(blocks).optimize().getBits(); + this(extent); + add(blocks); } + public BlockMask add(Predicate predicate) { + for (int i = 0; i < ordinals.length; i++) { + if (!ordinals[i]) { + BlockState state = BlockTypes.states[i]; + if (state != null) ordinals[i] = predicate.test(state); + } + } + return this; + } + + public BlockMask add(BlockState... states) { + addStates(Arrays.asList(states)); + return this; + } + + public BlockMask addStates(Collection states) { + for (BlockState state : states) ordinals[state.getOrdinal()] = true; + return this; + } + + public BlockMask add(BlockType... types) { + addTypes(Arrays.asList(types)); + return this; + } + + public BlockMask addTypes(Collection types) { + for (BlockType type : types) { + for (BlockState state : type.getAllStates()) { + ordinals[state.getOrdinal()] = true; + } + } + return this; + } + + /** + * @deprecated NBT not supported by this mask + */ @Deprecated - public BlockMask(Extent extent, BaseBlock... blocks) { - super(extent); - MainUtil.warnDeprecated(BlockMaskBuilder.class); - this.bitSets = new BlockMaskBuilder().addBlocks(blocks).optimize().getBits(); - } - - public BlockMask() { - super(NullExtent.INSTANCE); - this.bitSets = new long[BlockTypes.size()][]; - } - - protected BlockMask(Extent extent, long[][] bitSets) { - super(extent); - this.bitSets = bitSets; - } - - public BlockMaskBuilder toBuilder() { - return new BlockMaskBuilder(this.bitSets); + public void add(Collection blocks) { + for (BaseBlock block : blocks) { + add(block.toBlockState()); + } } @Override - public String toString() { - List strings = new ArrayList<>(); - for (int i = 0; i < bitSets.length; i++) { - if (bitSets[i] != null) { - long[] set = bitSets[i]; - BlockType type = BlockTypes.get(i); - if (set == ALL) { - strings.add(type.getId()); - } else { - for (BlockState state : type.getAllStates()) { - if (test(state)) { - strings.add(state.getAsString()); - } - } - } - } - } - return StringMan.join(strings, ","); + public boolean test(BlockState state) { + return ordinals[state.getOrdinal()]; } @Override - public Mask optimize() { - Map states = new HashMap<>(); - int indexFound = -1; - { - int indexNull = -1; - int indexAll = -1; - for (int i = 0; i < bitSets.length; i++) { - long[] bs = bitSets[i]; - if (bs == null) { - indexNull = i; - states.put(null, states.getOrDefault(null, 0) + 1); - } else if (bs.length == 0) { - indexAll = i; - states.put(ALL, states.getOrDefault(ALL, 0) + 1); - } else if (indexFound == -1) { - indexFound = i; - } else { - return this; - } - } - // Only types, no states - if (indexFound == -1) { - if (states.size() == 1) { - return states.keySet().iterator().next() == null ? Masks.alwaysFalse() : Masks.alwaysTrue(); - } - if (states.get(ALL) == 1) return new SingleBlockTypeMask(getExtent(), BlockTypes.get(indexAll)); - if (states.get(null) == 1) - return new SingleBlockTypeMask(getExtent(), BlockTypes.get(indexNull)).inverse(); - - boolean[] types = new boolean[BlockTypes.size()]; - for (int i = 0; i < bitSets.length; i++) { - if (bitSets[i].length == 0) types[i] = true; - } - return new BlockTypeMask(getExtent(), types); - } - } - BlockType type = BlockTypes.get(indexFound); - { - Mask mask = getOptimizedMask(type, bitSets[indexFound]); - if (mask == null) { // Try with inverse - long[] newBitSet = bitSets[indexFound]; - for (int i = 0; i < newBitSet.length; i++) newBitSet[i] = ~newBitSet[i]; - mask = getOptimizedMask(type, bitSets[indexFound]); - if (mask != null) mask = mask.inverse(); - } - return mask; - } - } - - private Mask getOptimizedMask(BlockType type, long[] bitSet) { - boolean single = true; - int and = type.getInternalId(); - List properties = type.getProperties(); - for (AbstractProperty prop : (List>) type.getProperties()) { - List values = prop.getValues(); - int numSet = 0; - for (int i = 0; i < values.size(); i++) { - int localI = i << prop.getBitOffset(); - if (FastBitSet.get(bitSet, localI)) { - numSet++; - and |= prop.modify(and, i); - } - } - // Cannot optimize multiple property values - use current mask (null) - if (numSet != values.size() && numSet != 1) { - return null; - } - single = single && numSet == 1; - } - if (single) - return new SingleBlockStateMask(getExtent(), BlockState.getFromInternalId(and)); - return new SingleBlockStateBitMask(getExtent(), and); + public boolean test(BlockVector3 vector) { + return ordinals[vector.getOrdinal(getExtent())]; } @Override - public Mask and(Mask other) { - if (other instanceof BlockMask) { - long[][] otherBitSets = ((BlockMask) other).bitSets; - for (int i = 0; i < otherBitSets.length; i++) { - long[] otherBitSet = otherBitSets[i]; - long[] bitSet = bitSets[i]; - if (otherBitSet == null) bitSets[i] = null; - else if (otherBitSet.length == 0) continue; - else if (bitSet == null) continue; - else if (bitSet.length == 0) bitSets[i] = otherBitSet; - else for (int j = 0; j < otherBitSet.length; j++) bitSet[j] &= otherBitSet[j]; + public Mask and(Mask mask) { + if (mask instanceof ABlockMask) { + ABlockMask other = (ABlockMask) mask; + for (int i = 0; i < ordinals.length; i++) { + if (ordinals[i]) { + ordinals[i] = other.test(BlockState.getFromOrdinal(i)); + } } return this; } - if (other instanceof SingleBlockStateMask) { - return new BlockMaskBuilder(bitSets).filter(((SingleBlockStateMask) other).getBlockState()).build(getExtent()); - } - if (other instanceof SingleBlockTypeMask) { - return new BlockMaskBuilder(bitSets).filter(((SingleBlockTypeMask) other).getBlockType()).build(getExtent()); - } return null; } @Override - public Mask or(Mask other) { - if (other instanceof BlockMask) { - long[][] otherBitSets = ((BlockMask) other).bitSets; - for (int i = 0; i < otherBitSets.length; i++) { - long[] otherBitSet = otherBitSets[i]; - long[] bitSet = bitSets[i]; - if (otherBitSet == null) continue; - else if (otherBitSet.length == 0) bitSets[i] = ALL; - else if (bitSet == null) bitSets[i] = otherBitSet; - else if (bitSet.length == 0) continue; - else for (int j = 0; j < otherBitSet.length; j++) bitSet[j] |= otherBitSet[j]; + public Mask or(Mask mask) { + if (mask instanceof ABlockMask) { + ABlockMask other = (ABlockMask) mask; + for (int i = 0; i < ordinals.length; i++) { + if (!ordinals[i]) { + ordinals[i] = other.test(BlockState.getFromOrdinal(i)); + } } return this; } - if (other instanceof SingleBlockStateMask) { - return new BlockMaskBuilder(bitSets).add(((SingleBlockStateMask) other).getBlockState()).build(getExtent()); + return null; + } + + @Override + public Mask optimize() { + int setStates = 0; + BlockState setState = null; + BlockState unsetState = null; + int totalStates = 0; + + int setTypes = 0; + BlockType setType = null; + BlockType unsetType = null; + int totalTypes = 0; + + for (BlockType type : BlockTypes.values) { + if (type != null) { + totalTypes++; + boolean hasAll = true; + boolean hasAny = false; + List all = type.getAllStates(); + for (BlockState state : all) { + totalStates++; + hasAll &= test(state); + hasAny = true; + } + if (hasAll) { + setTypes++; + setType = type; + setStates += all.size(); + setState = type.getDefaultState(); + } else if (hasAny) { + for (BlockState state : all) { + if (test(state)) { + setStates++; + setState = state; + } else { + unsetState = state; + } + } + } else { + unsetType = type; + } + } } - if (other instanceof SingleBlockTypeMask) { - return new BlockMaskBuilder(bitSets).add(((SingleBlockTypeMask) other).getBlockType()).build(getExtent()); + if (setStates == 0) { + return Masks.alwaysFalse(); } + if (setStates == totalStates) { + return Masks.alwaysTrue(); + } + + if (setStates == 1) { + return new SingleBlockStateMask(getExtent(), setState); + } + + if (setStates == totalStates - 1) { + return new InverseSingleBlockStateMask(getExtent(), unsetState); + } + + if (setTypes == 1) { + return new SingleBlockTypeMask(getExtent(), setType); + } + + if (setTypes == totalTypes - 1) { + return new InverseSingleBlockTypeMask(getExtent(), unsetType); + } + return null; } @Override public Mask inverse() { - long[][] cloned = bitSets.clone(); - for (int i = 0; i < cloned.length; i++) { - if (cloned[i] == null) cloned[i] = ALL; - else if (cloned[i] == ALL) cloned[i] = null; - else { - for (int j = 0; j < cloned[i].length; j++) - cloned[i][j] = ~cloned[i][j]; - } - } + boolean[] cloned = ordinals.clone(); + for (int i = 0; i < cloned.length; i++) cloned[i] = !cloned[i]; return new BlockMask(getExtent(), cloned); } - public boolean test(BlockState block) { - long[] bitSet = bitSets[block.getInternalBlockTypeId()]; - if (bitSet == null) return false; - if (bitSet.length == 0) return true; - return FastBitSet.get(bitSet, block.getInternalPropertiesId()); - } - @Override - public boolean test(BlockVector3 vector) { - BlockStateHolder block = getExtent().getBlock(vector); - long[] bitSet = bitSets[block.getInternalBlockTypeId()]; - if (bitSet == null) return false; - if (bitSet.length == 0) return true; - return FastBitSet.get(bitSet, block.getInternalPropertiesId()); - } - - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } - - -} \ No newline at end of file +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMaskBuilder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMaskBuilder.java index 5036a87c4..1c9bea628 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMaskBuilder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMaskBuilder.java @@ -30,6 +30,8 @@ public class BlockMaskBuilder { private static final Operator LESS_EQUAL = (a, b) -> a <= b; private static final Operator NOT = (a, b) -> a != b; + private final static long[] ALL = new long[0]; + private interface Operator { boolean test(int left, int right); } @@ -222,7 +224,7 @@ public class BlockMaskBuilder { if (states == null) return false; List values = prop.getValues(); int localI = index << prop.getBitOffset() >> BlockTypes.BIT_OFFSET; - return (states == BlockMask.ALL || FastBitSet.get(states, localI)); + return (states == ALL || FastBitSet.get(states, localI)); } private void suggest(String input, String property, Collection finalTypes) throws InputParseException { @@ -239,6 +241,7 @@ public class BlockMaskBuilder { ///// end internal ///// private long[][] bitSets; + private boolean[] ordinals; private boolean optimizedStates = true; @@ -257,23 +260,24 @@ public class BlockMaskBuilder { this.bitSets = bitSets; } - public BlockMaskBuilder parse(String input) { + public BlockMaskBuilder addAll() { + for (int i = 0; i < bitSets.length; i++) { + bitSets[i] = ALL; + } + reset(true); return this; } - public BlockMaskBuilder addAll() { - for (int i = 0; i < bitSets.length; i++) { - bitSets[i] = BlockMask.ALL; - } - optimizedStates = true; - return this; + private void reset(boolean optimized) { + this.ordinals = null; + this.optimizedStates = optimized; } public BlockMaskBuilder clear() { for (int i = 0; i < bitSets.length; i++) { bitSets[i] = null; } - optimizedStates = true; + reset(true); return this; } @@ -287,13 +291,13 @@ public class BlockMaskBuilder { int i = type.getInternalId(); long[] states = bitSets[i]; if (states != null) { - if (states == BlockMask.ALL) { + if (states == ALL) { bitSets[i] = states = FastBitSet.create(type.getMaxStateId() + 1); Arrays.fill(states, -1); } int stateId = state.getInternalPropertiesId(); FastBitSet.clear(states, stateId); - optimizedStates = false; + reset(false); } return this; } @@ -315,7 +319,7 @@ public class BlockMaskBuilder { if (states != null) { int stateId = state.getInternalPropertiesId(); boolean set = true; - if (states == BlockMask.ALL) { + if (states == ALL) { bitSets[i] = states = FastBitSet.create(type.getMaxStateId() + 1); } else { set = FastBitSet.get(states, stateId); @@ -325,7 +329,7 @@ public class BlockMaskBuilder { FastBitSet.set(states, stateId); else bitSets[i] = null; - optimizedStates = true; + reset(true); } return this; } @@ -354,14 +358,14 @@ public class BlockMaskBuilder { List values = prop.getValues(); for (int j = 0; j < values.size(); j++) { int localI = j << prop.getBitOffset() >> BlockTypes.BIT_OFFSET; - if (states == BlockMask.ALL || FastBitSet.get(states, localI)) { + if (states == ALL || FastBitSet.get(states, localI)) { if (!allowed.test(type, new AbstractMap.SimpleEntry(prop, values.get(j)))) { - if (states == BlockMask.ALL) { + if (states == ALL) { bitSets[i] = states = FastBitSet.create(type.getMaxStateId() + 1); FastBitSet.setAll(states); } FastBitSet.clear(states, localI); - optimizedStates = false; + reset(false); } } } @@ -371,7 +375,7 @@ public class BlockMaskBuilder { } public BlockMaskBuilder add(BlockType type) { - bitSets[type.getInternalId()] = BlockMask.ALL; + bitSets[type.getInternalId()] = ALL; return this; } @@ -379,13 +383,13 @@ public class BlockMaskBuilder { BlockType type = state.getBlockType(); int i = type.getInternalId(); long[] states = bitSets[i]; - if (states != BlockMask.ALL) { + if (states != ALL) { if (states == null) { bitSets[i] = states = FastBitSet.create(type.getMaxStateId() + 1); } int stateId = state.getInternalPropertiesId(); FastBitSet.set(states, stateId); - optimizedStates = false; + reset(false); } return this; } @@ -414,7 +418,7 @@ public class BlockMaskBuilder { for (int i = 0; i < bitSets.length; i++) { BlockType type = BlockTypes.get(i); if (allow.test(type)) { - bitSets[i] = BlockMask.ALL; + bitSets[i] = ALL; } } return this; @@ -423,7 +427,7 @@ public class BlockMaskBuilder { public BlockMaskBuilder addAll(Predicate typePredicate, BiPredicate, ?>> propPredicate) { for (int i = 0; i < bitSets.length; i++) { long[] states = bitSets[i]; - if (states == BlockMask.ALL) continue; + if (states == ALL) continue; BlockType type = BlockTypes.get(i); if (!typePredicate.test(type)) { continue; @@ -438,7 +442,7 @@ public class BlockMaskBuilder { bitSets[i] = states = FastBitSet.create(type.getMaxStateId() + 1); } FastBitSet.set(states, localI); - optimizedStates = false; + reset(false); } } } @@ -450,7 +454,7 @@ public class BlockMaskBuilder { public BlockMaskBuilder add(BlockType type, Property property, int index) { AbstractProperty prop = (AbstractProperty) property; long[] states = bitSets[type.getInternalId()]; - if (states == BlockMask.ALL) return this; + if (states == ALL) return this; List values = property.getValues(); int localI = index << prop.getBitOffset() >> BlockTypes.BIT_OFFSET; @@ -459,7 +463,7 @@ public class BlockMaskBuilder { bitSets[type.getInternalId()] = states = FastBitSet.create(type.getMaxStateId() + 1); } set(type, states, property, index); - optimizedStates = false; + reset(false); } return this; } @@ -470,13 +474,13 @@ public class BlockMaskBuilder { if (states == null) return this; List values = property.getValues(); int localI = index << prop.getBitOffset() >> BlockTypes.BIT_OFFSET; - if (states == BlockMask.ALL || FastBitSet.get(states, localI)) { - if (states == BlockMask.ALL) { + if (states == ALL || FastBitSet.get(states, localI)) { + if (states == ALL) { bitSets[type.getInternalId()] = states = FastBitSet.create(type.getMaxStateId() + 1); FastBitSet.setAll(states); } clear(type, states, property, index); - optimizedStates = false; + reset(false); } return this; } @@ -522,7 +526,7 @@ public class BlockMaskBuilder { if (!optimizedStates) { for (int i = 0; i < bitSets.length; i++) { long[] bitSet = bitSets[i]; - if (bitSet == null || bitSet == BlockMask.ALL) continue; + if (bitSet == null || bitSet == ALL) continue; BlockType type = BlockTypes.get(i); int maxStateId = type.getMaxStateId(); if (maxStateId == 0) { @@ -530,7 +534,7 @@ public class BlockMaskBuilder { bitSets[i] = null; continue; } else { - bitSets[i] = BlockMask.ALL; + bitSets[i] = ALL; continue; } } @@ -545,19 +549,38 @@ public class BlockMaskBuilder { } } if (set == 0) bitSets[i] = null; - else if (clear == 0) bitSets[i] = BlockMask.ALL; + else if (clear == 0) bitSets[i] = ALL; } - optimizedStates = true; + reset(true); } return this; } - protected long[][] getBits() { - return this.bitSets; + private boolean[] getOrdinals() { + if (ordinals == null) { + ordinals = new boolean[BlockTypes.states.length]; + for (int i = 0; i < BlockTypes.values.length; i++) { + long[] bitSet = bitSets[i]; + if (bitSet == null) continue; + BlockType type = BlockTypes.values[i]; + if (bitSet == ALL) { + for (BlockState state : type.getAllStates()) { + ordinals[state.getOrdinal()] = true; + } + } else { + for (BlockState state : type.getAllStates()) { + if (FastBitSet.get(bitSet, state.getInternalPropertiesId())) { + ordinals[state.getOrdinal()] = true; + } + } + + } + } + } + return ordinals; } public BlockMask build(Extent extent) { - optimize(); - return new BlockMask(extent, bitSets); + return new BlockMask(extent, getOrdinals()); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java index 69e47039d..e78f9b9be 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.function.mask; +import com.boydti.fawe.beta.FilterBlock; import com.google.common.collect.Maps; import com.sk89q.worldedit.blocks.Blocks; import com.sk89q.worldedit.extent.Extent; @@ -30,6 +31,7 @@ import com.sk89q.worldedit.world.block.BlockType; import javax.annotation.Nullable; import java.util.Map; +@Deprecated public class BlockStateMask extends AbstractExtentMask { private final Map states; @@ -52,7 +54,10 @@ public class BlockStateMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - BlockState block = getExtent().getBlock(vector); + return test(vector.getBlock(getExtent())); + } + + public boolean test(BlockState block) { final Map, Object> checkProps = cache .computeIfAbsent(block.getBlockType(), (b -> Blocks.resolveProperties(states, b))); if (strict && checkProps.isEmpty()) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java index c15c3d354..0dab694ca 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java @@ -1,20 +1,18 @@ package com.sk89q.worldedit.function.mask; -import static com.google.common.base.Preconditions.checkNotNull; - import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; +import javax.annotation.Nullable; import java.util.Collection; import java.util.HashSet; import java.util.Set; -import javax.annotation.Nullable; - import static com.google.common.base.Preconditions.checkNotNull; +@Deprecated public class BlockTypeMask extends AbstractExtentMask { private final boolean[] types; @@ -80,11 +78,12 @@ public class BlockTypeMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - return types[getExtent().getBlockType(vector).getInternalId()]; + return test(vector.getBlock(getExtent()).getBlockType()); + } + + public boolean test(BlockType block) { + return types[block.getInternalId()]; } -// public boolean test(BlockVector3 vector) { -// return blocks.contains(getExtent().getBlock(vector).getBlockType()); -// } @Nullable @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java index 2f72d5a1d..211a47628 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.function.mask; import static com.google.common.base.Preconditions.checkArgument; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.math.BlockVector3; import javax.annotation.Nullable; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java index ac4d24452..fbba26a97 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.function.mask; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; @@ -41,7 +42,7 @@ public class ExistingBlockMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - return !getExtent().getBlock(vector).getBlockType().getMaterial().isAir(); + return !vector.getBlock(getExtent()).getMaterial().isAir(); } @Nullable diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask.java index 52e0f345d..7048a3203 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.function.mask; import static com.google.common.base.Preconditions.checkNotNull; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.ExpressionException; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseMask.java index 3999dfc44..4a22ef5fd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseMask.java @@ -2,6 +2,7 @@ package com.sk89q.worldedit.function.mask; import javax.annotation.Nullable; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.math.BlockVector3; public class InverseMask extends AbstractMask { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockStateMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockStateMask.java new file mode 100644 index 000000000..024a61812 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockStateMask.java @@ -0,0 +1,38 @@ +package com.sk89q.worldedit.function.mask; + +import com.boydti.fawe.beta.FilterBlock; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.Arrays; + +public class InverseSingleBlockStateMask extends ABlockMask { + private final char ordinal; + + public BlockStateHolder getBlockState() { + return BlockState.getFromOrdinal(ordinal); + } + + public InverseSingleBlockStateMask(Extent extent, BlockState state) { + super(extent); + this.ordinal = state.getOrdinalChar(); + } + + @Override + public boolean test(BlockVector3 vector) { + return ordinal != vector.getOrdinal(getExtent()); + } + + @Override + public final boolean test(BlockState state) { + return state.getOrdinalChar() != ordinal; + } + + @Override + public Mask inverse() { + return new SingleBlockStateMask(getExtent(), BlockState.getFromOrdinal(ordinal)); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockTypeMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockTypeMask.java new file mode 100644 index 000000000..8c800a743 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockTypeMask.java @@ -0,0 +1,37 @@ +package com.sk89q.worldedit.function.mask; + +import com.boydti.fawe.beta.FilterBlock; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; + +public class InverseSingleBlockTypeMask extends ABlockMask { + private final int internalId; + + public InverseSingleBlockTypeMask(Extent extent, BlockType type) { + super(extent); + this.internalId = type.getInternalId(); + } + + @Override + public boolean test(BlockVector3 vector) { + return test(vector.getBlock(getExtent())); + } + + @Override + public final boolean test(BlockState state) { + return state.getBlockType().getInternalId() != internalId; + } + + @Override + public Mask inverse() { + return new SingleBlockTypeMask(getExtent(), BlockTypes.values[internalId]); + } + + public BlockType getBlockType() { + return BlockTypes.get(internalId); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java index 05e22d9d2..870c292aa 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java @@ -43,8 +43,6 @@ public interface Mask { */ boolean test(BlockVector3 vector); -// boolean test(FilterBlock block); - /** * Get the 2D version of this mask if one exists. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java index 844f319a7..8ba471db7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.function.mask; +import com.boydti.fawe.beta.FilterBlock; import com.google.common.base.Function; import com.sk89q.worldedit.math.BlockVector3; @@ -168,10 +169,6 @@ public class MaskIntersection extends AbstractMask { @Override public boolean test(BlockVector3 vector) { - if (masks.isEmpty()) { - return false; - } - for (Mask mask : masksArray) { if (!mask.test(vector)) { return false; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java index a3ac57a03..6e0d79e2a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.function.mask; +import com.boydti.fawe.beta.FilterBlock; import com.google.common.base.Function; import com.sk89q.worldedit.math.BlockVector3; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Masks.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Masks.java index 1a70e02b2..f7d2d73dc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Masks.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Masks.java @@ -2,6 +2,7 @@ package com.sk89q.worldedit.function.mask; import static com.google.common.base.Preconditions.checkNotNull; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; @@ -52,7 +53,6 @@ public final class Masks { * @param finalMask the mask * @return a new mask */ -//<<<<<<< HEAD public static Mask negate(final Mask finalMask) { return finalMask.inverse(); } @@ -124,7 +124,7 @@ public final class Masks { @Override public Mask or(Mask other) { - return other; + return this; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java index ee9b6e44d..97a27c510 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java @@ -22,7 +22,9 @@ package com.sk89q.worldedit.function.mask; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MutableVector3; import com.sk89q.worldedit.math.noise.NoiseGenerator; import javax.annotation.Nullable; @@ -85,8 +87,8 @@ public class NoiseFilter extends AbstractMask { } @Override - public boolean test(BlockVector3 vector) { - return noiseGenerator.noise(vector.toVector3()) <= density; + public boolean test(BlockVector3 v) { + return noiseGenerator.noise(MutableVector3.get(v.getX(), v.getY(), v.getZ())) <= density; } @Nullable diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java index b5e149dd5..8b9e7c477 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java @@ -2,6 +2,7 @@ package com.sk89q.worldedit.function.mask; import static com.google.common.base.Preconditions.checkNotNull; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.math.BlockVector3; import javax.annotation.Nullable; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/RegionMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/RegionMask.java index 28df2c206..eecd57652 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/RegionMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/RegionMask.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.function.mask; import static com.google.common.base.Preconditions.checkNotNull; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockStateBitMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockStateBitMask.java deleted file mode 100644 index 24da28c8f..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockStateBitMask.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.sk89q.worldedit.function.mask; - -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.math.BlockVector3; - -public class SingleBlockStateBitMask extends AbstractExtentMask { - private final int bitMask; - - protected SingleBlockStateBitMask(Extent extent, int bitMask) { - super(extent); - this.bitMask = bitMask; - } - - @Override - public boolean test(BlockVector3 vector) { - int internalId = getExtent().getBlock(vector).getInternalId(); - return (internalId & bitMask) == internalId; - } -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockStateMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockStateMask.java index e8514dafc..3507571e8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockStateMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockStateMask.java @@ -1,29 +1,50 @@ package com.sk89q.worldedit.function.mask; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; -public class SingleBlockStateMask extends AbstractExtentMask { - private final BlockStateHolder state; +import java.util.Arrays; + +public class SingleBlockStateMask extends ABlockMask { + private final char ordinal; public BlockStateHolder getBlockState() { - return state; + return BlockState.getFromOrdinal(ordinal); } - public SingleBlockStateMask(Extent extent, BlockStateHolder state) { + public SingleBlockStateMask(Extent extent, BlockState state) { super(extent); - this.state = state; + this.ordinal = state.getOrdinalChar(); } @Override public boolean test(BlockVector3 vector) { - return state.equals(getExtent().getBlock(vector)); + return ordinal == vector.getOrdinal(getExtent()); + } + + @Override + public final boolean test(BlockState state) { + return state.getOrdinalChar() == ordinal; } @Override public Mask inverse() { - return new BlockMaskBuilder().add(state).build(getExtent()).inverse(); + return new InverseSingleBlockStateMask(getExtent(), BlockState.getFromOrdinal(ordinal)); + } + + @Override + public Mask and(Mask mask) { + if (mask instanceof ABlockMask) { + ABlockMask other = (ABlockMask) mask; + if (other.test(BlockState.getFromOrdinal(ordinal))) { + return this; + } + return Masks.alwaysFalse(); + } + return null; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockTypeMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockTypeMask.java index 2f26b1aed..a6069d8bd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockTypeMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockTypeMask.java @@ -1,12 +1,14 @@ package com.sk89q.worldedit.function.mask; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; -public class SingleBlockTypeMask extends AbstractExtentMask { +public class SingleBlockTypeMask extends ABlockMask { private final int internalId; public SingleBlockTypeMask(Extent extent, BlockType type) { @@ -16,12 +18,17 @@ public class SingleBlockTypeMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - return getExtent().getBlockType(vector).getInternalId() == internalId; + return test(vector.getBlock(getExtent())); + } + + @Override + public final boolean test(BlockState state) { + return state.getBlockType().getInternalId() == internalId; } @Override public Mask inverse() { - return new BlockMaskBuilder().add(BlockTypes.get(internalId)).build(getExtent()).inverse(); + return new InverseSingleBlockTypeMask(getExtent(), BlockTypes.values[internalId]); } public BlockType getBlockType() { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java index 19afced40..634a1d50c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java @@ -1,39 +1,12 @@ package com.sk89q.worldedit.function.mask; import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.world.block.BlockTypes; -import javax.annotation.Nullable; - -public class SolidBlockMask extends BlockTypeMask { - - public static boolean[] getTypes() { - boolean[] types = new boolean[BlockTypes.size()]; - for (BlockType type : BlockTypes.values) { - types[type.getInternalId()] = type.getMaterial().isSolid(); - } - return types; - } - +public class SolidBlockMask extends BlockMask { public SolidBlockMask(Extent extent) { - super(extent, getTypes()); + super(extent); + add(state -> state.getMaterial().isSolid()); } - @Override - public boolean test(BlockVector3 vector) { - Extent extent = getExtent(); - BlockState block = extent.getBlock(vector); - return block.getBlockType().getMaterial().isMovementBlocker(); - } - - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } - - } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java index 8f0560364..76ecddd3c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.function.pattern; import static com.google.common.base.Preconditions.checkNotNull; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -63,5 +64,4 @@ public class BlockPattern extends AbstractPattern { public BaseBlock apply(BlockVector3 position) { return block; } - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java index 93eeb07a5..3ed94f36d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java @@ -43,12 +43,6 @@ public interface Pattern { BaseBlock apply(BlockVector3 position); default boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - return extent.setBlock(set, apply(get)); - } - -// void apply(FilterBlock block); - - default void apply(FilterBlock block) { - apply((BlockVector3) block).apply(block); + return set.setFullBlock(extent, apply(get)); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java index 083dbee10..d4b2995a3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java @@ -1,5 +1,6 @@ package com.sk89q.worldedit.function.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.object.collection.RandomCollection; import com.boydti.fawe.object.random.SimpleRandom; import com.boydti.fawe.object.random.TrueRandom; @@ -69,8 +70,8 @@ public class RandomPattern extends AbstractPattern { } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { - return collection.next(get.getBlockX(), get.getBlockY(), get.getBlockZ()).apply(extent, set, get); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + return collection.next(get.getBlockX(), get.getBlockY(), get.getBlockZ()).apply(extent, get, set); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java index 61d52823d..bbb2139e2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.function.pattern; import static com.google.common.base.Preconditions.checkNotNull; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.MutableBlockVector3; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java index bb4d0dc3e..e006aca61 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java @@ -22,8 +22,14 @@ package com.sk89q.worldedit.math; import static com.google.common.base.Preconditions.checkArgument; import com.google.common.collect.ComparisonChain; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.transform.AffineTransform; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import javax.annotation.Nullable; import java.util.Comparator; /** @@ -93,6 +99,42 @@ public abstract class BlockVector3 { return new MutableBlockVector3(getX(), getY(), z); } + public BlockVector3 toImmutable() { + return BlockVector3.at(getX(), getY(), getZ()); + } + + /** + * Get the BlockVector3 to the north
+ * Normal use you would use north(this), + * To avoid constructing a new Vector, pass e.g. north(some MutableBlockVector3) + * There is no gaurantee it will use this provided vector + * @param orDefault the vector to use as the result
+ * @return BlockVector3 + */ + public BlockVector3 north(BlockVector3 orDefault) { + return orDefault.setComponents(getX(), getY(), getZ() - 1); + } + + public BlockVector3 east(BlockVector3 orDefault) { + return orDefault.setComponents(getX() + 1, getY(), getZ()); + } + + public BlockVector3 south(BlockVector3 orDefault) { + return orDefault.setComponents(getX(), getY(), getZ() + 1); + } + + public BlockVector3 west(BlockVector3 orDefault) { + return orDefault.setComponents(getX() - 1, getY(), getZ()); + } + + public BlockVector3 up(BlockVector3 orDefault) { + return orDefault.setComponents(getX(), getY() + 1, getZ()); + } + + public BlockVector3 down(BlockVector3 orDefault) { + return orDefault.setComponents(getX(), getY() - 1, getZ()); + } + /** * Get the X coordinate. * @@ -576,6 +618,69 @@ public abstract class BlockVector3 { ); } + /* + Methods for getting/setting blocks + + Why are these methods here? + - Getting a block at a position requires various operations + (bounds checks, cache checks, ensuring loaded chunk, get ChunkSection, etc.) + - When iterating over a region, it will provide custom BlockVector3 positions + - These override the below set/get and avoid lookups (as the iterator shifts it to the chunk level) + */ + + public boolean setOrdinal(Extent orDefault, int ordinal) { + return orDefault.setBlock(this, BlockState.getFromOrdinal(ordinal)); + } + + public boolean setBlock(Extent orDefault, BlockState state) { + return orDefault.setBlock(this, state); + } + + public boolean setFullBlock(Extent orDefault, BaseBlock block) { + return orDefault.setBlock(this, block); + } + + public boolean setBiome(Extent orDefault, BiomeType biome) { + return orDefault.setBiome(getX(), getY(), getZ(), biome); + } + + public int getOrdinal(Extent orDefault) { + return getBlock(orDefault).getOrdinal(); + } + + public char getOrdinalChar(Extent orDefault) { + return (char) getOrdinal(orDefault); + } + + public BlockState getBlock(Extent orDefault) { + return orDefault.getBlock(this); + } + + public BaseBlock getFullBlock(Extent orDefault) { + return orDefault.getFullBlock(this); + } + + public CompoundTag getNbtData(Extent orDefault) { + return orDefault.getFullBlock(getX(), getY(), getZ()).getNbtData(); + } + + public BlockState getOrdinalBelow(Extent orDefault) { + return orDefault.getBlock(getX(), getY() - 1, getZ()); + } + + public BlockState getStateAbove(Extent orDefault) { + return orDefault.getBlock(getX(), getY() + 1, getZ()); + } + + public BlockState getStateRelativeY(Extent orDefault, final int y) { + return orDefault.getBlock(getX(), getY() + y, getZ()); + } + + + /* + Adapt + */ + /** * Creates a 2D vector by dropping the Y component from this vector. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3Imp.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3Imp.java index 69a148401..dd7399c64 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3Imp.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3Imp.java @@ -29,7 +29,7 @@ import java.util.Comparator; /** * An immutable 3-dimensional vector. */ -public class BlockVector3Imp extends BlockVector3 { +public final class BlockVector3Imp extends BlockVector3 { public static final BlockVector3Imp ZERO = new BlockVector3Imp(0, 0, 0); public static final BlockVector3Imp UNIT_X = new BlockVector3Imp(1, 0, 0); @@ -80,6 +80,11 @@ public class BlockVector3Imp extends BlockVector3 { return (getX() ^ (getZ() << 12)) ^ (getY() << 24); } + @Override + public final BlockVector3 toImmutable() { + return this; + } + @Override public String toString() { return "(" + getX() + ", " + getY() + ", " + getZ() + ")"; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableBlockVector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableBlockVector3.java index f065b905b..48296a3a6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableBlockVector3.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableBlockVector3.java @@ -1,13 +1,8 @@ package com.sk89q.worldedit.math; -public class MutableBlockVector3 extends BlockVector3 { +import com.boydti.fawe.FaweCache; - private static ThreadLocal MUTABLE_CACHE = new ThreadLocal() { - @Override - protected MutableBlockVector3 initialValue() { - return new MutableBlockVector3(); - } - }; +public class MutableBlockVector3 extends BlockVector3 { public static MutableBlockVector3 at(double x, double y, double z) { return at((int) Math.floor(x), (int) Math.floor(y), (int) Math.floor(z)); @@ -18,7 +13,7 @@ public class MutableBlockVector3 extends BlockVector3 { } public static MutableBlockVector3 get(int x, int y, int z) { - return MUTABLE_CACHE.get().setComponents(x, y, z); + return FaweCache.MUTABLE_BLOCKVECTOR3.get().setComponents(x, y, z); } public MutableBlockVector3() {} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableVector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableVector3.java index e1810a4b6..21ad77d21 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableVector3.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableVector3.java @@ -1,9 +1,20 @@ package com.sk89q.worldedit.math; +import com.boydti.fawe.Fawe; +import com.boydti.fawe.FaweCache; + import javax.annotation.Nullable; public class MutableVector3 extends Vector3 { + public static MutableVector3 get(int x, int y, int z) { + return FaweCache.MUTABLE_VECTOR3.get().setComponents(x, y, z); + } + + public static MutableVector3 get(double x, double y, double z) { + return FaweCache.MUTABLE_VECTOR3.get().setComponents(x, y, z); + } + public MutableVector3() {} public MutableVector3(double x, double y, double z) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java index cbfb6be0e..9c8384863 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.world; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.blocks.BaseItem; @@ -64,7 +65,7 @@ public abstract class AbstractWorld implements World { @Override public Mask createLiquidMask() { - return new BlockTypeMask(this, BlockTypes.LAVA, BlockTypes.WATER); + return new BlockMask(this).add(BlockTypes.LAVA, BlockTypes.WATER); } @Override 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 fa27b3d17..fa722749c 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 @@ -83,12 +83,12 @@ public class NullWorld extends AbstractWorld { } @Override - public BiomeType getBiome(BlockVector2 position) { + public BiomeType getBiome(int x, int z) { return BiomeTypes.THE_VOID; } @Override - public boolean setBiome(BlockVector2 position, BiomeType biome) { + public boolean setBiome(int x, int y, int z, BiomeType biome) { return false; } @@ -134,13 +134,18 @@ public class NullWorld extends AbstractWorld { } @Override - public BlockState getBlock(BlockVector3 position) { - return BlockTypes.AIR.getDefaultState(); + public BlockState getBlock(int x, int y, int z) { + return EditSession.nullBlock; } @Override - public BlockState getLazyBlock(BlockVector3 position) { - return getBlock(position); + public BaseBlock getFullBlock(int x, int y, int z) { + return EditSession.nullBlock.toBaseBlock(); + } + + @Override + public > boolean setBlock(int x, int y, int z, T block) throws WorldEditException { + return false; } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/SimpleWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/SimpleWorld.java index d9028c95f..32243a945 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/SimpleWorld.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/SimpleWorld.java @@ -60,7 +60,7 @@ public interface SimpleWorld extends World { @Override default BaseBlock getFullBlock(BlockVector3 position) { - return getLazyBlock(position).toBaseBlock(); + return getBlock(position).toBaseBlock(); } @Override @@ -73,7 +73,7 @@ public interface SimpleWorld extends World { @Override default Mask createLiquidMask() { - return new BlockTypeMask(this, BlockTypes.LAVA, BlockTypes.WATER); + return new BlockMask(this).add(BlockTypes.LAVA, BlockTypes.WATER); } @Override 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 cad0be0f5..c7dfcaa91 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 @@ -94,7 +94,9 @@ public interface World extends Extent { * @param notifyAndLight true to to notify and light * @return true if the block was successfully set (return value may not be accurate) */ - > boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException; + default > boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException { + return setBlock(position, block); + } /** * Notifies the simulation that the block at the given location has diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java index 18ca8fbdf..3c05fc719 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java @@ -135,20 +135,6 @@ public class BaseBlock implements BlockStateHolder { this(other.toImmutableState(), other.getNbtData()); } - @Override - public String getNbtId() { - CompoundTag nbtData = getNbtData(); - if (nbtData == null) { - return ""; - } - Tag idTag = nbtData.getValue().get("id"); - if (idTag instanceof StringTag) { - return ((StringTag) idTag).getValue(); - } else { - return ""; - } - } - @Nullable @Override public CompoundTag getNbtData() { @@ -247,14 +233,10 @@ public class BaseBlock implements BlockStateHolder { @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - return extent.setBlock(set, this); + set.setFullBlock(extent, this); + return true; } - @Override - public void apply(FilterBlock block) { - block.setFullBlock(this); - } - @Override public boolean hasNbtData() { return this.nbtData != null; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index 041faa865..6cf2e4bda 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -50,7 +50,7 @@ import java.util.stream.Stream; * An immutable class that represents the state a block can be in. */ @SuppressWarnings("unchecked") -public class BlockState implements BlockStateHolder, FawePattern { +public final class BlockState implements BlockStateHolder, FawePattern { private final int internalId; private final int ordinal; private final char ordinalChar; @@ -216,12 +216,7 @@ public class BlockState implements BlockStateHolder, FawePattern { @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - return extent.setBlock(set, this); - } - - @Override - public final void apply(FilterBlock block) { - block.setOrdinal(ordinal); + return set.setBlock(extent, this); } @Override @@ -267,6 +262,24 @@ public class BlockState implements BlockStateHolder, FawePattern { } } + public BlockState withProperties(final BlockState other) { + BlockType ot = other.getBlockType(); + if (ot == blockType) { + return other; + } + if (ot.getProperties().isEmpty() || blockType.getProperties().isEmpty()) { + return this; + } + BlockState newState = this; + for (Property prop: ot.getProperties()) { + PropertyKey key = prop.getKey(); + if (blockType.hasProperty(key)) { + newState = newState.with(key, other.getState(key)); + } + } + return this; + } + @Override public final V getState(final Property property) { try { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java index de459a6db..3f7a1d2a8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java @@ -21,8 +21,6 @@ package com.sk89q.worldedit.world.block; import static com.google.common.base.Preconditions.checkArgument; -import com.boydti.fawe.beta.FilterBlock; -import com.boydti.fawe.util.ReflectionUtils; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.mask.Mask; @@ -33,14 +31,12 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.extension.platform.Capability; -import com.sk89q.worldedit.registry.NamespacedRegistry; import com.sk89q.worldedit.registry.state.AbstractProperty; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.registry.state.PropertyKey; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.registry.LegacyMapper; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.*; import java.util.stream.Collectors; @@ -299,7 +295,7 @@ public final class BlockType implements FawePattern { @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - return extent.setBlock(set, this.getDefaultState()); + return set.setBlock(extent, getDefaultState()); } @Override @@ -307,11 +303,6 @@ public final class BlockType implements FawePattern { return this.getDefaultState().toBaseBlock(); } - @Override - public final void apply(FilterBlock block) { - block.setOrdinal(getDefaultState().getOrdinal()); - } - public Mask toMask(Extent extent) { return new SingleBlockTypeMask(extent, this); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/ImmutableBaseBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/ImmutableBaseBlock.java index f738aa6f7..726580af7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/ImmutableBaseBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/ImmutableBaseBlock.java @@ -2,6 +2,9 @@ package com.sk89q.worldedit.world.block; import com.boydti.fawe.beta.FilterBlock; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; import javax.annotation.Nullable; @@ -22,7 +25,7 @@ public final class ImmutableBaseBlock extends BaseBlock { } @Override - public final void apply(FilterBlock block) { - block.setOrdinal(getOrdinal()); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + return set.setBlock(extent, toBlockState()); } } From de4dcc0dd5caf28b55474343fe5de870857be1e1 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Wed, 26 Jun 2019 20:22:21 +1000 Subject: [PATCH 24/54] idk, messing around with region filtering --- .../com/boydti/fawe/beta/CharFilterBlock.java | 100 +++++-------- .../boydti/fawe/beta/ChunkFilterBlock.java | 13 +- .../java/com/boydti/fawe/beta/IBlocks.java | 2 +- .../java/com/boydti/fawe/beta/IChunk.java | 2 +- .../java/com/boydti/fawe/beta/IChunkSet.java | 4 +- .../com/boydti/fawe/beta/NorthVector.java | 1 - .../boydti/fawe/beta/SimpleFilterBlock.java | 8 -- .../beta/implementation/DelegateChunkSet.java | 113 +++++++++++++++ .../implementation/blocks/CharBlocks.java | 14 +- .../implementation/blocks/CharGetBlocks.java | 6 +- .../implementation/blocks/CharSetBlocks.java | 3 +- .../blocks/RegionCharSetBlocks.java | 77 ++++++++++ .../implementation/holder/ChunkHolder.java | 40 ++---- .../worldedit/function/RegionFunction.java | 1 - .../sk89q/worldedit/regions/CuboidRegion.java | 88 ++++++------ .../worldedit/regions/CylinderRegion.java | 47 ++++-- .../worldedit/regions/EllipsoidRegion.java | 135 ++++++++++++++++-- .../com/sk89q/worldedit/regions/Region.java | 94 ++++++++---- .../worldedit/regions/RegionIntersection.java | 11 +- .../session/request/RequestSelection.java | 5 - 20 files changed, 542 insertions(+), 222 deletions(-) create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/DelegateChunkSet.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/RegionCharSetBlocks.java diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java index 15d16d5ff..a4e2bbc71 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java @@ -16,7 +16,6 @@ import javax.annotation.Nullable; import static com.sk89q.worldedit.world.block.BlockTypes.states; public class CharFilterBlock extends ChunkFilterBlock { private CharGetBlocks get; - private IChunkSet set; private char[] getArr; @@ -43,7 +42,7 @@ public class CharFilterBlock extends ChunkFilterBlock { public void flood(final IChunkGet iget, final IChunkSet iset, final int layer, Flood flood, FilterBlockMask mask) { final int maxDepth = flood.getMaxDepth(); final boolean checkDepth = maxDepth < Character.MAX_VALUE; - if (init(iget, iset, layer)) { + if (init(iget, iset, layer) != null) { while ((index = flood.poll()) != -1) { x = index & 15; z = (index >> 4) & 15; @@ -62,10 +61,11 @@ public class CharFilterBlock extends ChunkFilterBlock { } } - private final boolean init(final IChunkGet iget, final IChunkSet iset, final int layer) { + @Override + public final ChunkFilterBlock init(final IChunkGet iget, final IChunkSet iset, final int layer) { this.layer = layer; final CharGetBlocks get = (CharGetBlocks) iget; - if (!get.hasSection(layer)) return false; + if (!get.hasSection(layer)) return null; this.set = iset; getArr = get.sections[layer].get(get, layer); if (set.hasSection(layer)) { @@ -76,29 +76,44 @@ public class CharFilterBlock extends ChunkFilterBlock { setArr = null; } this.yy = layer << 4; - return true; + return this; } @Override - public final void filter(final IChunkGet iget, final IChunkSet iset, final int layer, final Filter filter, final @Nullable Region region, BlockVector3 min, BlockVector3 max) { - if (init(iget, iset, layer)) { - if (region == null) { - if (min != null && max != null) { - iterate(min, max, layer, filter); - } else { - iterate(filter); - } - } else { - if (min != null && max != null) { - iterate(region, min, max, layer, filter); - } else { - iterate(region, filter); + public void filter(Filter filter, int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + this.index = x | (z << 4) | (y << 8); + filter.applyBlock(this); + } + + @Override + public void filter(Filter filter, int yStart, int yEnd) { + for (y = yStart, index = (yStart << 8); y < yEnd; y++) { + for (z = 0; z < 16; z++) { + for (x = 0; x < 16; x++, index++) { + filter.applyBlock(this); } } } } - private void iterate(final Region region, final Filter filter) { + @Override + public void filter(Filter filter, int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { + int yis = (minY << 8); + int zis = (minZ << 4); + for (y = minY, index = yis; y <= maxY; y++) { + for (z = minZ, index += zis; z <= maxZ; z++) { + for (x = minX, index += minX; x <= maxX; x++, index++) { + filter.applyBlock(this); + } + } + } + } + + @Override + public final void filter(final Filter filter, final Region region) { for (y = 0, index = 0; y < 16; y++) { int absY = yy + y; for (z = 0; z < 16; z++) { @@ -113,51 +128,8 @@ public class CharFilterBlock extends ChunkFilterBlock { } } - private void iterate(final Region region, BlockVector3 min, BlockVector3 max, int layer, final Filter filter) { - int by = Math.max(min.getY(), layer << 4) & 15; - int ty = Math.min(max.getY(), 15 + (layer << 4)) & 15; - int bx = min.getX(); - int bz = min.getZ(); - int tx = max.getX(); - int tz = max.getZ(); - for (y = by; y <= ty; y++) { - int yIndex = (y << 8); - int absY = yy + y; - for (z = bz; z <= tz; z++) { - int zIndex = yIndex + ((z) << 4); - int absZ = zz + z; - for (x = bx; x <= tx; x++) { - index = zIndex + x; - int absX = xx + x; - if (region.contains(absX, absY, absZ)) { - filter.applyBlock(this); - } - - } - } - } - } - - private void iterate(BlockVector3 min, BlockVector3 max, int layer, final Filter filter) { - int by = Math.max(min.getY(), layer << 4) & 15; - int ty = Math.min(max.getY(), 15 + (layer << 4)) & 15; - int bx = min.getX(); - int bz = min.getZ(); - int tx = max.getX(); - int tz = max.getZ(); - for (y = by; y <= ty; y++) { - int yIndex = (y << 8); - for (z = bz; z <= tz; z++) { - int zIndex = yIndex + ((z) << 4); - for (x = bx; x <= tx; x++) { - index = zIndex + x; - filter.applyBlock(this); - } - } - } - } - - private final void iterate(final Filter filter) { + @Override + public final void filter(final Filter filter) { for (y = 0, index = 0; y < 16; y++) { for (z = 0; z < 16; z++) { for (x = 0; x < 16; x++, index++) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFilterBlock.java index 8dd9f95f8..bc1957f51 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFilterBlock.java @@ -13,7 +13,18 @@ public abstract class ChunkFilterBlock extends SimpleFilterBlock { public abstract ChunkFilterBlock init(int X, int Z, IChunkGet chunk); + public abstract ChunkFilterBlock init(final IChunkGet iget, final IChunkSet iset, final int layer); + public abstract void flood(final IChunkGet iget, final IChunkSet iset, final int layer, Flood flood, FilterBlockMask mask); - public abstract void filter(IChunkGet get, IChunkSet set, int layer, Filter filter, @Nullable Region region, BlockVector3 min, BlockVector3 max); + + public abstract void filter(Filter filter, int x, int y, int z); + + public abstract void filter(Filter filter, int minX, int minY, int minZ, int maxX, int maxY, int maxZ); + + public abstract void filter(Filter filter); + + public abstract void filter(Filter filter, int yStart, int yEnd); + + public abstract void filter(final Filter filter, final Region region); } 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 0a63725e1..fce4a574d 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 @@ -6,5 +6,5 @@ package com.boydti.fawe.beta; public interface IBlocks extends Trimable { boolean hasSection(int layer); - void reset(); + IChunkSet reset(); } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java index ed8c080b0..26be59e53 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java @@ -71,7 +71,7 @@ public interface IChunk> extends Trimable, Callable { * @param unitialized a mutable block vector (buffer) * @param unitialized2 a mutable block vector (buffer) */ - void filterBlocks(Filter filter, ChunkFilterBlock block, @Nullable Region region, MutableBlockVector3 unitialized, MutableBlockVector3 unitialized2); + void filterBlocks(Filter filter, ChunkFilterBlock block, @Nullable Region region); void flood(Flood flood, FilterBlockMask mask, ChunkFilterBlock block); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkSet.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkSet.java index bef4af0bf..35efd352a 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkSet.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkSet.java @@ -8,8 +8,6 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import javax.annotation.Nullable; -import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -43,7 +41,7 @@ public interface IChunkSet extends IBlocks, OutputExtent { Set getEntityRemoves(); @Override - void reset(); + IChunkSet reset(); @Nullable @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/NorthVector.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/NorthVector.java index c0b4c8e5e..2b3581395 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/NorthVector.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/NorthVector.java @@ -3,7 +3,6 @@ package com.boydti.fawe.beta; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/SimpleFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/SimpleFilterBlock.java index 99ec8e2e6..b8d865aec 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/SimpleFilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/SimpleFilterBlock.java @@ -1,14 +1,6 @@ package com.boydti.fawe.beta; -import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockTypes; - -import javax.annotation.Nullable; public abstract class SimpleFilterBlock extends FilterBlock { private final Extent extent; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/DelegateChunkSet.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/DelegateChunkSet.java new file mode 100644 index 000000000..6b224de56 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/DelegateChunkSet.java @@ -0,0 +1,113 @@ +package com.boydti.fawe.beta.implementation; + +import com.boydti.fawe.beta.IChunkSet; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import javax.annotation.Nullable; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +public interface DelegateChunkSet extends IChunkSet { + IChunkSet getParent(); + + @Override + default boolean setBiome(int x, int y, int z, BiomeType biome) { + return getParent().setBiome(x, y, z, biome); + } + + @Override + default boolean setBlock(int x, int y, int z, BlockStateHolder holder) { + return getParent().setBlock(x, y, z, holder); + } + + @Override + default boolean isEmpty() { + return getParent().isEmpty(); + } + + @Override + default void setTile(int x, int y, int z, CompoundTag tile) { + getParent().setTile(x, y, z, tile); + } + + @Override + default void setEntity(CompoundTag tag) { + getParent().setEntity(tag); + } + + @Override + default void removeEntity(UUID uuid) { + getParent().removeEntity(uuid); + } + + @Override + default BlockState getBlock(int x, int y, int z) { + return getParent().getBlock(x, y, z); + } + + @Override + default char[] getArray(int layer) { + return getParent().getArray(layer); + } + + @Override + default BiomeType[] getBiomes() { + return getParent().getBiomes(); + } + + @Override + default Map getTiles() { + return getParent().getTiles(); + } + + @Override + default Set getEntities() { + return getParent().getEntities(); + } + + @Override + default Set getEntityRemoves() { + return getParent().getEntityRemoves(); + } + + @Override + default IChunkSet reset() { + IChunkSet parent = getParent(); + parent.reset(); + return parent; + } + + @Override + @Nullable + default Operation commit() { + return getParent().commit(); + } + + @Override + default boolean hasSection(int layer) { + return getParent().hasSection(layer); + } + + @Override + default boolean trim(boolean aggressive) { + return getParent().trim(aggressive); + } + + @Override + default > boolean setBlock(BlockVector3 position, T block) throws WorldEditException { + return getParent().setBlock(position, block); + } + + @Override + default boolean setBiome(BlockVector2 position, BiomeType biome) { + return getParent().setBiome(position, biome); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java index 66cb7b74a..0b94d17b3 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java @@ -1,6 +1,7 @@ package com.boydti.fawe.beta.implementation.blocks; import com.boydti.fawe.beta.IBlocks; +import com.boydti.fawe.beta.IChunkSet; public class CharBlocks implements IBlocks { public final char[][] blocks; @@ -9,14 +10,14 @@ public class CharBlocks implements IBlocks { public CharBlocks() { blocks = new char[16][]; sections = new Section[16]; - for (int i = 0; i < 16; i++) sections[i] = NULL; + for (int i = 0; i < 16; i++) sections[i] = EMPTY; } @Override public boolean trim(final boolean aggressive) { boolean result = true; for (int i = 0; i < 16; i++) { - if (sections[i] == NULL) { + if (sections[i] == EMPTY) { blocks[i] = null; } else { result = false; @@ -26,12 +27,13 @@ public class CharBlocks implements IBlocks { } @Override - public void reset() { - for (int i = 0; i < 16; i++) sections[i] = NULL; + public IChunkSet reset() { + for (int i = 0; i < 16; i++) sections[i] = EMPTY; + return null; } public void reset(final int layer) { - sections[layer] = NULL; + sections[layer] = EMPTY; } public char[] load(final int layer) { @@ -84,7 +86,7 @@ public class CharBlocks implements IBlocks { } } - public static final Section NULL = new Section() { + public static final Section EMPTY = new Section() { @Override public final char[] get(final CharBlocks blocks, final int layer) { blocks.sections[layer] = FULL; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java index 467d78ee8..7c5dcf613 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java @@ -1,6 +1,7 @@ package com.boydti.fawe.beta.implementation.blocks; import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IChunkSet; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; @@ -19,14 +20,15 @@ public abstract class CharGetBlocks extends CharBlocks implements IChunkGet { @Override public boolean trim(final boolean aggressive) { for (int i = 0; i < 16; i++) { - sections[i] = NULL; + sections[i] = EMPTY; blocks[i] = null; } return true; } @Override - public void reset() { + public IChunkSet reset() { super.reset(); + return null; } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java index 883fe34a9..82d13aa0e 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java @@ -102,11 +102,12 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet { } @Override - public void reset() { + public IChunkSet reset() { biomes = null; tiles = null; entities = null; entityRemoves = null; super.reset(); + return null; } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/RegionCharSetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/RegionCharSetBlocks.java new file mode 100644 index 000000000..caba79543 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/RegionCharSetBlocks.java @@ -0,0 +1,77 @@ +package com.boydti.fawe.beta.implementation.blocks; + +import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.IChunkSet; +import com.boydti.fawe.beta.implementation.DelegateChunkSet; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +public class RegionCharSetBlocks implements DelegateChunkSet { + private final Region region; + private final CharSetBlocks parent; + private final int X, Z; + + public RegionCharSetBlocks(Region region, int X, int Z, CharSetBlocks parent) { + this.region = region; + this.parent = parent; + this.X = X; + this.Z = Z; + } + + @Override + public CharSetBlocks getParent() { + return parent; + } + + public Region getRegion() { + return region; + } + + @Override + public boolean setBiome(int x, int y, int z, BiomeType biome) { + if (region.contains(x, y, z)) { + return parent.setBiome(x, y, z, biome); + } + return false; + } + + public static final CharBlocks.Section EMPTY_REGION = new CharBlocks.Section() { + @Override + public final char[] get(final CharBlocks blocks, final int layer) { + RegionCharSetBlocks checked = (RegionCharSetBlocks) blocks; + Region region = checked.getRegion(); + + blocks.sections[layer] = FULL; + char[] arr = blocks.blocks[layer]; + if (arr == null) { + arr = blocks.blocks[layer] = blocks.load(layer); + } else { + blocks.blocks[layer] = blocks.load(layer, arr); + } + return arr; + } + }; + + public static final CharBlocks.Section NULL = new CharBlocks.Section() { + @Override + public final char[] get(final CharBlocks blocks, final int layer) { + return FaweCache.EMPTY_CHAR_4096; + } + }; + + // EMPTY_CHAR_4096 + + @Override + public boolean setBlock(final int x, final int y, final int z, final BlockStateHolder holder) { + + } + + @Override + public void setTile(final int x, final int y, final int z, final CompoundTag tile) { + if (region.contains(x, y, z)) { + super.setTile(x, y, z, tile); + } + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java index b1336a480..3f8f43471 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java @@ -2,16 +2,15 @@ package com.boydti.fawe.beta.implementation.holder; import com.boydti.fawe.beta.ChunkFilterBlock; import com.boydti.fawe.beta.Filter; -import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.beta.FilterBlockMask; import com.boydti.fawe.beta.Flood; -import com.boydti.fawe.beta.IQueueExtent; -import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks; import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.IChunkGet; import com.boydti.fawe.beta.IChunkSet; +import com.boydti.fawe.beta.IQueueExtent; import com.boydti.fawe.beta.implementation.SingleThreadQueueExtent; import com.boydti.fawe.beta.implementation.WorldChunkCache; +import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks; import com.boydti.fawe.util.MathMan; import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.regions.Region; @@ -47,39 +46,20 @@ public abstract class ChunkHolder implements IChunk, Supplier { } @Override - public void filterBlocks(final Filter filter, ChunkFilterBlock block, @Nullable Region region, @Nullable final MutableBlockVector3 min, @Nullable final MutableBlockVector3 max) { + public void filterBlocks(final Filter filter, ChunkFilterBlock block, @Nullable Region region) { final IChunkGet get = getOrCreateGet(); final IChunkSet set = getOrCreateSet(); try { if (region != null) { - switch (region.getChunkBounds(X, Z, min, max)) { - case NONE: - return; - case FULL: - if (min.getY() == 0 && max.getY() == 255) { - break; - } - case PARTIAL: - region = null; - case CHECKED: - default: { - int minLayer = min.getY() >> 4; - int maxLayer = max.getY() >> 4; - block = block.init(X, Z, get); - for (int layer = minLayer; layer <= maxLayer; layer++) { - if (!get.hasSection(layer) || !filter.appliesLayer(this, layer)) continue; - block.filter(get, set, layer, filter, region, min, max); - } - return; - } + region.filter(this, filter, block, get, set); + } else { + block = block.init(X, Z, get); + for (int layer = 0; layer < 16; layer++) { + if (!get.hasSection(layer) || !filter.appliesLayer(this, layer)) continue; + block.init(get, set, layer); + block.filter(filter); } } - - block = block.init(X, Z, get); - for (int layer = 0; layer < 16; layer++) { - if (!get.hasSection(layer) || !filter.appliesLayer(this, layer)) continue; - block.filter(get, set, layer, filter, region, null, null); - } } finally { filter.finishChunk(this); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/RegionFunction.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/RegionFunction.java index 332565e35..25f5f22d7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/RegionFunction.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/RegionFunction.java @@ -35,5 +35,4 @@ public interface RegionFunction { * @throws WorldEditException thrown on an error */ boolean apply(BlockVector3 position) throws WorldEditException; - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java index 913285e52..5b58b217e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java @@ -19,29 +19,27 @@ package com.sk89q.worldedit.regions; +import com.boydti.fawe.beta.ChunkFilterBlock; +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IChunkSet; import com.boydti.fawe.config.Settings; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - import com.boydti.fawe.object.collection.BlockVectorSet; -import com.boydti.fawe.object.collection.LocalBlockVectorSet; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.math.MutableBlockVector2; +import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.storage.ChunkStore; import java.util.AbstractSet; -import java.util.HashSet; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Set; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.worldedit.regions.Region.Contains.*; /** * An axis-aligned cuboid. It can be defined using two corners of the cuboid. @@ -400,13 +398,7 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { public boolean contains(int x, int z) { return x >= this.minX && x <= this.maxX && z >= this.minZ && z <= this.maxZ; } - @Override - public boolean contains(BlockVector3 position) { - BlockVector3 min = getMinimumPoint(); - BlockVector3 max = getMaximumPoint(); - return position.containedWithin(min, max); - } @Override public Iterator iterator() { if (Settings.IMP.HISTORY.COMPRESSION_LEVEL >= 9 || useOldIterator) { @@ -629,35 +621,49 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { } @Override - public Contains getChunkBounds(int X, int Z, MutableBlockVector3 min, MutableBlockVector3 max) { - int minChunkX = minX >> 4; - if (minChunkX <= X) { - int maxChunkX = maxX >> 4; - if (maxChunkX >= X) { - int minChunkZ = minZ >> 4; - if (minChunkZ <= Z) { - int maxChunkZ = maxZ >> 4; - if (maxChunkZ >= Z) { - int cx1 = X << 4; - int cx2 = cx1 + 15; - int cz1 = Z << 4; - int cz2 = cz1 + 15; + public int getMinY() { + return minY; + } - int bx = Math.max(cx1, minX); - int bz = Math.max(cz1, minZ); - int tx = Math.min(cx2, maxX); - int tz = Math.min(cz2, maxZ); + @Override + public int getMaxY() { + return maxY; + } - min.setComponents(bx & 15, minY, bz & 15); - max.setComponents(tx & 15, maxY, tz & 15); - if (min.getX() == 0 && min.getZ() == 0 && max.getX() == 15 && max.getZ() == 15) { - return FULL; - } - return PARTIAL; - } - } - } + @Override + public void filter(final IChunk chunk, final Filter filter, ChunkFilterBlock block, final IChunkGet get, final IChunkSet set) { + int X = chunk.getX(); + int Z = chunk.getZ(); + block = block.init(X, Z, get); + + if ((minX + 15) >> 4 <= X && (maxX - 15) >> 4 >= X && (minZ + 15) >> 4 <= Z && (maxZ - 15) >> 4 >= Z) { + filter(chunk, filter, block, get, set, minY, maxY); + return; + } + int localMinX = Math.max(minX, X << 4) & 15; + int localMaxX = Math.min(maxX, 15 + X << 4) & 15; + int localMinZ = Math.max(minZ, Z << 4) & 15; + int localMaxZ = Math.min(maxZ, 15 + Z << 4) & 15; + + int yStart = (minY & 15); + int yEnd = (maxY & 15); + + int minSection = minY >> 4; + int maxSection = maxY >> 4; + if (minSection == maxSection) { + filter(chunk, filter, block, get, set, minSection, localMinX, yStart, localMinZ, localMaxX, yEnd, localMaxZ); + return; + } + if (yStart != 0) { + filter(chunk, filter, block, get, set, minSection, localMinX, yStart, localMinZ, localMaxX, 15, localMaxZ); + minSection++; + } + if (yEnd != 15) { + filter(chunk, filter, block, get, set, minSection, localMinX, 0, localMinZ, localMaxX, 15, localMaxZ); + maxSection--; + } + for (int layer = minSection; layer < maxSection; layer++) { + filter(chunk, filter, block, get, set, layer, localMinX, yStart, localMinZ, localMaxX, yEnd, localMaxZ); } - return NONE; } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java index 90892ed12..a2741b061 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java @@ -21,6 +21,11 @@ package com.sk89q.worldedit.regions; import static com.google.common.base.Preconditions.checkNotNull; +import com.boydti.fawe.beta.ChunkFilterBlock; +import com.boydti.fawe.beta.Filter; +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.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector2; @@ -290,25 +295,22 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { minY += changeY; } - /** - * Checks to see if a point is inside this region. - */ @Override - public boolean contains(BlockVector3 position) { - final int blockY = position.getBlockY(); - if (blockY < minY || blockY > maxY) { + public boolean contains(int x, int y, int z) { + if (y < minY || y > maxY) { return false; } - int px = position.getBlockX(); - int pz = position.getBlockZ(); + return contains(x, z); + } - double dx = Math.abs(px - center.getBlockX()) * radiusInverse.getX(); - double dz = Math.abs(pz - center.getBlockZ()) * radiusInverse.getZ(); + @Override + public boolean contains(int x, int z) { + double dx = Math.abs(x - center.getBlockX()) * radiusInverse.getX(); + double dz = Math.abs(z - center.getBlockZ()) * radiusInverse.getZ(); return dx * dx + dz * dz <= 1; } - /** * Sets the height of the cylinder to fit the specified Y. * @@ -363,6 +365,16 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { return Polygons.polygonizeCylinder(center, radius, maxPoints); } + @Override + public int getMinY() { + return minY; + } + + @Override + public int getMaxY() { + return maxY; + } + /** * Return a new instance with the given center and radius in the X and Z * axes with a Y that extends from the bottom of the extent to the top @@ -381,4 +393,17 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { int maxY = extent.getMaximumPoint().getBlockY(); return new CylinderRegion(center, radiusVec, minY, maxY); } + + @Override + public void filter(final IChunk chunk, final Filter filter, final ChunkFilterBlock block, final IChunkGet get, final IChunkSet set) { + int bcx = chunk.getX() >> 4; + int bcz = chunk.getZ() >> 4; + int tcx = bcx + 15; + int tcz = bcz + 15; + if (contains(bcx, bcz) && contains(tcx, tcz)) { + filter(chunk, filter, block, get, set, minY, maxY); + return; + } + super.filter(chunk, filter, block, get, set); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java index 0c0be6781..bf5c4d8e3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java @@ -20,6 +20,11 @@ package com.sk89q.worldedit.regions; +import com.boydti.fawe.beta.ChunkFilterBlock; +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IChunkSet; import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; @@ -215,19 +220,19 @@ public class EllipsoidRegion extends AbstractRegion { return chunks; } - @Override - public boolean contains(BlockVector3 position) { - int cx = position.getBlockX() - center.getBlockX(); + @Override + public boolean contains(int x, int y, int z) { + int cx = x - center.getBlockX(); int cx2 = cx * cx; if (cx2 > radiusSqr.getBlockX()) { return false; } - int cz = position.getBlockZ() - center.getBlockZ(); + int cz = z - center.getBlockZ(); int cz2 = cz * cz; if (cz2 > radiusSqr.getBlockZ()) { return false; } - int cy = position.getBlockY() - center.getBlockY(); + int cy = y - center.getBlockY(); int cy2 = cy * cy; if (radiusSqr.getBlockY() < 255 && cy2 > radiusSqr.getBlockY()) { return false; @@ -235,10 +240,30 @@ public class EllipsoidRegion extends AbstractRegion { if (sphere) { return cx2 + cy2 + cz2 <= radiusLengthSqr; } - double cxd = cx * inverseRadius.getX(); - double cyd = cy * inverseRadius.getY(); - double czd = cz * inverseRadius.getZ(); - return cxd * cxd + cyd * cyd + czd * czd <= 1; + double cxd = cx2 * inverseRadius.getX(); + double cyd = cy2 * inverseRadius.getY(); + double czd = cz2 * inverseRadius.getZ(); + return cxd + cyd + czd <= 1; + } + + @Override + public boolean contains(int x, int z) { + int cx = x - center.getBlockX(); + int cx2 = cx * cx; + if (cx2 > radiusSqr.getBlockX()) { + return false; + } + int cz = z - center.getBlockZ(); + int cz2 = cz * cz; + if (cz2 > radiusSqr.getBlockZ()) { + return false; + } + if (sphere) { + return cx2 + cz2 <= radiusLengthSqr; + } + double cxd = cx2 * inverseRadius.getX(); + double czd = cz2 * inverseRadius.getZ(); + return cxd + czd <= 1; } /** @@ -260,4 +285,96 @@ public class EllipsoidRegion extends AbstractRegion { public EllipsoidRegion clone() { return (EllipsoidRegion) super.clone(); } + + @Override + public void filter(IChunk chunk, Filter filter, ChunkFilterBlock block, IChunkGet get, IChunkSet set) { + int bx = chunk.getX() << 4; + int bz = chunk.getZ() << 4; + int tx = bx + 15; + int tz = bz + 15; + int cx1 = bx - center.getBlockX(); + int cx2 = tx - center.getBlockX(); + int cxMax, cxMin; + if (cx1 < cx2) { + cxMin = cx1; + cxMax = cx2; + } else { + cxMin = cx2; + cxMax = cx1; + } + int cxMin2 = cxMin * cxMin; + int cxMax2 = cxMax * cxMax; + int cz1 = bz - center.getBlockZ(); + int cz2 = tz - center.getBlockZ(); + int czMax, czMin; + if (cz1 < cz2) { + czMin = cz1; + czMax = cz2; + } else { + czMin = cz2; + czMax = cz1; + } + int czMin2 = czMin * czMin; + int czMax2 = czMax * czMax; + + + if (sphere) { + if (cxMin2 + czMin2 >= radiusLengthSqr) { + return; + } + int diffY2 = radiusLengthSqr - cxMax2 - czMax2; + if (diffY2 > 0) { + diffy2 + } + + + + } else { + if (cxMin2 * inverseRadius.getX() + czMin2 * inverseRadius.getZ() > 1) { + return; + } + partial = cxMax2 * inverseRadius.getX() + czMax2 * inverseRadius.getZ() > 1; + } + if (partial) { + + } else { + // get min y and max y + for (int layer = 0; layer < 16; layer++) { + // if contains all + { + filter(chunk, ) + } + } + } + + + int cy1 = 0 - center.getBlockY(); + int cy2 = 255 - center.getBlockY(); + int cyMax, cyMin; + if (cy1 < cy2) { + cyMin = cy1; + cyMax = cy2; + } else { + cyMin = cy2; + cyMax = cy1; + } + int cyMin2 = cyMin * cyMin; + int cyMax2 = cyMax * cyMax; + + boolean containsMin = contains(bx, bz); + boolean containsMax = contains(tx, tz); + if (containsMin && containsMax) { + // set all + return; + } + + + for (int layer = 0; layer < 16; layer++) { + if (contains()) + } + TODO optimize; + int minY = getMinY(); + int maxY = getMaxY(); + contains() + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java index a90bea7a8..bdecfc4de 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java @@ -19,6 +19,12 @@ package com.sk89q.worldedit.regions; +import com.boydti.fawe.beta.ChunkFilterBlock; +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IChunkSet; +import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.MutableBlockVector3; @@ -26,12 +32,10 @@ import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.world.World; import javax.annotation.Nullable; +import java.util.Iterator; import java.util.List; import java.util.Set; -import static com.sk89q.worldedit.regions.Region.Contains.CHECKED; -import static com.sk89q.worldedit.regions.Region.Contains.NONE; - /** * Represents a physical shape. */ @@ -137,7 +141,9 @@ public interface Region extends Iterable, Cloneable { * @param position the position * @return true if contained */ - boolean contains(BlockVector3 position); + default boolean contains(BlockVector3 position) { + return contains(position.getX(), position.getY(), position.getZ()); + } /** * Get a list of chunks. @@ -183,32 +189,62 @@ public interface Region extends Iterable, Cloneable { */ List polygonize(int maxPoints); - default Contains getChunkBounds(int X, int Z, MutableBlockVector3 min, MutableBlockVector3 max) { - BlockVector3 pos1 = getMinimumPoint(); - BlockVector3 pos2 = getMaximumPoint(); - int cx1 = X << 4; - int cx2 = cx1 + 15; - int cz1 = Z << 4; - int cz2 = cz1 + 15; - - int bx = Math.max(cx1, pos1.getX()); - int bz = Math.max(cz1, pos1.getZ()); - int tx = Math.min(cx2, pos2.getX()); - int tz = Math.min(cz2, pos2.getZ()); - - min.setComponents(bx & 15, pos1.getY(), bz & 15); - max.setComponents(tx & 15, pos2.getY(), tz & 15); - - if (bx > cx2 || bz > cz2 || tx < cx1 || tz < cz1) { - return NONE; - } - return CHECKED; + default int getMinY() { + return getMinimumPoint().getY(); } - enum Contains { - FULL, - PARTIAL, - CHECKED, - NONE; + default int getMaxY() { + return getMaximumPoint().getY(); + } + + default void filter(final IChunk chunk, final Filter filter, ChunkFilterBlock block, final IChunkGet get, final IChunkSet set) { + int minSection = Math.max(0, getMinY() >> 4); + int maxSection = Math.min(15, getMaxY() >> 4); + for (int layer = minSection; layer <= maxSection; layer++) { + if (!get.hasSection(layer) || !filter.appliesLayer(chunk, layer)) return; + block = block.init(get, set, layer); + block.filter(filter, this); + } + } + + default void filter(final IChunk chunk, final Filter filter, ChunkFilterBlock block, final IChunkGet get, final IChunkSet set, final int minY, final int maxY) { + int minSection = minY >> 4; + int maxSection = maxY >> 4; + int yStart = (minY & 15); + int yEnd = (maxY & 15); + if (minSection == maxSection) { + filter(chunk, filter, block, get, set, minSection, yStart, yEnd); + return; + } + if (yStart != 0) { + filter(chunk, filter, block, get, set, minSection, yStart, 15); + minSection++; + } + if (yEnd != 15) { + filter(chunk, filter, block, get, set, minSection, 0, yEnd); + maxSection--; + } + for (int layer = minSection; layer < maxSection; layer++) { + filter(chunk, filter, block, get, set, layer); + } + return; + } + + default void filter(final IChunk chunk, final Filter filter, ChunkFilterBlock block, final IChunkGet get, final IChunkSet set, int layer) { + if (!get.hasSection(layer) || !filter.appliesLayer(chunk, layer)) return; + block = block.init(get, set, layer); + block.filter(filter); + } + + default void filter(final IChunk chunk, final Filter filter, ChunkFilterBlock block, final IChunkGet get, final IChunkSet set, int layer, int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { + if (!get.hasSection(layer) || !filter.appliesLayer(chunk, layer)) return; + block = block.init(get, set, layer); + block.filter(filter, minX, minY, minZ, maxX, maxY, maxZ); + } + + default void filter(final IChunk chunk, final Filter filter, ChunkFilterBlock block, final IChunkGet get, final IChunkSet set, int layer, int yStart, int yEnd) { + if (!get.hasSection(layer) || !filter.appliesLayer(chunk, layer)) return; + block = block.init(get, set, layer); + block.filter(filter, yStart, yEnd); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java index 161852248..cc1dbd954 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java @@ -19,16 +19,8 @@ package com.sk89q.worldedit.regions; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.worldedit.regions.Region.Contains.CHECKED; -import static com.sk89q.worldedit.regions.Region.Contains.FULL; -import static com.sk89q.worldedit.regions.Region.Contains.NONE; -import static com.sk89q.worldedit.regions.Region.Contains.PARTIAL; - import com.google.common.collect.Iterators; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.world.World; import java.util.ArrayList; @@ -36,6 +28,9 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + /** * An intersection of several other regions. Any location that is contained in one * of the child regions is considered as contained by this region. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestSelection.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestSelection.java index 3766676fd..7645154f8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestSelection.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestSelection.java @@ -148,11 +148,6 @@ public class RequestSelection implements Region { return getRegion().polygonize(maxPoints); } - @Override - public Contains getChunkBounds(int X, int Z, MutableBlockVector3 min, MutableBlockVector3 max) { - return getRegion().getChunkBounds(X, Z, min, max); - } - @Override public Iterator iterator() { return getRegion().iterator(); From 2b0a310e0ed4626e63d4d197a96f05690acf2c65 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Sat, 29 Jun 2019 00:16:12 +1000 Subject: [PATCH 25/54] filter sphere --- .../com/boydti/fawe/beta/CharFilterBlock.java | 27 +--- .../boydti/fawe/beta/DelegateFilterBlock.java | 38 +++--- .../com/boydti/fawe/beta/FilterBlock.java | 1 - .../com/boydti/fawe/beta/IDelegateChunk.java | 4 +- .../com/boydti/fawe/beta/NorthVector.java | 8 +- .../boydti/fawe/beta/SingleFilterBlock.java | 8 +- .../beta/implementation/QueueHandler.java | 5 +- .../SingleThreadQueueExtent.java | 2 +- .../implementation/blocks/CharBlocks.java | 5 + .../implementation/blocks/CharSetBlocks.java | 11 ++ .../blocks/RegionCharSetBlocks.java | 77 ------------ .../sk89q/worldedit/math/BlockVector3.java | 62 +++++----- .../worldedit/regions/EllipsoidRegion.java | 116 ++++++++++-------- 13 files changed, 148 insertions(+), 216 deletions(-) delete mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/RegionCharSetBlocks.java diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java index a4e2bbc71..459a27b1d 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java @@ -3,7 +3,6 @@ package com.boydti.fawe.beta; import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; @@ -367,31 +366,9 @@ public class CharFilterBlock extends ChunkFilterBlock { return BlockTypes.__RESERVED__.getDefaultState(); } - - - @Override - public BlockVector3 north() { - return this.north; - } - - @Override - public BlockVector3 east() { - return super.east(); - } - - @Override - public BlockVector3 south() { - return super.south(); - } - - @Override - public BlockVector3 west() { - return super.west(); - } - /* - Extent - */ + Extent + */ @Override public char getOrdinalChar(Extent orDefault) { return getOrdinalChar(); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilterBlock.java index 88e1f9340..7589300fb 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilterBlock.java @@ -298,25 +298,25 @@ public class DelegateFilterBlock extends FilterBlock { return parent.toImmutable(); } - @Override - public BlockVector3 north() { - return parent.north(); - } - - @Override - public BlockVector3 east() { - return parent.east(); - } - - @Override - public BlockVector3 south() { - return parent.south(); - } - - @Override - public BlockVector3 west() { - return parent.west(); - } +// @Override +// public BlockVector3 north() { +// return parent.north(); +// } +// +// @Override +// public BlockVector3 east() { +// return parent.east(); +// } +// +// @Override +// public BlockVector3 south() { +// return parent.south(); +// } +// +// @Override +// public BlockVector3 west() { +// return parent.west(); +// } @Override public int getBlockX() { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java index 34fc86323..ed2a84be4 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java @@ -119,7 +119,6 @@ public abstract class FilterBlock extends BlockVector3 implements Extent, TileEn /* Extent */ - public boolean setOrdinal(Extent orDefault, int ordinal) { setOrdinal(ordinal); return true; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java index 3862c23c5..e36529fc8 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java @@ -88,8 +88,8 @@ public interface IDelegateChunk extends IChunk { } @Override - default void filterBlocks(Filter filter, ChunkFilterBlock block, @Nullable Region region, MutableBlockVector3 unitialized, MutableBlockVector3 unitialized2) { - getParent().filterBlocks(filter, block, region, unitialized, unitialized2); + default void filterBlocks(Filter filter, ChunkFilterBlock block, @Nullable Region region) { + getParent().filterBlocks(filter, block, region); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/NorthVector.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/NorthVector.java index 2b3581395..94279a6aa 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/NorthVector.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/NorthVector.java @@ -14,10 +14,10 @@ public class NorthVector extends BlockVector3 { this.parent = parent; } - @Override - public BlockVector3 south(BlockVector3 orDefault) { - return parent; - } +// @Override +// public BlockVector3 south(BlockVector3 orDefault) { +// return parent; +// } @Override public int getX() { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/SingleFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/SingleFilterBlock.java index 8a7add4b6..39a2c04a0 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/SingleFilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/SingleFilterBlock.java @@ -51,10 +51,10 @@ public class SingleFilterBlock extends FilterBlock { return block.getOrdinal(); } - @Override - public BaseBlock getFullBlockRelative(int x, int y, int z) { - return block; - } +// @Override +// public BaseBlock getFullBlockRelative(int x, int y, int z) { +// return block; +// } @Override public BlockState getBlock() { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java index e7a90b531..665f4043f 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java @@ -156,9 +156,6 @@ public abstract class QueueHandler implements Trimable, Runnable { tasks[i] = forkJoinPoolPrimary.submit(new Runnable() { @Override public void run() { - MutableBlockVector3 mbv1 = new MutableBlockVector3(); - MutableBlockVector3 mbv2 = new MutableBlockVector3(); - final Filter newFilter = filter.fork(); // Create a chunk that we will reuse/reset for each operation final IQueueExtent queue = getQueue(world); @@ -185,7 +182,7 @@ public abstract class QueueHandler implements Trimable, Runnable { if (newChunk != null) { chunk = newChunk; if (block == null) block = queue.initFilterBlock(); - chunk.filterBlocks(newFilter, block, region, mbv1, mbv2); + chunk.filterBlocks(newFilter, block, region); } queue.submit(chunk); } 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 661868e8f..cc057334c 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 @@ -103,7 +103,7 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { private > T submitUnchecked(final IChunk chunk) { if (chunk.isEmpty()) { CHUNK_POOL.add(chunk); - return (T) (Future) Futures.immediateFuture(null); + return (T) Futures.immediateFuture(null); } if (Fawe.isMainThread()) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java index 0b94d17b3..1c50695f2 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java @@ -7,6 +7,11 @@ public class CharBlocks implements IBlocks { public final char[][] blocks; public final Section[] sections; + public CharBlocks(CharBlocks other) { + this.blocks = other.blocks; + this.sections = other.sections; + } + public CharBlocks() { blocks = new char[16][]; sections = new Section[16]; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java index 82d13aa0e..23db45a27 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java @@ -20,6 +20,17 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet { public HashSet entities; public HashSet entityRemoves; + public CharSetBlocks(CharBlocks other) { + super(other); + if (other instanceof CharSetBlocks) { + + } + } + + public CharSetBlocks() { + + } + @Override public char[] getArray(int layer) { return sections[layer].get(this, layer); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/RegionCharSetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/RegionCharSetBlocks.java deleted file mode 100644 index caba79543..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/RegionCharSetBlocks.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.boydti.fawe.beta.implementation.blocks; - -import com.boydti.fawe.FaweCache; -import com.boydti.fawe.beta.IChunkSet; -import com.boydti.fawe.beta.implementation.DelegateChunkSet; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BlockStateHolder; - -public class RegionCharSetBlocks implements DelegateChunkSet { - private final Region region; - private final CharSetBlocks parent; - private final int X, Z; - - public RegionCharSetBlocks(Region region, int X, int Z, CharSetBlocks parent) { - this.region = region; - this.parent = parent; - this.X = X; - this.Z = Z; - } - - @Override - public CharSetBlocks getParent() { - return parent; - } - - public Region getRegion() { - return region; - } - - @Override - public boolean setBiome(int x, int y, int z, BiomeType biome) { - if (region.contains(x, y, z)) { - return parent.setBiome(x, y, z, biome); - } - return false; - } - - public static final CharBlocks.Section EMPTY_REGION = new CharBlocks.Section() { - @Override - public final char[] get(final CharBlocks blocks, final int layer) { - RegionCharSetBlocks checked = (RegionCharSetBlocks) blocks; - Region region = checked.getRegion(); - - blocks.sections[layer] = FULL; - char[] arr = blocks.blocks[layer]; - if (arr == null) { - arr = blocks.blocks[layer] = blocks.load(layer); - } else { - blocks.blocks[layer] = blocks.load(layer, arr); - } - return arr; - } - }; - - public static final CharBlocks.Section NULL = new CharBlocks.Section() { - @Override - public final char[] get(final CharBlocks blocks, final int layer) { - return FaweCache.EMPTY_CHAR_4096; - } - }; - - // EMPTY_CHAR_4096 - - @Override - public boolean setBlock(final int x, final int y, final int z, final BlockStateHolder holder) { - - } - - @Override - public void setTile(final int x, final int y, final int z, final CompoundTag tile) { - if (region.contains(x, y, z)) { - super.setTile(x, y, z, tile); - } - } -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java index e006aca61..8259ce872 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java @@ -103,37 +103,37 @@ public abstract class BlockVector3 { return BlockVector3.at(getX(), getY(), getZ()); } - /** - * Get the BlockVector3 to the north
- * Normal use you would use north(this), - * To avoid constructing a new Vector, pass e.g. north(some MutableBlockVector3) - * There is no gaurantee it will use this provided vector - * @param orDefault the vector to use as the result
- * @return BlockVector3 - */ - public BlockVector3 north(BlockVector3 orDefault) { - return orDefault.setComponents(getX(), getY(), getZ() - 1); - } - - public BlockVector3 east(BlockVector3 orDefault) { - return orDefault.setComponents(getX() + 1, getY(), getZ()); - } - - public BlockVector3 south(BlockVector3 orDefault) { - return orDefault.setComponents(getX(), getY(), getZ() + 1); - } - - public BlockVector3 west(BlockVector3 orDefault) { - return orDefault.setComponents(getX() - 1, getY(), getZ()); - } - - public BlockVector3 up(BlockVector3 orDefault) { - return orDefault.setComponents(getX(), getY() + 1, getZ()); - } - - public BlockVector3 down(BlockVector3 orDefault) { - return orDefault.setComponents(getX(), getY() - 1, getZ()); - } +// /** +// * Get the BlockVector3 to the north
+// * Normal use you would use north(this), +// * To avoid constructing a new Vector, pass e.g. north(some MutableBlockVector3) +// * There is no gaurantee it will use this provided vector +// * @param orDefault the vector to use as the result
+// * @return BlockVector3 +// */ +// public BlockVector3 north(BlockVector3 orDefault) { +// return orDefault.setComponents(getX(), getY(), getZ() - 1); +// } +// +// public BlockVector3 east(BlockVector3 orDefault) { +// return orDefault.setComponents(getX() + 1, getY(), getZ()); +// } +// +// public BlockVector3 south(BlockVector3 orDefault) { +// return orDefault.setComponents(getX(), getY(), getZ() + 1); +// } +// +// public BlockVector3 west(BlockVector3 orDefault) { +// return orDefault.setComponents(getX() - 1, getY(), getZ()); +// } +// +// public BlockVector3 up(BlockVector3 orDefault) { +// return orDefault.setComponents(getX(), getY() + 1, getZ()); +// } +// +// public BlockVector3 down(BlockVector3 orDefault) { +// return orDefault.setComponents(getX(), getY() - 1, getZ()); +// } /** * Get the X coordinate. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java index bf5c4d8e3..e01196242 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java @@ -25,6 +25,7 @@ import com.boydti.fawe.beta.Filter; import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.IChunkGet; import com.boydti.fawe.beta.IChunkSet; +import com.boydti.fawe.util.MathMan; import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; @@ -286,14 +287,54 @@ public class EllipsoidRegion extends AbstractRegion { return (EllipsoidRegion) super.clone(); } + private void filterSpherePartial(int y1, int y2, int bx, int bz, Filter filter, ChunkFilterBlock block, IChunkGet get, IChunkSet set) { + int sectionStart = y1 >> 4; + int sectionEnd = y2 >> 4; + + } + + private void filterSpherePartial(int layer, int y1, int y2, int bx, int bz, Filter filter, ChunkFilterBlock block, IChunkGet get, IChunkSet set) { + int cx = center.getBlockX(); + int cy = center.getBlockY(); + int cz = center.getBlockZ(); + + block.init(get, set, layer); + + int by = layer << 4; + int diffY; + for (int y = y1, yy = by + y1; y <= y2; y++, yy++) { + diffY = cy - yy; + int remainderY = radiusLengthSqr - (diffY * diffY); + if (remainderY >= 0) { + for (int z = 0; z < 16; z++) { + int zz = z + bz; + int diffZ = cz - zz; + int remainderZ = remainderY - (diffZ * diffZ); + if (remainderZ >= 0) { + int diffX = MathMan.usqrt(remainderZ); + int minX = Math.max(0, cx - diffX - bx); + int maxX = Math.min(15, cx + diffX - bx); + if (minX != maxX) { + block.filter(filter, minX, y, z, maxX, y, z); + } + } + } + } + } + } + @Override public void filter(IChunk chunk, Filter filter, ChunkFilterBlock block, IChunkGet get, IChunkSet set) { + // Check bounds + // This needs to be able to perform 50M blocks/sec otherwise it becomes a bottleneck + int cx = center.getBlockX(); + int cz = center.getBlockZ(); int bx = chunk.getX() << 4; int bz = chunk.getZ() << 4; int tx = bx + 15; int tz = bz + 15; - int cx1 = bx - center.getBlockX(); - int cx2 = tx - center.getBlockX(); + int cx1 = bx - cx; + int cx2 = tx - cx; int cxMax, cxMin; if (cx1 < cx2) { cxMin = cx1; @@ -304,8 +345,8 @@ public class EllipsoidRegion extends AbstractRegion { } int cxMin2 = cxMin * cxMin; int cxMax2 = cxMax * cxMax; - int cz1 = bz - center.getBlockZ(); - int cz2 = tz - center.getBlockZ(); + int cz1 = bz - cz; + int cz2 = tz - cz; int czMax, czMin; if (cz1 < cz2) { czMin = cz1; @@ -319,62 +360,41 @@ public class EllipsoidRegion extends AbstractRegion { if (sphere) { + // Does not contain chunk if (cxMin2 + czMin2 >= radiusLengthSqr) { return; } int diffY2 = radiusLengthSqr - cxMax2 - czMax2; - if (diffY2 > 0) { - diffy2 - } + // (shortcut) Contains all of certain layers + if (diffY2 >= 0) { + // Get the solid layers + int cy = center.getBlockY(); + int diffYFull = MathMan.usqrt(diffY2); + int yBotFull = Math.max(0, cy - diffYFull); + int yTopFull = Math.min(255, cy + diffYFull); + // Set those layers + filter(chunk, filter, block, get, set, yBotFull, yTopFull); + // Fill the remaining layers + if (yBotFull != 0 || yTopFull != 255) { + int diffYPartial = MathMan.usqrt(radiusLengthSqr - cxMin * cxMin - czMin * czMin); + if (yBotFull != 0) { + int yBotPartial = Math.max(0, cy - diffYPartial); + filterSpherePartial(yBotPartial, yBotFull - 1, bx, bz, filter, block, get, set); + } - } else { - if (cxMin2 * inverseRadius.getX() + czMin2 * inverseRadius.getZ() > 1) { - return; - } - partial = cxMax2 * inverseRadius.getX() + czMax2 * inverseRadius.getZ() > 1; - } - if (partial) { - - } else { - // get min y and max y - for (int layer = 0; layer < 16; layer++) { - // if contains all - { - filter(chunk, ) + if (yTopFull != 255) { + int yTopPartial = Math.min(255, cy + diffYPartial); + filterSpherePartial(yTopFull + 1, yTopPartial - 1, bx, bz, filter, block, get, set); + } } } - } - int cy1 = 0 - center.getBlockY(); - int cy2 = 255 - center.getBlockY(); - int cyMax, cyMin; - if (cy1 < cy2) { - cyMin = cy1; - cyMax = cy2; } else { - cyMin = cy2; - cyMax = cy1; + super.filter(chunk, filter, block, get, set); + // TODO optimize } - int cyMin2 = cyMin * cyMin; - int cyMax2 = cyMax * cyMax; - - boolean containsMin = contains(bx, bz); - boolean containsMax = contains(tx, tz); - if (containsMin && containsMax) { - // set all - return; - } - - - for (int layer = 0; layer < 16; layer++) { - if (contains()) - } - TODO optimize; - int minY = getMinY(); - int maxY = getMaxY(); - contains() } } From a4344fb2dfb3b429cd69eee9c5b22c4878a37158 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Sat, 29 Jun 2019 14:06:19 +1000 Subject: [PATCH 26/54] add 1.14 depend (non functional) --- worldedit-bukkit/build.gradle | 11 +- .../com/boydti/fawe/bukkit/FaweBukkit.java | 6 +- .../adapter/v1_13_1/BlockMaterial_1_13.java | 4 +- .../adapter/v1_13_1/Spigot_v1_13_R2.java | 18 ++-- .../fawe/bukkit/beta/BukkitChunkHolder.java | 24 ++--- .../fawe/bukkit/beta/BukkitGetBlocks.java | 28 ++--- .../boydti/fawe/bukkit/beta/BukkitQueue.java | 34 +++--- .../fawe/bukkit/v1_13/BukkitChunk_1_13.java | 56 +++++----- .../fawe/bukkit/v1_13/BukkitQueue_1_13.java | 102 +++++++++--------- .../fawe/bukkit/wrapper/AsyncWorld.java | 28 +++-- .../worldedit/bukkit/WorldEditPlugin.java | 4 +- .../sk89q/worldedit/extent/InputExtent.java | 4 +- 12 files changed, 161 insertions(+), 158 deletions(-) diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle index 205c447d8..863012ff6 100644 --- a/worldedit-bukkit/build.gradle +++ b/worldedit-bukkit/build.gradle @@ -6,15 +6,20 @@ repositories { maven { url "https://hub.spigotmc.org/nexus/content/groups/public" } maven { url "https://repo.codemc.org/repository/maven-public" } maven { url 'https://papermc.io/repo/repository/maven-public/' } + flatDir { + dirs 'lib' + } } dependencies { compile project(':worldedit-core') -// compile 'org.bukkit:craftbukkit-1.14:pre5' compile 'net.milkbowl.vault:VaultAPI:1.7' compile 'com.sk89q:dummypermscompat:1.10' - compile 'com.destroystokyo.paper:paper-api:1.13.2-R0.1-SNAPSHOT' - compile 'org.spigotmc:spigot:1.13.2-R0.1-SNAPSHOT' + compile 'com.destroystokyo.paper:paper-api:1.14.3-R0.1-SNAPSHOT' + +// compile 'org.spigotmc:spigot:1.14.3-R0.1-SNAPSHOT' + compile name: 'spigot-1.14.3' + compile 'org.slf4j:slf4j-jdk14:1.7.26' testCompile 'org.mockito:mockito-core:1.9.0-rc1' compile 'com.massivecraft:factions:2.8.0' 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 913d0f0bb..cbbb2b5ce 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 @@ -614,13 +614,13 @@ public class FaweBukkit implements IFawe, Listener { } public enum Version { - v1_13_R2, + v1_14_R1, NONE, } private FaweQueue getQueue(World world) { switch (getVersion()) { - case v1_13_R2: + case v1_14_R1: return new BukkitQueue_1_13(world); default: case NONE: @@ -630,7 +630,7 @@ public class FaweBukkit implements IFawe, Listener { private FaweQueue getQueue(String world) { switch (getVersion()) { - case v1_13_R2: + case v1_14_R1: return new BukkitQueue_1_13(world); default: case NONE: diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/BlockMaterial_1_13.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/BlockMaterial_1_13.java index 53a59d24d..0cc6bf7da 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/BlockMaterial_1_13.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/BlockMaterial_1_13.java @@ -3,8 +3,8 @@ package com.boydti.fawe.bukkit.adapter.v1_13_1; import com.sk89q.util.ReflectionUtil; import com.sk89q.worldedit.world.registry.BlockMaterial; -import net.minecraft.server.v1_13_R2.*; -import org.bukkit.craftbukkit.v1_13_R2.block.data.CraftBlockData; +import net.minecraft.server.v1_14_R1.*; +import org.bukkit.craftbukkit.v1_14_R1.block.data.CraftBlockData; public class BlockMaterial_1_13 implements BlockMaterial { private final Block block; diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/Spigot_v1_13_R2.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/Spigot_v1_13_R2.java index 2adc9d3ad..b4aca6eb8 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/Spigot_v1_13_R2.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/Spigot_v1_13_R2.java @@ -40,17 +40,17 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.*; import com.sk89q.worldedit.world.entity.EntityType; import com.sk89q.worldedit.world.registry.BlockMaterial; -import net.minecraft.server.v1_13_R2.*; +import net.minecraft.server.v1_14_R1.*; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_13_R2.CraftChunk; -import org.bukkit.craftbukkit.v1_13_R2.CraftServer; -import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_13_R2.block.CraftBlock; -import org.bukkit.craftbukkit.v1_13_R2.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_13_R2.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_14_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_14_R1.CraftServer; +import org.bukkit.craftbukkit.v1_14_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_14_R1.block.CraftBlock; +import org.bukkit.craftbukkit.v1_14_R1.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity; import org.bukkit.entity.Player; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.slf4j.Logger; @@ -66,7 +66,7 @@ import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; -public final class Spigot_v1_13_R2 extends CachedBukkitAdapter implements BukkitImplAdapter{ +public final class Spigot_v1_14_R1 extends CachedBukkitAdapter implements BukkitImplAdapter{ private final Logger logger = LoggerFactory.getLogger(getClass()); @@ -82,7 +82,7 @@ public final class Spigot_v1_13_R2 extends CachedBukkitAdapter implements Bukkit // Code that may break between versions of Minecraft // ------------------------------------------------------------------------ - public Spigot_v1_13_R2() throws NoSuchFieldException, NoSuchMethodException { + public Spigot_v1_14_R1() throws NoSuchFieldException, NoSuchMethodException { // The list of tags on an NBTTagList nbtListTagListField = NBTTagList.class.getDeclaredField("list"); nbtListTagListField.setAccessible(true); diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java index 605f18d8b..fea4c3813 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java @@ -17,19 +17,19 @@ import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.internal.Constants; import com.sk89q.worldedit.world.biome.BiomeType; -import net.minecraft.server.v1_13_R2.BiomeBase; -import net.minecraft.server.v1_13_R2.BlockPosition; -import net.minecraft.server.v1_13_R2.Chunk; -import net.minecraft.server.v1_13_R2.ChunkSection; -import net.minecraft.server.v1_13_R2.Entity; -import net.minecraft.server.v1_13_R2.EntityTypes; -import net.minecraft.server.v1_13_R2.MinecraftKey; -import net.minecraft.server.v1_13_R2.NBTTagCompound; -import net.minecraft.server.v1_13_R2.NBTTagInt; -import net.minecraft.server.v1_13_R2.TileEntity; +import net.minecraft.server.v1_14_R1.BiomeBase; +import net.minecraft.server.v1_14_R1.BlockPosition; +import net.minecraft.server.v1_14_R1.Chunk; +import net.minecraft.server.v1_14_R1.ChunkSection; +import net.minecraft.server.v1_14_R1.Entity; +import net.minecraft.server.v1_14_R1.EntityTypes; +import net.minecraft.server.v1_14_R1.MinecraftKey; +import net.minecraft.server.v1_14_R1.NBTTagCompound; +import net.minecraft.server.v1_14_R1.NBTTagInt; +import net.minecraft.server.v1_14_R1.TileEntity; import org.bukkit.World; import org.bukkit.block.Biome; -import org.bukkit.craftbukkit.v1_13_R2.block.CraftBlock; +import org.bukkit.craftbukkit.v1_14_R1.block.CraftBlock; import org.bukkit.event.entity.CreatureSpawnEvent; import java.util.Collection; @@ -185,7 +185,7 @@ public class BukkitChunkHolder> extends ChunkHolder { Runnable[] syncTasks = null; - net.minecraft.server.v1_13_R2.World nmsWorld = nmsChunk.getWorld(); + net.minecraft.server.v1_14_R1.World nmsWorld = nmsChunk.getWorld(); int bx = X << 4; int bz = Z << 4; diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java index 1fdd4ce85..fd377a758 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java @@ -2,24 +2,24 @@ package com.boydti.fawe.bukkit.beta; import com.boydti.fawe.FaweCache; import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; -import com.boydti.fawe.bukkit.adapter.v1_13_1.Spigot_v1_13_R2; +import com.boydti.fawe.bukkit.adapter.v1_13_1.Spigot_v1_14_R1; import com.boydti.fawe.bukkit.v1_13.BukkitQueue_1_13; import com.boydti.fawe.jnbt.anvil.BitArray4096; import com.boydti.fawe.util.TaskManager; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockTypes; -import net.minecraft.server.v1_13_R2.Chunk; -import net.minecraft.server.v1_13_R2.ChunkCoordIntPair; -import net.minecraft.server.v1_13_R2.ChunkProviderServer; -import net.minecraft.server.v1_13_R2.ChunkSection; -import net.minecraft.server.v1_13_R2.DataBits; -import net.minecraft.server.v1_13_R2.DataPalette; -import net.minecraft.server.v1_13_R2.DataPaletteBlock; -import net.minecraft.server.v1_13_R2.DataPaletteHash; -import net.minecraft.server.v1_13_R2.DataPaletteLinear; -import net.minecraft.server.v1_13_R2.IBlockData; -import net.minecraft.server.v1_13_R2.World; +import net.minecraft.server.v1_14_R1.Chunk; +import net.minecraft.server.v1_14_R1.ChunkCoordIntPair; +import net.minecraft.server.v1_14_R1.ChunkProviderServer; +import net.minecraft.server.v1_14_R1.ChunkSection; +import net.minecraft.server.v1_14_R1.DataBits; +import net.minecraft.server.v1_14_R1.DataPalette; +import net.minecraft.server.v1_14_R1.DataPaletteBlock; +import net.minecraft.server.v1_14_R1.DataPaletteHash; +import net.minecraft.server.v1_14_R1.DataPaletteLinear; +import net.minecraft.server.v1_14_R1.IBlockData; +import net.minecraft.server.v1_14_R1.World; import java.util.Arrays; @@ -98,7 +98,7 @@ public class BukkitGetBlocks extends CharGetBlocks { if (ibd == null) { ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar(); } else { - ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToChar(ibd); + ordinal = ((Spigot_v1_14_R1) getAdapter()).adaptToChar(ibd); } paletteToBlockChars[paletteVal] = ordinal; } @@ -147,7 +147,7 @@ public class BukkitGetBlocks extends CharGetBlocks { if (ibd == null) { return BlockTypes.AIR.getDefaultState().getOrdinalChar(); } else { - return ((Spigot_v1_13_R2) getAdapter()).adaptToChar(ibd); + return ((Spigot_v1_14_R1) getAdapter()).adaptToChar(ibd); } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java index 3d34e3cb9..f0827403c 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java @@ -20,23 +20,23 @@ import com.sk89q.worldedit.world.block.BlockID; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; import net.jpountz.util.UnsafeUtils; -import net.minecraft.server.v1_13_R2.Block; -import net.minecraft.server.v1_13_R2.Chunk; -import net.minecraft.server.v1_13_R2.ChunkCoordIntPair; -import net.minecraft.server.v1_13_R2.ChunkProviderServer; -import net.minecraft.server.v1_13_R2.ChunkSection; -import net.minecraft.server.v1_13_R2.DataBits; -import net.minecraft.server.v1_13_R2.DataPalette; -import net.minecraft.server.v1_13_R2.DataPaletteBlock; -import net.minecraft.server.v1_13_R2.DataPaletteLinear; -import net.minecraft.server.v1_13_R2.GameProfileSerializer; -import net.minecraft.server.v1_13_R2.IBlockData; -import net.minecraft.server.v1_13_R2.PlayerChunk; -import net.minecraft.server.v1_13_R2.PlayerChunkMap; -import net.minecraft.server.v1_13_R2.WorldServer; +import net.minecraft.server.v1_14_R1.Block; +import net.minecraft.server.v1_14_R1.Chunk; +import net.minecraft.server.v1_14_R1.ChunkCoordIntPair; +import net.minecraft.server.v1_14_R1.ChunkProviderServer; +import net.minecraft.server.v1_14_R1.ChunkSection; +import net.minecraft.server.v1_14_R1.DataBits; +import net.minecraft.server.v1_14_R1.DataPalette; +import net.minecraft.server.v1_14_R1.DataPaletteBlock; +import net.minecraft.server.v1_14_R1.DataPaletteLinear; +import net.minecraft.server.v1_14_R1.GameProfileSerializer; +import net.minecraft.server.v1_14_R1.IBlockData; +import net.minecraft.server.v1_14_R1.PlayerChunk; +import net.minecraft.server.v1_14_R1.PlayerChunkMap; +import net.minecraft.server.v1_14_R1.WorldServer; import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_13_R2.CraftChunk; -import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_14_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_14_R1.CraftWorld; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -202,7 +202,7 @@ public class BukkitQueue extends SimpleCharQueueExtent { return ensureLoaded(nmsWorld, X, Z); } - public static Chunk ensureLoaded(net.minecraft.server.v1_13_R2.World nmsWorld, int X, int Z) { + public static Chunk ensureLoaded(net.minecraft.server.v1_14_R1.World nmsWorld, int X, int Z) { ChunkProviderServer provider = (ChunkProviderServer) nmsWorld.getChunkProvider(); Chunk nmsChunk = provider.chunks.get(ChunkCoordIntPair.a(X, Z)); if (nmsChunk != null) { diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitChunk_1_13.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitChunk_1_13.java index 4b9146f8c..4d0c6137f 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitChunk_1_13.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitChunk_1_13.java @@ -2,7 +2,7 @@ package com.boydti.fawe.bukkit.v1_13; import com.boydti.fawe.Fawe; import com.boydti.fawe.bukkit.adapter.v1_13_1.BlockMaterial_1_13; -import com.boydti.fawe.bukkit.adapter.v1_13_1.Spigot_v1_13_R2; +import com.boydti.fawe.bukkit.adapter.v1_13_1.Spigot_v1_14_R1; import com.boydti.fawe.bukkit.v0.BukkitQueue_0; import com.boydti.fawe.config.Settings; import com.boydti.fawe.example.IntFaweChunk; @@ -23,32 +23,32 @@ import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockID; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; -import net.minecraft.server.v1_13_R2.BiomeBase; -import net.minecraft.server.v1_13_R2.Block; -import net.minecraft.server.v1_13_R2.BlockPosition; -import net.minecraft.server.v1_13_R2.Blocks; -import net.minecraft.server.v1_13_R2.ChunkSection; -import net.minecraft.server.v1_13_R2.DataBits; -import net.minecraft.server.v1_13_R2.DataPalette; -import net.minecraft.server.v1_13_R2.DataPaletteBlock; -import net.minecraft.server.v1_13_R2.DataPaletteHash; -import net.minecraft.server.v1_13_R2.DataPaletteLinear; -import net.minecraft.server.v1_13_R2.Entity; -import net.minecraft.server.v1_13_R2.EntityPlayer; -import net.minecraft.server.v1_13_R2.EntityTypes; -import net.minecraft.server.v1_13_R2.GameProfileSerializer; -import net.minecraft.server.v1_13_R2.IBlockData; -import net.minecraft.server.v1_13_R2.MinecraftKey; -import net.minecraft.server.v1_13_R2.NBTTagCompound; -import net.minecraft.server.v1_13_R2.NBTTagInt; -import net.minecraft.server.v1_13_R2.NibbleArray; -import net.minecraft.server.v1_13_R2.RegistryID; -import net.minecraft.server.v1_13_R2.TileEntity; +import net.minecraft.server.v1_14_R1.BiomeBase; +import net.minecraft.server.v1_14_R1.Block; +import net.minecraft.server.v1_14_R1.BlockPosition; +import net.minecraft.server.v1_14_R1.Blocks; +import net.minecraft.server.v1_14_R1.ChunkSection; +import net.minecraft.server.v1_14_R1.DataBits; +import net.minecraft.server.v1_14_R1.DataPalette; +import net.minecraft.server.v1_14_R1.DataPaletteBlock; +import net.minecraft.server.v1_14_R1.DataPaletteHash; +import net.minecraft.server.v1_14_R1.DataPaletteLinear; +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.GameProfileSerializer; +import net.minecraft.server.v1_14_R1.IBlockData; +import net.minecraft.server.v1_14_R1.MinecraftKey; +import net.minecraft.server.v1_14_R1.NBTTagCompound; +import net.minecraft.server.v1_14_R1.NBTTagInt; +import net.minecraft.server.v1_14_R1.NibbleArray; +import net.minecraft.server.v1_14_R1.RegistryID; +import net.minecraft.server.v1_14_R1.TileEntity; import org.bukkit.Chunk; import org.bukkit.World; import org.bukkit.block.Biome; -import org.bukkit.craftbukkit.v1_13_R2.CraftChunk; -import org.bukkit.craftbukkit.v1_13_R2.block.CraftBlock; +import org.bukkit.craftbukkit.v1_14_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_14_R1.block.CraftBlock; import org.bukkit.event.entity.CreatureSpawnEvent; import java.lang.reflect.InvocationTargetException; @@ -134,7 +134,7 @@ public class BukkitChunk_1_13 extends IntFaweChunk { if (ibd == null) { ibd = defaultBlock; } - final int ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToInt(ibd); + final int ordinal = ((Spigot_v1_14_R1) getAdapter()).adaptToInt(ibd); idsArray[i] = BlockTypes.states[ordinal].getInternalId(); } } catch (final IllegalAccessException e) { @@ -328,7 +328,7 @@ public class BukkitChunk_1_13 extends IntFaweChunk { @Override public FaweChunk call() { - final Spigot_v1_13_R2 adapter = (Spigot_v1_13_R2) BukkitQueue_0.getAdapter(); + final Spigot_v1_14_R1 adapter = (Spigot_v1_14_R1) BukkitQueue_0.getAdapter(); try { final BukkitChunk_1_13 copy = getParent().getChangeTask() != null ? new BukkitChunk_1_13(getParent(), getX(), getZ()) : null; final Chunk chunk = this.getChunk(); @@ -337,11 +337,11 @@ public class BukkitChunk_1_13 extends IntFaweChunk { final int bx = this.getX() << 4; final int bz = this.getZ() << 4; final boolean flag = world.getEnvironment() == World.Environment.NORMAL; - final net.minecraft.server.v1_13_R2.Chunk nmsChunk = ((CraftChunk) chunk).getHandle(); + final net.minecraft.server.v1_14_R1.Chunk nmsChunk = ((CraftChunk) chunk).getHandle(); nmsChunk.f(true); // Set Modified nmsChunk.mustSave = true; nmsChunk.markDirty(); - final net.minecraft.server.v1_13_R2.World nmsWorld = nmsChunk.world; + final net.minecraft.server.v1_14_R1.World nmsWorld = nmsChunk.world; final ChunkSection[] sections = nmsChunk.getSections(); final List[] entities = nmsChunk.getEntitySlices(); final Map tiles = nmsChunk.getTileEntities(); diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java index 0f86e37c7..e9b76907f 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java @@ -4,7 +4,7 @@ import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; import com.boydti.fawe.bukkit.BukkitPlayer; import com.boydti.fawe.bukkit.adapter.v1_13_1.BlockMaterial_1_13; -import com.boydti.fawe.bukkit.adapter.v1_13_1.Spigot_v1_13_R2; +import com.boydti.fawe.bukkit.adapter.v1_13_1.Spigot_v1_14_R1; import com.boydti.fawe.bukkit.v0.BukkitQueue_0; import com.boydti.fawe.config.Settings; import com.boydti.fawe.example.IntFaweChunk; @@ -25,38 +25,38 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; -import net.minecraft.server.v1_13_R2.BiomeBase; -import net.minecraft.server.v1_13_R2.Block; -import net.minecraft.server.v1_13_R2.BlockPosition; -import net.minecraft.server.v1_13_R2.ChunkProviderServer; -import net.minecraft.server.v1_13_R2.ChunkSection; -import net.minecraft.server.v1_13_R2.DataBits; -import net.minecraft.server.v1_13_R2.DataPalette; -import net.minecraft.server.v1_13_R2.DataPaletteBlock; -import net.minecraft.server.v1_13_R2.DataPaletteHash; -import net.minecraft.server.v1_13_R2.DataPaletteLinear; -import net.minecraft.server.v1_13_R2.Entity; -import net.minecraft.server.v1_13_R2.EntityPlayer; -import net.minecraft.server.v1_13_R2.EnumSkyBlock; -import net.minecraft.server.v1_13_R2.GameProfileSerializer; -import net.minecraft.server.v1_13_R2.IBlockData; -import net.minecraft.server.v1_13_R2.NBTTagCompound; -import net.minecraft.server.v1_13_R2.Packet; -import net.minecraft.server.v1_13_R2.PacketDataSerializer; -import net.minecraft.server.v1_13_R2.PacketPlayOutMultiBlockChange; -import net.minecraft.server.v1_13_R2.PlayerChunk; -import net.minecraft.server.v1_13_R2.PlayerChunkMap; -import net.minecraft.server.v1_13_R2.RegistryID; -import net.minecraft.server.v1_13_R2.TileEntity; -import net.minecraft.server.v1_13_R2.WorldChunkManager; -import net.minecraft.server.v1_13_R2.WorldData; -import net.minecraft.server.v1_13_R2.WorldServer; +import net.minecraft.server.v1_14_R1.BiomeBase; +import net.minecraft.server.v1_14_R1.Block; +import net.minecraft.server.v1_14_R1.BlockPosition; +import net.minecraft.server.v1_14_R1.ChunkProviderServer; +import net.minecraft.server.v1_14_R1.ChunkSection; +import net.minecraft.server.v1_14_R1.DataBits; +import net.minecraft.server.v1_14_R1.DataPalette; +import net.minecraft.server.v1_14_R1.DataPaletteBlock; +import net.minecraft.server.v1_14_R1.DataPaletteHash; +import net.minecraft.server.v1_14_R1.DataPaletteLinear; +import net.minecraft.server.v1_14_R1.Entity; +import net.minecraft.server.v1_14_R1.EntityPlayer; +import net.minecraft.server.v1_14_R1.EnumSkyBlock; +import net.minecraft.server.v1_14_R1.GameProfileSerializer; +import net.minecraft.server.v1_14_R1.IBlockData; +import net.minecraft.server.v1_14_R1.NBTTagCompound; +import net.minecraft.server.v1_14_R1.Packet; +import net.minecraft.server.v1_14_R1.PacketDataSerializer; +import net.minecraft.server.v1_14_R1.PacketPlayOutMultiBlockChange; +import net.minecraft.server.v1_14_R1.PlayerChunk; +import net.minecraft.server.v1_14_R1.PlayerChunkMap; +import net.minecraft.server.v1_14_R1.RegistryID; +import net.minecraft.server.v1_14_R1.TileEntity; +import net.minecraft.server.v1_14_R1.WorldChunkManager; +import net.minecraft.server.v1_14_R1.WorldData; +import net.minecraft.server.v1_14_R1.WorldServer; import org.bukkit.Chunk; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_13_R2.CraftChunk; -import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_13_R2.block.CraftBlock; -import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_14_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_14_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_14_R1.block.CraftBlock; +import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer; import java.io.IOException; import java.lang.reflect.Field; @@ -66,7 +66,7 @@ import java.util.Map; import java.util.concurrent.atomic.LongAdder; import java.util.function.Supplier; -public class BukkitQueue_1_13 extends BukkitQueue_0 { +public class BukkitQueue_1_13 extends BukkitQueue_0 { public final static Field fieldBits; public final static Field fieldPalette; @@ -150,7 +150,7 @@ public class BukkitQueue_1_13 extends BukkitQueue_0 iter = provider.a().iterator(); +// Iterator iter = provider.a().iterator(); // while (iter.hasNext()) { -// net.minecraft.server.v1_13_R2.Chunk chunk = iter.next(); +// net.minecraft.server.v1_14_R1.Chunk chunk = iter.next(); // if (chunk.locX >> 5 == mcaX && chunk.locZ >> 5 == mcaZ) { // boolean isIn = allowed.isInChunk(chunk.locX, chunk.locZ); // if (isIn) { @@ -402,7 +402,7 @@ public class BukkitQueue_1_13 extends BukkitQueue_0 dataPalette = lastSection.getBlocks(); final IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); - final int ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToInt(ibd); + final int ordinal = ((Spigot_v1_14_R1) getAdapter()).adaptToInt(ibd); return BlockTypes.states[ordinal].getInternalId(); } @Override - public BiomeType getBiome(final net.minecraft.server.v1_13_R2.Chunk chunk, final int x, final int z) { + public BiomeType getBiome(final net.minecraft.server.v1_14_R1.Chunk chunk, final int x, final int z) { final BiomeBase base = chunk.getBiomeIndex()[((z & 15) << 4) + (x & 15)]; return getAdapter().adapt(CraftBlock.biomeBaseToBiome(base)); } @@ -563,7 +563,7 @@ public class BukkitQueue_1_13 extends BukkitQueue_0[] entities = nmsChunk.entitySlices; for (int i = 0; i < entities.length; i++) { @@ -931,7 +931,7 @@ public class BukkitQueue_1_13 extends BukkitQueue_0 tiles = chunk.getTileEntities(); pos.c(x, y, z); final TileEntity tile = tiles.get(pos); @@ -951,7 +951,7 @@ public class BukkitQueue_1_13 extends BukkitQueue_0() { @Override public void run(Boolean value) { - this.value = parent.unloadChunk(x, z, save, safe); + this.value = parent.unloadChunk(x, z, save); } }); } @@ -445,12 +440,15 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue @Override public boolean unloadChunkRequest(int x, int z) { - return unloadChunk(x, z); - } - - @Override - public boolean unloadChunkRequest(int x, int z, boolean safe) { - return unloadChunk(x, z, safe); + if (isChunkLoaded(x, z)) { + return TaskManager.IMP.sync(new RunnableVal() { + @Override + public void run(Boolean value) { + this.value = parent.unloadChunkRequest(x, z); + } + }); + } + return true; } @Override @@ -501,8 +499,8 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue } @Override - public T spawnArrow(Location location, Vector vector, float v, float v1, Class aClass) { - return parent.spawnArrow(location, vector, v, v1, aClass); + public T spawnArrow(Location location, Vector direction, float speed, float spread, Class clazz) { + return parent.spawnArrow(location, direction, speed, spread, clazz); } @Override 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 cdcdb6fb5..f4a7c6d3f 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 @@ -22,7 +22,7 @@ package com.sk89q.worldedit.bukkit; import com.bekvon.bukkit.residence.commands.message; import com.boydti.fawe.Fawe; import com.boydti.fawe.bukkit.FaweBukkit; -import com.boydti.fawe.bukkit.adapter.v1_13_1.Spigot_v1_13_R2; +import com.boydti.fawe.bukkit.adapter.v1_13_1.Spigot_v1_14_R1; import com.boydti.fawe.util.MainUtil; import com.google.common.base.Joiner; import com.sk89q.util.yaml.YAMLProcessor; @@ -366,7 +366,7 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter // Attempt to load a Bukkit adapter BukkitImplLoader adapterLoader = new BukkitImplLoader(); try { - adapterLoader.addClass(Spigot_v1_13_R2.class); + adapterLoader.addClass(Spigot_v1_14_R1.class); } catch (Throwable throwable) { throwable.printStackTrace(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/InputExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/InputExtent.java index 1f4342518..d8f533407 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/InputExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/InputExtent.java @@ -84,10 +84,10 @@ public interface InputExtent { * @return the biome at the location */ default BiomeType getBiome(BlockVector2 position) { - return getBiome(position.getX(), position.getZ()); + return getBiomeType(position.getX(), position.getZ()); } - default BiomeType getBiome(int x, int z) { + default BiomeType getBiomeType(int x, int z) { return getBiome(MutableBlockVector2.get(x, z)); } } From de52b65738a75e7939733aa03ebe137057c2628a Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Sat, 29 Jun 2019 16:04:37 +1000 Subject: [PATCH 27/54] Add paper methods to AsyncWorld --- .../fawe/bukkit/wrapper/AsyncWorld.java | 237 ++++++++---------- 1 file changed, 110 insertions(+), 127 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java index aa3b92e81..62321647f 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java @@ -1,6 +1,5 @@ package com.boydti.fawe.bukkit.wrapper; -import com.avaje.ebean.validation.NotNull; import com.boydti.fawe.FaweAPI; import com.boydti.fawe.bukkit.v0.BukkitQueue_0; import com.boydti.fawe.object.FaweQueue; @@ -29,6 +28,7 @@ import org.bukkit.*; import org.bukkit.block.Biome; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; +import org.bukkit.entity.AbstractArrow; import org.bukkit.entity.Arrow; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; @@ -47,6 +47,7 @@ import org.bukkit.util.BoundingBox; import org.bukkit.util.Consumer; import org.bukkit.util.RayTraceResult; import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; /** * Modify the world from an async thread
@@ -444,8 +445,8 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue } @Override - public T spawnArrow(Location location, Vector vector, float v, float v1, Class aClass) { - return parent.spawnArrow(location, vector, v, v1, aClass); + public @NotNull T spawnArrow(@NotNull Location location, @NotNull Vector direction, float speed, float spread, @NotNull Class clazz) { + return parent.spawnArrow(location, direction, speed, spread, clazz); } @Override @@ -1167,128 +1168,110 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue return parent.getForceLoadedChunks(); } -// @Override -// public int getHighestBlockYAt(int x, int z, com.destroystokyo.paper.HeightmapType heightmap) throws UnsupportedOperationException { -// return TaskManager.IMP.sync(new Supplier() { -// @Override -// public Integer get() { -// return parent.getHighestBlockYAt(x, z, heightmap); -// } -// }); -// } -// -// @Override -// public int getEntityCount() { -// return TaskManager.IMP.sync(new RunnableVal() { -// @Override -// public void run(Integer value) { -// this.value = parent.getEntityCount(); -// } -// }); -// } -// -// @Override -// public int getTileEntityCount() { -// return TaskManager.IMP.sync(new RunnableVal() { -// @Override -// public void run(Integer value) { -// this.value = parent.getTileEntityCount(); -// } -// }); -// } -// -// @Override -// public int getTickableTileEntityCount() { -// return TaskManager.IMP.sync(new RunnableVal() { -// @Override -// public void run(Integer value) { -// this.value = parent.getTickableTileEntityCount(); -// } -// }); -// } -// -// @Override -// public int getChunkCount() { -// return TaskManager.IMP.sync(new RunnableVal() { -// @Override -// public void run(Integer value) { -// this.value = parent.getChunkCount(); -// } -// }); -// } -// -// @Override -// public int getPlayerCount() { -// return TaskManager.IMP.sync(new RunnableVal() { -// @Override -// public void run(Integer value) { -// this.value = parent.getPlayerCount(); -// } -// }); -// } -// -// @Override -// public CompletableFuture getChunkAtAsync(int arg0, int arg1, boolean arg2) { -// return parent.getChunkAtAsync(arg0, arg1, arg2); -// } -// -// @Override -// public boolean isDayTime() { -// return parent.isDayTime(); -// } -// -// @Override -// public boolean unloadChunk(final int x, final int z, final boolean save, final boolean safe) { -// if (isChunkLoaded(x, z)) { -// return TaskManager.IMP.sync(new RunnableVal() { -// @Override -// public void run(Boolean value) { -// this.value = parent.unloadChunk(x, z, save, safe); -// } -// }); -// } -// return true; -// } -// -// @Override -// public boolean unloadChunkRequest(int x, int z, boolean safe) { -// return unloadChunk(x, z, safe); -// } -// -// @Override -// public void getChunkAtAsync(int x, int z, ChunkLoadCallback cb) { -// parent.getChunkAtAsync(x, z, cb); -// } -// -// @Override -// public void getChunkAtAsync(Location location, ChunkLoadCallback cb) { -// parent.getChunkAtAsync(location, cb); -// } -// -// @Override -// public void getChunkAtAsync(Block block, ChunkLoadCallback cb) { -// parent.getChunkAtAsync(block, cb); -// } -// -// @Override -// public Entity getEntity(UUID uuid) { -// return TaskManager.IMP.sync(() -> parent.getEntity(uuid)); -// } -// -// -// @Override -// public boolean createExplosion(Entity source, Location loc, float power, boolean setFire, boolean breakBlocks) { -// return TaskManager.IMP.sync(() -> parent.createExplosion(source, loc, power, setFire, breakBlocks)); -// } -// -// -// @Override -// public void spawnParticle(Particle particle, List receivers, Player source, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data) { -// parent.spawnParticle(particle, receivers, source, x, y, z, count, offsetX, offsetY, offsetZ, extra, data); -// } -// -// @Override -// public void spawnParticle(Particle particle, List list, Player player, double v, double v1, double v2, int i, double v3, double v4, double v5, double v6, T t, boolean b) { -// parent.spawnParticle(particle, list, player, v, v1, v2, i, v3, v4, v5, v6, t, b); -// } + @Override + public int getHighestBlockYAt(int x, int z, com.destroystokyo.paper.HeightmapType heightmap) throws UnsupportedOperationException { + return TaskManager.IMP.sync(new Supplier() { + @Override + public Integer get() { + return parent.getHighestBlockYAt(x, z, heightmap); + } + }); + } + + @Override + public int getEntityCount() { + return TaskManager.IMP.sync(new RunnableVal() { + @Override + public void run(Integer value) { + this.value = parent.getEntityCount(); + } + }); + } + + @Override + public int getTileEntityCount() { + return TaskManager.IMP.sync(new RunnableVal() { + @Override + public void run(Integer value) { + this.value = parent.getTileEntityCount(); + } + }); + } + + @Override + public int getTickableTileEntityCount() { + return TaskManager.IMP.sync(new RunnableVal() { + @Override + public void run(Integer value) { + this.value = parent.getTickableTileEntityCount(); + } + }); + } + + @Override + public int getChunkCount() { + return TaskManager.IMP.sync(new RunnableVal() { + @Override + public void run(Integer value) { + this.value = parent.getChunkCount(); + } + }); + } + + @Override + public int getPlayerCount() { + return TaskManager.IMP.sync(new RunnableVal() { + @Override + public void run(Integer value) { + this.value = parent.getPlayerCount(); + } + }); + } + + @Override + public CompletableFuture getChunkAtAsync(int arg0, int arg1, boolean arg2) { + return parent.getChunkAtAsync(arg0, arg1, arg2); + } + + @Override + public boolean isDayTime() { + return parent.isDayTime(); + } + + @Override + public void getChunkAtAsync(int x, int z, ChunkLoadCallback cb) { + parent.getChunkAtAsync(x, z, cb); + } + + @Override + public void getChunkAtAsync(Location location, ChunkLoadCallback cb) { + parent.getChunkAtAsync(location, cb); + } + + @Override + public void getChunkAtAsync(Block block, ChunkLoadCallback cb) { + parent.getChunkAtAsync(block, cb); + } + + @Override + public Entity getEntity(UUID uuid) { + return TaskManager.IMP.sync(() -> parent.getEntity(uuid)); + } + + + @Override + public boolean createExplosion(Entity source, Location loc, float power, boolean setFire, boolean breakBlocks) { + return TaskManager.IMP.sync(() -> parent.createExplosion(source, loc, power, setFire, breakBlocks)); + } + + + @Override + public void spawnParticle(Particle particle, List receivers, Player source, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data) { + parent.spawnParticle(particle, receivers, source, x, y, z, count, offsetX, offsetY, offsetZ, extra, data); + } + + @Override + public void spawnParticle(Particle particle, List list, Player player, double v, double v1, double v2, int i, double v3, double v4, double v5, double v6, T t, boolean b) { + parent.spawnParticle(particle, list, player, v, v1, v2, i, v3, v4, v5, v6, t, b); + } } From 0d7b4629bafe05646d0df499ea3939bad8c25dac Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Sat, 29 Jun 2019 16:08:03 +1000 Subject: [PATCH 28/54] re-add 1.13 depend --- worldedit-bukkit/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle index 32d95545a..f194b7fd5 100644 --- a/worldedit-bukkit/build.gradle +++ b/worldedit-bukkit/build.gradle @@ -25,7 +25,7 @@ dependencies { compile 'com.destroystokyo.paper:paper-api:1.14.3-R0.1-SNAPSHOT' implementation 'io.papermc:paperlib:1.0.2' compileOnly 'com.sk89q:dummypermscompat:1.10' -// compile 'org.spigotmc:spigot:1.13.2-R0.1-SNAPSHOT' + compile 'org.spigotmc:spigot:1.13.2-R0.1-SNAPSHOT' compile name: 'spigot-1.14.3' implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1' testCompile 'org.mockito:mockito-core:1.9.0-rc1' From 19468b64d4caeccd70248f4f96851f91c08b8f64 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Tue, 9 Jul 2019 17:46:27 +1000 Subject: [PATCH 29/54] Use bstats for metrics The metrics config option will be removed in the future - The current value will be copied over when generating bstats config --- .../java/com/boydti/fawe/bukkit/BStats.java | 705 ------------------ .../com/boydti/fawe/bukkit/FaweBukkit.java | 3 +- .../java/org/bstats/bukkit/MetricsLite.java | 367 +++++++++ .../src/main/java/com/boydti/fawe/Fawe.java | 5 + .../main/java/com/boydti/fawe/beta/Flood.java | 1 - .../java/com/boydti/fawe/config/Settings.java | 2 +- 6 files changed, 375 insertions(+), 708 deletions(-) delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/BStats.java create mode 100644 worldedit-bukkit/src/main/java/org/bstats/bukkit/MetricsLite.java diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/BStats.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/BStats.java deleted file mode 100644 index 8031c1242..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/BStats.java +++ /dev/null @@ -1,705 +0,0 @@ -package com.boydti.fawe.bukkit; - -import com.boydti.fawe.Fawe; -import org.bstats.bukkit.Metrics; -import org.bukkit.Bukkit; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.RegisteredServiceProvider; -import org.bukkit.plugin.ServicePriority; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; - -import javax.net.ssl.HttpsURLConnection; -import java.io.*; -import java.lang.reflect.InvocationTargetException; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.Callable; -import java.util.logging.Level; -import java.util.zip.GZIPOutputStream; - -/** - * bStats collects some data for plugin authors. - *

- * Check out https://bStats.org/ to learn more about bStats! - */ -@SuppressWarnings({"WeakerAccess", "unused"}) public class BStats { - - static { - // You can use the property to disable the check in your test environment - if (System.getProperty("bstats.relocatecheck") == null || !System - .getProperty("bstats.relocatecheck").equals("false")) { - // Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D - final String defaultPackage = new String( - new byte[] {'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', - 'k', 'i', 't'}); - final String examplePackage = - new String(new byte[] {'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); - // We want to make sure nobody just copy & pastes the example and use the wrong package names - if (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class - .getPackage().getName().equals(examplePackage)) { - throw new IllegalStateException( - "bStats Metrics class has not been relocated correctly!"); - } - } - } - - // The version of this bStats class - public static final int B_STATS_VERSION = 1; - - // The url to which the data is sent - private static final String URL = "https://bStats.org/submitData/bukkit"; - - // Is bStats enabled on this server? - private boolean enabled; - - // Should failed requests be logged? - private static boolean logFailedRequests; - - // Should the sent data be logged? - private static boolean logSentData; - - // Should the response text be logged? - private static boolean logResponseStatusText; - - // The uuid of the server - private static String serverUUID; - - // The plugin - private final Plugin plugin; - - // A list with all custom charts - private final List charts = new ArrayList<>(); - - /** - * Class constructor. - * - * @param plugin The plugin which stats should be submitted. - */ - public BStats(Plugin plugin) { - if (plugin == null) { - throw new IllegalArgumentException("Plugin cannot be null!"); - } - this.plugin = plugin; - - // Get the config file - File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); - File configFile = new File(bStatsFolder, "config.yml"); - YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); - - // Check if the config file exists - if (!config.isSet("serverUuid")) { - - // Add default values - config.addDefault("enabled", true); - // Every server gets it's unique random id. - config.addDefault("serverUuid", UUID.randomUUID().toString()); - // Should failed request be logged? - config.addDefault("logFailedRequests", false); - // Should the sent data be logged? - config.addDefault("logSentData", false); - // Should the response text be logged? - config.addDefault("logResponseStatusText", false); - - // Inform the server owners about bStats - config.options().header( - "bStats collects some data for plugin authors like how many servers are using their plugins.\n" - + "To honor their work, you should not disable it.\n" - + "This has nearly no effect on the server performance!\n" - + "Check out https://bStats.org/ to learn more :)").copyDefaults(true); - try { - config.save(configFile); - } catch (IOException ignored) { - } - } - - // Load the data - enabled = config.getBoolean("enabled", true); - serverUUID = config.getString("serverUuid"); - logFailedRequests = config.getBoolean("logFailedRequests", false); - logSentData = config.getBoolean("logSentData", false); - logResponseStatusText = config.getBoolean("logResponseStatusText", false); - - if (enabled) { - boolean found = false; - // Search for all other bStats Metrics classes to see if we are the first one - for (Class service : Bukkit.getServicesManager().getKnownServices()) { - try { - service.getField("B_STATS_VERSION"); // Our identifier :) - found = true; // We aren't the first - break; - } catch (NoSuchFieldException ignored) { - } - } - // Register our service - Bukkit.getServicesManager() - .register(BStats.class, this, plugin, ServicePriority.Normal); - if (!found) { - // We are the first! - startSubmitting(); - } - } - } - - /** - * Checks if bStats is enabled. - * - * @return Whether bStats is enabled or not. - */ - public boolean isEnabled() { - return enabled; - } - - /** - * Adds a custom chart. - * - * @param chart The chart to add. - */ - public void addCustomChart(CustomChart chart) { - if (chart == null) { - throw new IllegalArgumentException("Chart cannot be null!"); - } - charts.add(chart); - } - - /** - * Starts the Scheduler which submits our data every 30 minutes. - */ - private void startSubmitting() { - final Timer timer = - new Timer(true); // We use a timer cause the Bukkit scheduler is affected by server lags - timer.scheduleAtFixedRate(new TimerTask() { - @Override public void run() { - if (!plugin.isEnabled()) { // Plugin was disabled - timer.cancel(); - return; - } - // Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler - // Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;) - Bukkit.getScheduler().runTask(plugin, () -> submitData()); - } - }, 1000 * 60 * 5, 1000 * 60 * 30); - // Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start - // WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted! - // WARNING: Just don't do it! - } - - /** - * Gets the plugin specific data. - * This method is called using Reflection. - * - * @return The plugin specific data. - */ - public JSONObject getPluginData() { - JSONObject data = new JSONObject(); - - String pluginName = "FastAsyncWorldEdit"; - String pluginVersion = Fawe.get().getVersion() + ""; - - data.put("pluginName", pluginName); // Append the name of the plugin - data.put("pluginVersion", pluginVersion); // Append the version of the plugin - JSONArray customCharts = new JSONArray(); - for (CustomChart customChart : charts) { - // Add the data of the custom charts - JSONObject chart = customChart.getRequestJsonObject(); - if (chart == null) { // If the chart is null, we skip it - continue; - } - customCharts.add(chart); - } - data.put("customCharts", customCharts); - - return data; - } - - /** - * Gets the server specific data. - * - * @return The server specific data. - */ - private JSONObject getServerData() { - // Minecraft specific data - int playerAmount = getPlayerCount(); - int onlineMode = Fawe.imp().isOnlineMode() ? 1 : 0; - String serverVersion = Fawe.imp().getPlatformVersion(); - - // OS/Java specific data - String javaVersion = System.getProperty("java.version"); - String osName = System.getProperty("os.name"); - String osArch = System.getProperty("os.arch"); - String osVersion = System.getProperty("os.version"); - int coreCount = Runtime.getRuntime().availableProcessors(); - - JSONObject data = new JSONObject(); - - data.put("serverUUID", serverUUID); - - data.put("playerAmount", playerAmount); - data.put("onlineMode", onlineMode); - data.put("bukkitVersion", serverVersion); - - data.put("javaVersion", javaVersion); - data.put("osName", osName); - data.put("osArch", osArch); - data.put("osVersion", osVersion); - data.put("coreCount", coreCount); - - return data; - } - - public int getPlayerCount() { - return Fawe.imp() == null ? 1 : Fawe.imp().getPlayerCount(); - } - - /** - * Collects the data and sends it afterwards. - */ - private void submitData() { - final JSONObject data = getServerData(); - - JSONArray pluginData = new JSONArray(); - // Search for all other bStats Metrics classes to get their plugin data - for (Class service : Bukkit.getServicesManager().getKnownServices()) { - try { - service.getField("B_STATS_VERSION"); // Our identifier :) - - for (RegisteredServiceProvider provider : Bukkit.getServicesManager() - .getRegistrations(service)) { - try { - pluginData.add(provider.getService().getMethod("getPluginData") - .invoke(provider.getProvider())); - } catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { - } - } - } catch (NoSuchFieldException ignored) { - } - } - - data.put("plugins", pluginData); - - // Create a new thread for the connection to the bStats server - new Thread(() -> { - try { - // Send the data - sendData(plugin, data); - } catch (Exception e) { - // Something went wrong! :( - if (logFailedRequests) { - plugin.getLogger() - .log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), - e); - } - } - }).start(); - } - - /** - * Sends the data to the bStats server. - * - * @param plugin Any plugin. It's just used to get a logger instance. - * @param data The data to send. - * @throws Exception If the request failed. - */ - private static void sendData(Plugin plugin, JSONObject data) throws Exception { - if (data == null) { - throw new IllegalArgumentException("Data cannot be null!"); - } - if (Bukkit.isPrimaryThread()) { - throw new IllegalAccessException( - "This method must not be called from the main thread!"); - } - if (logSentData) { - plugin.getLogger().info("Sending data to bStats: " + data.toString()); - } - HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection(); - - // Compress the data to save bandwidth - byte[] compressedData = compress(data.toString()); - - // Add headers - connection.setRequestMethod("POST"); - connection.addRequestProperty("Accept", "application/json"); - connection.addRequestProperty("Connection", "close"); - connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request - connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); - connection.setRequestProperty("Content-Type", - "application/json"); // We send our data in JSON format - connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION); - - // Send data - connection.setDoOutput(true); - try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) { - outputStream.write(compressedData); - outputStream.flush(); - } - - StringBuilder builder; - try (InputStream inputStream = connection.getInputStream(); - BufferedReader bufferedReader = new BufferedReader( - new InputStreamReader(inputStream))) { - - builder = new StringBuilder(); - String line; - while ((line = bufferedReader.readLine()) != null) { - builder.append(line); - } - } - if (logResponseStatusText) { - plugin.getLogger() - .info("Sent data to bStats and received response: " + builder.toString()); - } - } - - /** - * Gzips the given String. - * - * @param str The string to gzip. - * @return The gzipped String. - * @throws IOException If the compression failed. - */ - private static byte[] compress(final String str) throws IOException { - if (str == null) { - return null; - } - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - GZIPOutputStream gzip = new GZIPOutputStream(outputStream); - gzip.write(str.getBytes(StandardCharsets.UTF_8)); - gzip.close(); - return outputStream.toByteArray(); - } - - /** - * Represents a custom chart. - */ - public static abstract class CustomChart { - - // The id of the chart - final String chartId; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - */ - CustomChart(String chartId) { - if (chartId == null || chartId.isEmpty()) { - throw new IllegalArgumentException("ChartId cannot be null or empty!"); - } - this.chartId = chartId; - } - - private JSONObject getRequestJsonObject() { - JSONObject chart = new JSONObject(); - chart.put("chartId", chartId); - try { - JSONObject data = getChartData(); - if (data == null) { - // If the data is null we don't send the chart. - return null; - } - chart.put("data", data); - } catch (Throwable t) { - if (logFailedRequests) { - Bukkit.getLogger().log(Level.WARNING, - "Failed to get data for custom chart with id " + chartId, t); - } - return null; - } - return chart; - } - - protected abstract JSONObject getChartData() throws Exception; - - } - - - /** - * Represents a custom simple pie. - */ - public static class SimplePie extends CustomChart { - - private final Callable callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SimplePie(String chartId, Callable callable) { - super(chartId); - this.callable = callable; - } - - @Override protected JSONObject getChartData() throws Exception { - JSONObject data = new JSONObject(); - String value = callable.call(); - if (value == null || value.isEmpty()) { - // Null = skip the chart - return null; - } - data.put("value", value); - return data; - } - } - - - /** - * Represents a custom advanced pie. - */ - public static class AdvancedPie extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public AdvancedPie(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override protected JSONObject getChartData() throws Exception { - JSONObject data = new JSONObject(); - JSONObject values = new JSONObject(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() == 0) { - continue; // Skip this invalid - } - allSkipped = false; - values.put(entry.getKey(), entry.getValue()); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - data.put("values", values); - return data; - } - } - - - /** - * Represents a custom drilldown pie. - */ - public static class DrilldownPie extends CustomChart { - - private final Callable>> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public DrilldownPie(String chartId, Callable>> callable) { - super(chartId); - this.callable = callable; - } - - @Override public JSONObject getChartData() throws Exception { - JSONObject data = new JSONObject(); - JSONObject values = new JSONObject(); - Map> map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean reallyAllSkipped = true; - for (Map.Entry> entryValues : map.entrySet()) { - JSONObject value = new JSONObject(); - boolean allSkipped = true; - for (Map.Entry valueEntry : map.get(entryValues.getKey()) - .entrySet()) { - value.put(valueEntry.getKey(), valueEntry.getValue()); - allSkipped = false; - } - if (!allSkipped) { - reallyAllSkipped = false; - values.put(entryValues.getKey(), value); - } - } - if (reallyAllSkipped) { - // Null = skip the chart - return null; - } - data.put("values", values); - return data; - } - } - - - /** - * Represents a custom single line chart. - */ - public static class SingleLineChart extends CustomChart { - - private final Callable callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SingleLineChart(String chartId, Callable callable) { - super(chartId); - this.callable = callable; - } - - @Override protected JSONObject getChartData() throws Exception { - JSONObject data = new JSONObject(); - int value = callable.call(); - if (value == 0) { - // Null = skip the chart - return null; - } - data.put("value", value); - return data; - } - - } - - - /** - * Represents a custom multi line chart. - */ - public static class MultiLineChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public MultiLineChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override protected JSONObject getChartData() throws Exception { - JSONObject data = new JSONObject(); - JSONObject values = new JSONObject(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() == 0) { - continue; // Skip this invalid - } - allSkipped = false; - values.put(entry.getKey(), entry.getValue()); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - data.put("values", values); - return data; - } - - } - - - /** - * Represents a custom simple bar chart. - */ - public static class SimpleBarChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SimpleBarChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override protected JSONObject getChartData() throws Exception { - JSONObject data = new JSONObject(); - JSONObject values = new JSONObject(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - for (Map.Entry entry : map.entrySet()) { - JSONArray categoryValues = new JSONArray(); - categoryValues.add(entry.getValue()); - values.put(entry.getKey(), categoryValues); - } - data.put("values", values); - return data; - } - - } - - - /** - * Represents a custom advanced bar chart. - */ - public static class AdvancedBarChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public AdvancedBarChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override protected JSONObject getChartData() throws Exception { - JSONObject data = new JSONObject(); - JSONObject values = new JSONObject(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue().length == 0) { - continue; // Skip this invalid - } - allSkipped = false; - JSONArray categoryValues = new JSONArray(); - for (int categoryValue : entry.getValue()) { - categoryValues.add(categoryValue); - } - values.put(entry.getKey(), categoryValues); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - data.put("values", values); - return data; - } - } - -} 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 35acd8310..8ac840a5f 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 @@ -46,6 +46,7 @@ import com.boydti.fawe.util.TaskManager; import com.boydti.fawe.util.image.ImageViewer; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.world.World; +import org.bstats.bukkit.MetricsLite; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.command.ConsoleCommandSender; @@ -263,7 +264,7 @@ public class FaweBukkit implements IFawe, Listener { } @Override public void startMetrics() { - new BStats(plugin); + new MetricsLite(plugin); } public ItemUtil getItemUtil() { diff --git a/worldedit-bukkit/src/main/java/org/bstats/bukkit/MetricsLite.java b/worldedit-bukkit/src/main/java/org/bstats/bukkit/MetricsLite.java new file mode 100644 index 000000000..20772b14b --- /dev/null +++ b/worldedit-bukkit/src/main/java/org/bstats/bukkit/MetricsLite.java @@ -0,0 +1,367 @@ +package org.bstats.bukkit; + +import com.boydti.fawe.config.Settings; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.plugin.ServicePriority; + +import javax.net.ssl.HttpsURLConnection; +import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Collection; +import java.util.Timer; +import java.util.TimerTask; +import java.util.UUID; +import java.util.logging.Level; +import java.util.zip.GZIPOutputStream; + +/** + * bStats collects some data for plugin authors. + *

+ * Check out https://bStats.org/ to learn more about bStats! + */ +@SuppressWarnings({"WeakerAccess", "unused"}) +public class MetricsLite { + + static { + // You can use the property to disable the check in your test environment + if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) { + // Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D + final String defaultPackage = new String( + new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't'}); + final String examplePackage = defaultPackage; + // We want to make sure nobody just copy & pastes the example and use the wrong package names + if (MetricsLite.class.getPackage().getName().equals(defaultPackage) || MetricsLite.class.getPackage().getName().equals(examplePackage)) { + throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); + } + } + } + + // The version of this bStats class + public static final int B_STATS_VERSION = 1; + + // The url to which the data is sent + private static final String URL = "https://bStats.org/submitData/bukkit"; + + // Is bStats enabled on this server? + private boolean enabled; + + // Should failed requests be logged? + private static boolean logFailedRequests; + + // Should the sent data be logged? + private static boolean logSentData; + + // Should the response text be logged? + private static boolean logResponseStatusText; + + // The uuid of the server + private static String serverUUID; + + // The plugin + private final Plugin plugin; + + /** + * Class constructor. + * + * @param plugin The plugin which stats should be submitted. + */ + public MetricsLite(Plugin plugin) { + if (plugin == null) { + throw new IllegalArgumentException("Plugin cannot be null!"); + } + this.plugin = plugin; + + // Get the config file + File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); + File configFile = new File(bStatsFolder, "config.yml"); + YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); + + // Check if the config file exists + if (!config.isSet("serverUuid")) { + + // Add default values + config.addDefault("enabled", Settings.IMP.METRICS); + // Every server gets it's unique random id. + config.addDefault("serverUuid", UUID.randomUUID().toString()); + // Should failed request be logged? + config.addDefault("logFailedRequests", false); + // Should the sent data be logged? + config.addDefault("logSentData", false); + // Should the response text be logged? + config.addDefault("logResponseStatusText", false); + + // Inform the server owners about bStats + config.options().header( + "bStats collects some data for plugin authors like how many servers are using their plugins.\n" + + "To honor their work, you should not disable it.\n" + + "This has nearly no effect on the server performance!\n" + + "Check out https://bStats.org/ to learn more :)" + ).copyDefaults(true); + try { + config.save(configFile); + } catch (IOException ignored) { } + } + + // Load the data + serverUUID = config.getString("serverUuid"); + logFailedRequests = config.getBoolean("logFailedRequests", false); + enabled = config.getBoolean("enabled", Settings.IMP.METRICS); + logSentData = config.getBoolean("logSentData", false); + logResponseStatusText = config.getBoolean("logResponseStatusText", false); + if (enabled) { + boolean found = false; + // Search for all other bStats Metrics classes to see if we are the first one + for (Class service : Bukkit.getServicesManager().getKnownServices()) { + try { + service.getField("B_STATS_VERSION"); // Our identifier :) + found = true; // We aren't the first + break; + } catch (NoSuchFieldException ignored) { } + } + // Register our service + Bukkit.getServicesManager().register(MetricsLite.class, this, plugin, ServicePriority.Normal); + if (!found) { + // We are the first! + startSubmitting(); + } + } + } + + /** + * Checks if bStats is enabled. + * + * @return Whether bStats is enabled or not. + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Starts the Scheduler which submits our data every 30 minutes. + */ + private void startSubmitting() { + final Timer timer = new Timer(true); // We use a timer cause the Bukkit scheduler is affected by server lags + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + if (!plugin.isEnabled()) { // Plugin was disabled + timer.cancel(); + return; + } + // Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler + // Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;) + Bukkit.getScheduler().runTask(plugin, () -> submitData()); + } + }, 1000 * 60 * 5, 1000 * 60 * 30); + // Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start + // WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted! + // WARNING: Just don't do it! + } + + /** + * Gets the plugin specific data. + * This method is called using Reflection. + * + * @return The plugin specific data. + */ + public JsonObject getPluginData() { + JsonObject data = new JsonObject(); + + String pluginName = plugin.getDescription().getName(); + String pluginVersion = plugin.getDescription().getVersion(); + + data.addProperty("pluginName", pluginName); // Append the name of the plugin + data.addProperty("pluginVersion", pluginVersion); // Append the version of the plugin + data.add("customCharts", new JsonArray()); + + return data; + } + + /** + * Gets the server specific data. + * + * @return The server specific data. + */ + private JsonObject getServerData() { + // Minecraft specific data + int playerAmount; + try { + // Around MC 1.8 the return type was changed to a collection from an array, + // This fixes java.lang.NoSuchMethodError: org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection; + Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers"); + playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class) + ? ((Collection) onlinePlayersMethod.invoke(Bukkit.getServer())).size() + : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length; + } catch (Exception e) { + playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed + } + int onlineMode = Bukkit.getOnlineMode() ? 1 : 0; + String bukkitVersion = Bukkit.getVersion(); + String bukkitName = Bukkit.getName(); + + // OS/Java specific data + String javaVersion = System.getProperty("java.version"); + String osName = System.getProperty("os.name"); + String osArch = System.getProperty("os.arch"); + String osVersion = System.getProperty("os.version"); + int coreCount = Runtime.getRuntime().availableProcessors(); + + JsonObject data = new JsonObject(); + + data.addProperty("serverUUID", serverUUID); + + data.addProperty("playerAmount", playerAmount); + data.addProperty("onlineMode", onlineMode); + data.addProperty("bukkitVersion", bukkitVersion); + data.addProperty("bukkitName", bukkitName); + + data.addProperty("javaVersion", javaVersion); + data.addProperty("osName", osName); + data.addProperty("osArch", osArch); + data.addProperty("osVersion", osVersion); + data.addProperty("coreCount", coreCount); + + return data; + } + + /** + * Collects the data and sends it afterwards. + */ + private void submitData() { + final JsonObject data = getServerData(); + + JsonArray pluginData = new JsonArray(); + // Search for all other bStats Metrics classes to get their plugin data + for (Class service : Bukkit.getServicesManager().getKnownServices()) { + try { + service.getField("B_STATS_VERSION"); // Our identifier :) + + for (RegisteredServiceProvider provider : Bukkit.getServicesManager().getRegistrations(service)) { + try { + Object plugin = provider.getService().getMethod("getPluginData").invoke(provider.getProvider()); + if (plugin instanceof JsonObject) { + pluginData.add((JsonObject) plugin); + } else { // old bstats version compatibility + try { + Class jsonObjectJsonSimple = Class.forName("org.json.simple.JSONObject"); + if (plugin.getClass().isAssignableFrom(jsonObjectJsonSimple)) { + Method jsonStringGetter = jsonObjectJsonSimple.getDeclaredMethod("toJSONString"); + jsonStringGetter.setAccessible(true); + String jsonString = (String) jsonStringGetter.invoke(plugin); + JsonObject object = new JsonParser().parse(jsonString).getAsJsonObject(); + pluginData.add(object); + } + } catch (ClassNotFoundException e) { + // minecraft version 1.14+ + if (logFailedRequests) { + this.plugin.getLogger().log(Level.SEVERE, "Encountered unexpected exception ", e); + } + continue; // continue looping since we cannot do any other thing. + } + } + } catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { + } + } + } catch (NoSuchFieldException ignored) { } + } + + data.add("plugins", pluginData); + + // Create a new thread for the connection to the bStats server + new Thread(new Runnable() { + @Override + public void run() { + try { + // Send the data + sendData(plugin, data); + } catch (Exception e) { + // Something went wrong! :( + if (logFailedRequests) { + plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e); + } + } + } + }).start(); + } + + /** + * Sends the data to the bStats server. + * + * @param plugin Any plugin. It's just used to get a logger instance. + * @param data The data to send. + * @throws Exception If the request failed. + */ + private static void sendData(Plugin plugin, JsonObject data) throws Exception { + if (data == null) { + throw new IllegalArgumentException("Data cannot be null!"); + } + if (Bukkit.isPrimaryThread()) { + throw new IllegalAccessException("This method must not be called from the main thread!"); + } + if (logSentData) { + plugin.getLogger().info("Sending data to bStats: " + data.toString()); + } + HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection(); + + // Compress the data to save bandwidth + byte[] compressedData = compress(data.toString()); + + // Add headers + connection.setRequestMethod("POST"); + connection.addRequestProperty("Accept", "application/json"); + connection.addRequestProperty("Connection", "close"); + connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request + connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); + connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format + connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION); + + // Send data + connection.setDoOutput(true); + DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream()); + outputStream.write(compressedData); + outputStream.flush(); + outputStream.close(); + + InputStream inputStream = connection.getInputStream(); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); + + StringBuilder builder = new StringBuilder(); + String line; + while ((line = bufferedReader.readLine()) != null) { + builder.append(line); + } + bufferedReader.close(); + if (logResponseStatusText) { + plugin.getLogger().info("Sent data to bStats and received response: " + builder.toString()); + } + } + + /** + * Gzips the given String. + * + * @param str The string to gzip. + * @return The gzipped String. + * @throws IOException If the compression failed. + */ + private static byte[] compress(final String str) throws IOException { + if (str == null) { + return null; + } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + GZIPOutputStream gzip = new GZIPOutputStream(outputStream); + gzip.write(str.getBytes(StandardCharsets.UTF_8)); + gzip.close(); + return outputStream.toByteArray(); + } + +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java b/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java index f36c8e522..d9fe50c22 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java @@ -178,6 +178,11 @@ public class Fawe { WEManager.IMP.managers.add(new PlotSquaredFeature()); Fawe.debug("Plugin 'PlotSquared' found. Using it now."); } catch (Throwable ignored) {} + try { + imp().startMetrics(); + } catch (Throwable ignored) { + debug(ignored.getMessage()); + } }, 0); TaskManager.IMP.repeat(timer, 1); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/Flood.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/Flood.java index 602da196b..bfc567181 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/Flood.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/Flood.java @@ -49,7 +49,6 @@ public class Flood { int Z = MathMan.unpairIntY(firstKey); int[][] chunkQueue = chunkQueues.get(firstKey); // apply - TODO } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/config/Settings.java b/worldedit-core/src/main/java/com/boydti/fawe/config/Settings.java index 462fb8633..5e234d644 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/config/Settings.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/config/Settings.java @@ -29,7 +29,7 @@ public class Settings extends Config { @Comment({"Options: cn, de, es, fr, it, nl, ru, tr", "Create a PR to contribute a translation: https://github.com/IntellectualSites/FastAsyncWorldEdit-1.13/tree/master/worldedit-core/src/main/resources",}) public String LANGUAGE = ""; - @Comment("Send anonymous usage statistics") + @Comment("@deprecated - use bstats config.yml") public boolean METRICS = true; @Comment({ "Set true to enable WorldEdit restrictions per region (e.g. PlotSquared or WorldGuard).", From 6a87d2107db7a9fcc33072234fb89ca0bc01cfab Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Wed, 10 Jul 2019 04:58:53 +1000 Subject: [PATCH 30/54] fix compile --- worldedit-bukkit/build.gradle | 4 +- .../fawe/bukkit/beta/BukkitChunkHolder.java | 55 ++++--- .../fawe/bukkit/beta/BukkitGetBlocks.java | 13 +- .../boydti/fawe/bukkit/beta/BukkitQueue.java | 25 +-- .../fawe/bukkit/v1_14/BukkitQueue_1_14.java | 4 +- .../bukkit/v1_14/adapter/Spigot_v1_14_R1.java | 1 - .../fawe/object/collection/ChunkBitSet.java | 152 ++++++++++++++++++ 7 files changed, 210 insertions(+), 44 deletions(-) create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/object/collection/ChunkBitSet.java diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle index be0cc651e..b915d4e92 100644 --- a/worldedit-bukkit/build.gradle +++ b/worldedit-bukkit/build.gradle @@ -8,7 +8,7 @@ repositories { maven { url "https://repo.codemc.org/repository/maven-public" } maven { url "https://papermc.io/repo/repository/maven-public/" } flatDir { - dirs 'lib' + dirs "$rootProject.projectDir/lib" } } @@ -26,6 +26,7 @@ task downloadJarsToLibs(){ } dependencies { + compile ('net.milkbowl.vault:VaultAPI:1.7') api project(':worldedit-core') api project(':worldedit-libs:bukkit') compileOnly 'com.sk89q:dummypermscompat:1.10' @@ -38,7 +39,6 @@ dependencies { // compile([fileTree(dir: 'lib', include: ['*.jar']),'commons-validator:commons-validator:1.4.1']) implementation('com.sk89q.worldguard:worldguard-core:7.0.0-20190215.210421-39'){transitive = false} implementation('com.sk89q.worldguard:worldguard-legacy:7.0.0-20190215.210421-39'){transitive = false} - implementation('net.milkbowl.vault:VaultAPI:1.7'){transitive = false} implementation('com.massivecraft:factions:2.8.0'){transitive = false} implementation('com.drtshock:factions:1.6.9.5'){transitive = false} implementation('com.factionsone:FactionsOne:1.2.2'){transitive = false} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java index 3987e02de..919da1b05 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java @@ -7,7 +7,7 @@ import com.boydti.fawe.beta.IChunkSet; import com.boydti.fawe.beta.implementation.QueueHandler; import com.boydti.fawe.beta.implementation.holder.ChunkHolder; import com.boydti.fawe.bukkit.v0.BukkitQueue_0; -import com.boydti.fawe.bukkit.v1_13.BukkitQueue_1_13; +import com.boydti.fawe.bukkit.v1_14.BukkitQueue_1_14; import com.boydti.fawe.util.MemUtil; import com.boydti.fawe.util.ReflectionUtils; import com.sk89q.jnbt.CompoundTag; @@ -71,6 +71,11 @@ public class BukkitChunkHolder> extends ChunkHolder { } } + private void removeEntity(Entity entity) { + entity.die(); + entity.valid = false; + } + @Override public synchronized T call() { try { @@ -99,7 +104,7 @@ public class BukkitChunkHolder> extends ChunkHolder { } if (set.getBlock(lx, ly, lz).getOrdinal() != 0) { TileEntity tile = entry.getValue(); - tile.z(); + tile.n(); tile.invalidateBlockCache(); } } @@ -121,7 +126,7 @@ public class BukkitChunkHolder> extends ChunkHolder { ChunkSection newSection; ChunkSection existingSection = sections[layer]; if (existingSection == null) { - newSection = extent.newChunkSection(layer, hasSky, setArr); + newSection = extent.newChunkSection(layer, setArr); if (BukkitQueue.setSectionAtomic(sections, null, newSection, layer)) { updateGet(get, nmsChunk, sections, newSection, setArr, layer); continue; @@ -159,7 +164,7 @@ public class BukkitChunkHolder> extends ChunkHolder { getArr[i] = value; } } - newSection = extent.newChunkSection(layer, hasSky, getArr); + newSection = extent.newChunkSection(layer, getArr); if (!BukkitQueue.setSectionAtomic(sections, existingSection, newSection, layer)) { System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer); continue; @@ -207,9 +212,7 @@ public class BukkitChunkHolder> extends ChunkHolder { final Entity entity = iter.next(); if (entityRemoves.contains(entity.getUniqueID())) { iter.remove(); - entity.b(false); - entity.die(); - entity.valid = false; + removeEntity(entity); } } } @@ -240,20 +243,24 @@ public class BukkitChunkHolder> extends ChunkHolder { final float yaw = rotTag.getFloat(0); final float pitch = rotTag.getFloat(1); final String id = idTag.getValue(); - final Entity entity = EntityTypes.a(nmsWorld, new MinecraftKey(id)); - if (entity != null) { - final UUID uuid = entity.getUniqueID(); - entityTagMap.put("UUIDMost", new LongTag(uuid.getMostSignificantBits())); - entityTagMap.put("UUIDLeast", new LongTag(uuid.getLeastSignificantBits())); - if (nativeTag != null) { - final NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_13.fromNative(nativeTag); - for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); + + EntityTypes type = EntityTypes.a(id).orElse(null); + if (type != null) { + Entity entity = type.a(nmsWorld); + if (entity != null) { + UUID uuid = entity.getUniqueID(); + entityTagMap.put("UUIDMost", new LongTag(uuid.getMostSignificantBits())); + entityTagMap.put("UUIDLeast", new LongTag(uuid.getLeastSignificantBits())); + if (nativeTag != null) { + final NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_14.fromNative(nativeTag); + for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + tag.remove(name); + } + entity.f(tag); } - entity.f(tag); + entity.setLocation(x, y, z, yaw, pitch); + nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM); } - entity.setLocation(x, y, z, yaw, pitch); - nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM); } } } @@ -278,12 +285,12 @@ public class BukkitChunkHolder> extends ChunkHolder { final BlockPosition pos = new BlockPosition(x, y, z); synchronized (BukkitQueue_0.class) { TileEntity tileEntity = nmsWorld.getTileEntity(pos); - if (tileEntity == null || tileEntity.x()) { - nmsWorld.n(pos); + if (tileEntity == null || tileEntity.isRemoved()) { + nmsWorld.removeTileEntity(pos); tileEntity = nmsWorld.getTileEntity(pos); } if (tileEntity != null) { - final NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_13.fromNative(nativeTag); + final NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_14.fromNative(nativeTag); tag.set("x", new NBTTagInt(x)); tag.set("y", new NBTTagInt(y)); tag.set("z", new NBTTagInt(z)); @@ -302,8 +309,8 @@ public class BukkitChunkHolder> extends ChunkHolder { int finalMask = bitMask; callback = () -> { // Set Modified - nmsChunk.f(true); - nmsChunk.mustSave = true; + nmsChunk.d(true); // Set Modified + nmsChunk.mustNotSave = false; nmsChunk.markDirty(); // send to player extent.sendChunk(X, Z, finalMask); diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java index da1506fd7..256268ec5 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java @@ -9,6 +9,7 @@ import com.boydti.fawe.util.MemUtil; import com.boydti.fawe.util.TaskManager; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockTypes; import net.minecraft.server.v1_14_R1.BiomeBase; @@ -84,6 +85,8 @@ public class BukkitGetBlocks extends CharGetBlocks { lock.setModified(false); // Efficiently convert ChunkSection to raw data try { + Spigot_v1_14_R1 adapter = ((Spigot_v1_14_R1) WorldEditPlugin.getInstance().getBukkitImplAdapter()); + final DataPaletteBlock blocks = section.getBlocks(); final DataBits bits = (DataBits) BukkitQueue_1_14.fieldBits.get(blocks); final DataPalette palette = (DataPalette) BukkitQueue_1_14.fieldPalette.get(blocks); @@ -112,7 +115,7 @@ public class BukkitGetBlocks extends CharGetBlocks { if (ibd == null) { ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar(); } else { - ordinal = ((Spigot_v1_14_R1) getAdapter()).adaptToChar(ibd); + ordinal = adapter.adaptToChar(ibd); } paletteToBlockChars[paletteVal] = ordinal; } @@ -132,7 +135,7 @@ public class BukkitGetBlocks extends CharGetBlocks { final int size = num_palette; if (size != 1) { for (int i = 0; i < size; i++) { - char ordinal = ordinal(palette.a(i)); + char ordinal = ordinal(palette.a(i), adapter); paletteToBlockChars[i] = ordinal; } for (int i = 0; i < 4096; i++) { @@ -141,7 +144,7 @@ public class BukkitGetBlocks extends CharGetBlocks { data[i] = val; } } else { - char ordinal = ordinal(palette.a(0)); + char ordinal = ordinal(palette.a(0), adapter); Arrays.fill(data, ordinal); } } finally { @@ -157,11 +160,11 @@ public class BukkitGetBlocks extends CharGetBlocks { } } - private final char ordinal(IBlockData ibd) { + private final char ordinal(IBlockData ibd, Spigot_v1_14_R1 adapter) { if (ibd == null) { return BlockTypes.AIR.getDefaultState().getOrdinalChar(); } else { - return ((Spigot_v1_14_R1) getAdapter()).adaptToChar(ibd); + return adapter.adaptToChar(ibd); } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java index 79b37e1eb..2e48d7329 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java @@ -7,6 +7,7 @@ import com.boydti.fawe.beta.implementation.SimpleCharQueueExtent; import com.boydti.fawe.beta.implementation.SingleThreadQueueExtent; import com.boydti.fawe.beta.implementation.WorldChunkCache; import com.boydti.fawe.bukkit.adapter.v1_13_1.BlockMaterial_1_13; +import com.boydti.fawe.bukkit.v1_14.adapter.BlockMaterial_1_14; import com.boydti.fawe.config.Settings; import com.boydti.fawe.jnbt.anvil.BitArray4096; import com.boydti.fawe.object.collection.IterableThreadLocal; @@ -234,14 +235,11 @@ public class BukkitQueue extends SimpleCharQueueExtent { } private PlayerChunk getPlayerChunk(final int cx, final int cz) { - final PlayerChunkMap chunkMap = nmsWorld.getPlayerChunkMap(); - final PlayerChunk playerChunk = chunkMap.getChunk(cx, cz); + PlayerChunkMap chunkMap = nmsWorld.getChunkProvider().playerChunkMap; + PlayerChunk playerChunk = chunkMap.visibleChunks.get(ChunkCoordIntPair.pair(cx, cz)); if (playerChunk == null) { return null; } - if (playerChunk.players.isEmpty()) { - return null; - } return playerChunk; } @@ -250,14 +248,20 @@ public class BukkitQueue extends SimpleCharQueueExtent { if (playerChunk == null) { return false; } - if (playerChunk.e()) { +// ChunkSection[] sections = nmsChunk.getSections(); +// for (int layer = 0; layer < 16; layer++) { +// if (sections[layer] == null && (mask & (1 << layer)) != 0) { +// sections[layer] = new ChunkSection(layer << 4); +// } +// } + if (playerChunk.hasBeenLoaded()) { TaskManager.IMP.sync(new Supplier() { @Override public Object get() { try { int dirtyBits = fieldDirtyBits.getInt(playerChunk); if (dirtyBits == 0) { - nmsWorld.getPlayerChunkMap().a(playerChunk); + nmsWorld.getChunkProvider().playerChunkMap.a(playerChunk); } if (mask == 0) { dirtyBits = 65535; @@ -267,14 +271,15 @@ public class BukkitQueue extends SimpleCharQueueExtent { fieldDirtyBits.set(playerChunk, dirtyBits); fieldDirtyCount.set(playerChunk, 64); - } catch (final IllegalAccessException e) { + } catch (IllegalAccessException e) { e.printStackTrace(); } return null; } }); + return true; } - return true; + return false; } /* @@ -342,7 +347,7 @@ public class BukkitQueue extends SimpleCharQueueExtent { final int ordinal = paletteToBlock[i]; blockToPalette[ordinal] = Integer.MAX_VALUE; final BlockState state = BlockTypes.states[ordinal]; - final IBlockData ibd = ((BlockMaterial_1_13) state.getMaterial()).getState(); + final IBlockData ibd = ((BlockMaterial_1_14) state.getMaterial()).getState(); palette.a(ibd); } try { diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_14/BukkitQueue_1_14.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_14/BukkitQueue_1_14.java index b6ddf06de..bdeaca902 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_14/BukkitQueue_1_14.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_14/BukkitQueue_1_14.java @@ -72,8 +72,8 @@ import java.util.function.Supplier; public class BukkitQueue_1_14 extends BukkitQueue_0 { - protected final static Field fieldBits; - protected final static Field fieldPalette; + public final static Field fieldBits; + public final static Field fieldPalette; protected final static Field fieldSize; protected final static Field fieldHashBlocks; diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_14/adapter/Spigot_v1_14_R1.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_14/adapter/Spigot_v1_14_R1.java index 717cac214..6aa146a24 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_14/adapter/Spigot_v1_14_R1.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_14/adapter/Spigot_v1_14_R1.java @@ -20,7 +20,6 @@ package com.boydti.fawe.bukkit.v1_14.adapter; import com.boydti.fawe.Fawe; -import com.boydti.fawe.bukkit.adapter.v1_13_1.BlockMaterial_1_13; import com.google.common.collect.ImmutableList; import com.google.common.collect.Maps; import com.sk89q.jnbt.ByteArrayTag; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/ChunkBitSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/ChunkBitSet.java new file mode 100644 index 000000000..33e3988ab --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/ChunkBitSet.java @@ -0,0 +1,152 @@ +package com.boydti.fawe.object.collection; + +import java.util.Arrays; + +public class ChunkBitSet { + private final static int CHUNK_LAYERS = 16; + private final static int BITS_PER_LAYER = 4096; + private final static int BITS_PER_WORD = 6; + private final static int WORDS = BITS_PER_LAYER >> BITS_PER_WORD; + private final static IRow NULL_ROW_X = new NullRowX(); + private final static IRow NULL_ROW_Z = new NullRowZ(); + private final static IRow NULL_ROW_Y = new NullRowY(); + + private final IRow[] rows; + + public ChunkBitSet() { + this(16); + } + + public ChunkBitSet(int size) { + this.rows = new IRow[size]; + for (int i = 0; i < size; i++) rows[i] = NULL_ROW_X; + } + + public boolean get(int x, int y, int z) { + return rows[x >> 4].get(this.rows, x, y, z); + } + + public void set(int x, int y, int z) { + rows[x >> 4].set(this.rows, x, y, z); + } + + public void clear(int x, int y, int z) { + rows[x >> 4].clear(this.rows, x, y, z); + } + + private interface IRow { + default boolean get(IRow[] rows, int x, int y, int z) { return false; } + void set(IRow[] rows, int x, int y, int z); + default void clear(IRow[] rows, int x, int y, int z) { return; } + } + + private static class NullRowX implements IRow { + @Override + public void set(IRow[] parent, int x, int y, int z) { + IRow row = new RowX(parent.length); + parent[x >> 4] = row; + row.set(parent, x, y, z); + } + } + + private static class NullRowZ implements IRow { + @Override + public void set(IRow[] parent, int x, int y, int z) { + IRow row = new RowZ(); + parent[z >> 4] = row; + row.set(parent, x, y, z); + } + } + + private static class NullRowY implements IRow { + @Override + public void set(IRow[] parent, int x, int y, int z) { + IRow row = new RowY(); + parent[y >> 4] = row; + row.set(parent, x, y, z); + } + } + + private static class RowX implements IRow { + private final IRow[] rows; + + public RowX(int size) { + this.rows = new IRow[size]; + for (int i = 0; i < size; i++) rows[i] = NULL_ROW_Z; + } + + @Override + public boolean get(IRow[] parent, int x, int y, int z) { + return rows[z >> 4].get(this.rows, x, y, z); + } + + @Override + public void set(IRow[] parent, int x, int y, int z) { + this.rows[z >> 4].set(this.rows, x, y, z); + } + + @Override + public void clear(IRow[] parent, int x, int y, int z) { + this.rows[z >> 4].clear(this.rows, x, y, z); + } + } + + private static class RowZ implements IRow { + private final IRow[] rows; + + public RowZ() { + this.rows = new IRow[CHUNK_LAYERS]; + for (int i = 0; i < CHUNK_LAYERS; i++) rows[i] = NULL_ROW_Y; + } + + @Override + public boolean get(IRow[] parent, int x, int y, int z) { + return rows[y >> 4].get(this.rows, x, y, z); + } + + @Override + public void set(IRow[] parent, int x, int y, int z) { + this.rows[y >> 4].set(this.rows, x, y, z); + } + + @Override + public void clear(IRow[] parent, int x, int y, int z) { + this.rows[y >> 4].set(this.rows, x, y, z); + } + } + + private static class RowY implements IRow { + private final long[] bits; + + public RowY() { + this.bits = new long[WORDS]; + } + + @Override + public boolean get(IRow[] parent, int x, int y, int z) { + int i = ((y & 15) << 8) | ((z & 15) << 4) | (x & 15); + return (bits[i >> 6] & (1L << (i & 0x3F))) != 0; + } + + @Override + public void set(IRow[] parent, int x, int y, int z) { + int i = ((y & 15) << 8) | ((z & 15) << 4) | (x & 15); + bits[i >> 6] |= (1L << (i & 0x3F)); + } + + @Override + public void clear(IRow[] parent, int x, int y, int z) { + int i = ((y & 15) << 8) | ((z & 15) << 4) | (x & 15); + bits[i >> 6] &= ~(1L << (i & 0x3F)); + } + } + + private static IRow[] resize(IRow[] arr, IRow def) { + int len = arr.length; + int newLen = len == 1 ? 1 : Integer.highestOneBit(len - 1) * 2; + IRow[] copy = Arrays.copyOf(arr, newLen, IRow[].class); + for (int i = len; i < newLen; i++) copy[i] = def; + return copy; + } +} + From 4a40c7d99caf8f8a0df4ffac02ef1b77c1f0e738 Mon Sep 17 00:00:00 2001 From: MattBDev <4009945+MattBDev@users.noreply.github.com> Date: Tue, 9 Jul 2019 15:50:13 -0400 Subject: [PATCH 31/54] Renaming and cleanup and a new method. --- .../sk89q/worldedit/bukkit/BukkitWorld.java | 11 +- .../main/java/com/boydti/fawe/FaweAPI.java | 9 +- .../main/java/com/boydti/fawe/FaweCache.java | 15 +- .../boydti/fawe/command/AnvilCommands.java | 121 ++++-- .../com/boydti/fawe/command/CFICommand.java | 71 ++-- .../com/boydti/fawe/command/CFICommands.java | 399 ++++++++++-------- .../fawe/command/FawePrimitiveBinding.java | 262 ++++++------ .../main/java/com/boydti/fawe/config/BBC.java | 2 +- .../com/boydti/fawe/example/NMSRelighter.java | 2 +- .../com/boydti/fawe/jnbt/NBTStreamer.java | 14 +- .../boydti/fawe/jnbt/SchematicStreamer.java | 20 +- .../fawe/jnbt/anvil/generator/OreGen.java | 23 +- .../fawe/jnbt/anvil/generator/Resource.java | 5 +- .../fawe/jnbt/anvil/generator/SchemGen.java | 2 +- .../fawe/object/brush/ShatterBrush.java | 60 ++- .../brush/visualization/VisualExtent.java | 29 +- .../AbstractDelegateFaweClipboard.java | 5 +- .../clipboard/CPUOptimizedClipboard.java | 11 +- .../clipboard/DiskOptimizedClipboard.java | 87 ++-- .../fawe/object/clipboard/FaweClipboard.java | 16 +- .../clipboard/MemoryOptimizedClipboard.java | 18 +- .../object/clipboard/OffsetFaweClipboard.java | 1 - .../object/clipboard/ReadOnlyClipboard.java | 6 +- .../object/clipboard/WorldCopyClipboard.java | 31 +- .../object/clipboard/WorldCutClipboard.java | 1 + .../clipboard/remap/RemappedClipboard.java | 72 ---- .../object/clipboard/remap/WikiScraper.java | 14 +- .../collection/FastRandomCollection.java | 2 +- .../collection/LocalBlockVector2DSet.java | 38 +- .../collection/LocalBlockVectorSet.java | 4 +- .../fawe/object/extent/MultiTransform.java | 2 +- .../boydti/fawe/object/extent/NullExtent.java | 106 ++--- .../fawe/object/extent/ProcessedWEExtent.java | 23 +- .../fawe/object/extent/StripNBTExtent.java | 4 +- .../boydti/fawe/object/mask/AngleMask.java | 7 - .../fawe/object/mask/BlockLightMask.java | 5 - .../fawe/object/mask/BrightnessMask.java | 9 +- .../com/boydti/fawe/object/mask/DataMask.java | 8 - .../boydti/fawe/object/mask/IdDataMask.java | 9 - .../com/boydti/fawe/object/mask/IdMask.java | 5 - .../boydti/fawe/object/mask/LightMask.java | 7 +- .../boydti/fawe/object/mask/OpacityMask.java | 5 - .../boydti/fawe/object/mask/PlaneMask.java | 5 - .../boydti/fawe/object/mask/RadiusMask.java | 5 - .../boydti/fawe/object/mask/SkyLightMask.java | 7 +- .../fawe/object/mask/SolidPlaneMask.java | 5 - .../boydti/fawe/object/mask/XAxisMask.java | 5 - .../boydti/fawe/object/mask/YAxisMask.java | 8 - .../boydti/fawe/object/mask/ZAxisMask.java | 5 - .../fawe/object/pattern/PatternExtent.java | 20 +- .../object/progress/ChatProgressTracker.java | 12 +- .../fawe/object/regions/PolyhedralRegion.java | 2 +- ...ureFormat.java => MinecraftStructure.java} | 40 +- .../fawe/object/visitor/FaweChunkVisitor.java | 10 +- .../fawe/regions/general/plot/PlotTrim.java | 23 +- .../boydti/fawe/wrappers/WorldWrapper.java | 8 +- .../java/com/sk89q/jnbt/NBTInputStream.java | 51 +-- .../java/com/sk89q/worldedit/EditSession.java | 123 +++--- .../com/sk89q/worldedit/LocalSession.java | 2 +- .../worldedit/command/ClipboardCommands.java | 39 +- .../worldedit/command/SchematicCommands.java | 8 +- .../worldedit/command/tool/BrushTool.java | 6 +- .../extent/clipboard/BlockArrayClipboard.java | 5 +- .../worldedit/extent/clipboard/Clipboard.java | 3 +- .../clipboard/io/BuiltInClipboardFormat.java | 37 +- .../transform/BlockTransformExtent.java | 30 +- .../function/mask/BlockCategoryMask.java | 8 - .../worldedit/function/mask/BlockMask.java | 7 - .../function/mask/BlockStateMask.java | 6 - .../function/mask/BlockTypeMask.java | 8 - .../function/mask/BoundedHeightMask.java | 9 - .../function/mask/ExistingBlockMask.java | 8 - .../worldedit/function/mask/RegionMask.java | 9 - .../function/mask/SolidBlockMask.java | 8 - .../sk89q/worldedit/math/MutableVector3.java | 3 - .../com/sk89q/worldedit/util/Location.java | 4 - .../sk89q/worldedit/world/AbstractWorld.java | 5 + .../sk89q/worldedit/world/SimpleWorld.java | 31 +- .../java/com/sk89q/worldedit/world/World.java | 13 + 79 files changed, 893 insertions(+), 1226 deletions(-) delete mode 100644 worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/remap/RemappedClipboard.java rename worldedit-core/src/main/java/com/boydti/fawe/object/schematic/{StructureFormat.java => MinecraftStructure.java} (92%) 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 887b48e7b..1a8769094 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 @@ -47,10 +47,12 @@ import org.bukkit.block.Chest; import org.bukkit.entity.Entity; import org.bukkit.inventory.DoubleChestInventory; import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; import org.slf4j.Logger; import javax.annotation.Nullable; import java.lang.ref.WeakReference; +import java.nio.file.Path; import java.util.ArrayList; import java.util.EnumMap; import java.util.HashMap; @@ -154,6 +156,11 @@ public class BukkitWorld extends AbstractWorld { return getWorld().getName(); } + @Override + public Path getStoragePath() { + return getWorld().getWorldFolder().toPath(); + } + @Override public int getBlockLightLevel(BlockVector3 pt) { return getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).getLightLevel(); @@ -239,11 +246,11 @@ public class BukkitWorld extends AbstractWorld { return false; } BlockState state = block.getState(); - if (!(state instanceof org.bukkit.inventory.InventoryHolder)) { + if (!(state instanceof InventoryHolder)) { return false; } - org.bukkit.inventory.InventoryHolder chest = (org.bukkit.inventory.InventoryHolder) state; + InventoryHolder chest = (InventoryHolder) state; Inventory inven = chest.getInventory(); if (chest instanceof Chest) { inven = getBlockInventory((Chest) chest); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/FaweAPI.java b/worldedit-core/src/main/java/com/boydti/fawe/FaweAPI.java index 763b22c02..656a5c51b 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/FaweAPI.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/FaweAPI.java @@ -17,6 +17,7 @@ import com.boydti.fawe.util.SetQueue; import com.boydti.fawe.util.TaskManager; import com.boydti.fawe.util.WEManager; import com.boydti.fawe.wrappers.WorldWrapper; + import com.google.common.collect.Sets; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEdit; @@ -36,24 +37,18 @@ import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.world.AbstractWorld; import com.sk89q.worldedit.world.World; -import org.jetbrains.annotations.NotNull; +import javax.annotation.Nullable; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.net.URL; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; /** * The FaweAPI class offers a few useful functions.
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 c3ed20bf8..cf345ef95 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java @@ -1,12 +1,17 @@ package com.boydti.fawe; import com.boydti.fawe.object.collection.IterableThreadLocal; + import com.sk89q.jnbt.*; -import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockTypes; import java.lang.reflect.Field; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; public class FaweCache { public static final IterableThreadLocal BLOCK_TO_PALETTE = new IterableThreadLocal() { @@ -115,7 +120,7 @@ public class FaweCache { } else if (value instanceof String) { return asTag((String) value); } else if (value instanceof Map) { - return asTag((Map) value); + return asTag((Map) value); } else if (value instanceof Collection) { return asTag((Collection) value); } else if (value instanceof Object[]) { @@ -153,7 +158,7 @@ public class FaweCache { } public static ListTag asTag(Object... values) { - Class clazz = null; + Class clazz = null; List list = new ArrayList<>(values.length); for (Object value : values) { Tag tag = asTag(value); @@ -167,7 +172,7 @@ public class FaweCache { } public static ListTag asTag(Collection values) { - Class clazz = null; + Class clazz = null; List list = new ArrayList<>(values.size()); for (Object value : values) { Tag tag = asTag(value); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/command/AnvilCommands.java b/worldedit-core/src/main/java/com/boydti/fawe/command/AnvilCommands.java index c1430dab8..26e19a352 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/command/AnvilCommands.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/command/AnvilCommands.java @@ -1,10 +1,12 @@ package com.boydti.fawe.command; -import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweAPI; -import com.boydti.fawe.FaweCache; import com.boydti.fawe.config.BBC; -import com.boydti.fawe.jnbt.anvil.*; +import com.boydti.fawe.jnbt.anvil.MCAClipboard; +import com.boydti.fawe.jnbt.anvil.MCAFile; +import com.boydti.fawe.jnbt.anvil.MCAFilter; +import com.boydti.fawe.jnbt.anvil.MCAFilterCounter; +import com.boydti.fawe.jnbt.anvil.MCAQueue; import com.boydti.fawe.jnbt.anvil.filters.*; import com.boydti.fawe.jnbt.anvil.history.IAnvilHistory; import com.boydti.fawe.jnbt.anvil.history.NullAnvilHistory; @@ -14,17 +16,18 @@ import com.boydti.fawe.object.RegionWrapper; import com.boydti.fawe.object.RunnableVal4; import com.boydti.fawe.object.changeset.AnvilHistory; import com.boydti.fawe.object.clipboard.remap.ClipboardRemapper; -import com.boydti.fawe.object.mask.FaweBlockMatcher; import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.SetQueue; -import com.boydti.fawe.util.StringMan; + +import static com.google.common.base.Preconditions.checkNotNull; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.EditSession; +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.function.pattern.Pattern; -import com.sk89q.worldedit.function.pattern.RandomPattern; import com.sk89q.worldedit.internal.annotation.Selection; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; @@ -36,17 +39,12 @@ import com.sk89q.worldedit.world.biome.BiomeType; import java.io.IOException; import java.io.RandomAccessFile; -import java.util.*; import java.util.function.Consumer; - -import static com.google.common.base.Preconditions.checkNotNull; - -@Command(aliases = {"/anvil"}, desc = "Manipulate billions of blocks: [More Info](https://github.com/boy0001/FastAsyncWorldedit/wiki/Anvil-API)") +@Command(aliases = {"/anvil"}, + desc = "Manipulate billions of blocks: [More Info](https://github.com/boy0001/FastAsyncWorldedit/wiki/Anvil-API)") public class AnvilCommands { - private final WorldEdit worldEdit; - /** * Create a new instance. * @@ -54,7 +52,6 @@ public class AnvilCommands { */ public AnvilCommands(WorldEdit worldEdit) { checkNotNull(worldEdit); - this.worldEdit = worldEdit; } /** @@ -170,19 +167,20 @@ public class AnvilCommands { ) @CommandPermissions("worldedit.anvil.remapall") public void remapall(Player player, String folder) throws WorldEditException { - ClipboardRemapper mapper; ClipboardRemapper.RemapPlatform from; ClipboardRemapper.RemapPlatform to; from = ClipboardRemapper.RemapPlatform.PE; to = ClipboardRemapper.RemapPlatform.PC; RemapFilter filter = new RemapFilter(from, to); RemapFilter result = runWithWorld(player, folder, filter, true); - if (result != null) player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + if (result != null) { + player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + } } @Command( - aliases = {"deleteallunvisited", "delunvisited" }, + aliases = {"deleteallunvisited", "delunvisited"}, usage = " [file-age=60000]", desc = "Delete all chunks which haven't been occupied", help = "Delete all chunks which haven't been occupied for `age-ticks` (20t = 1s) and \n" + @@ -196,11 +194,13 @@ public class AnvilCommands { public void deleteAllUnvisited(Player player, String folder, int inhabitedTicks, @Optional("60000") int fileDurationMillis) throws WorldEditException { DeleteUninhabitedFilter filter = new DeleteUninhabitedFilter(fileDurationMillis, inhabitedTicks, fileDurationMillis); DeleteUninhabitedFilter result = runWithWorld(player, folder, filter, true); - if (result != null) player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + if (result != null) { + player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + } } @Command( - aliases = {"deleteallunclaimed", "delallunclaimed" }, + aliases = {"deleteallunclaimed", "delallunclaimed"}, usage = " [file-age=60000]", desc = "(Supports: WG, P2, GP) Delete all chunks which haven't been occupied AND claimed", help = "(Supports: WG, P2, GP) Delete all chunks which aren't claimed AND haven't been occupied for `age-ticks` (20t = 1s) and \n" + @@ -211,12 +211,17 @@ public class AnvilCommands { max = 3 ) @CommandPermissions("worldedit.anvil.deleteallunclaimed") - public void deleteAllUnclaimed(Player player, int inhabitedTicks, @Optional("60000") int fileDurationMillis, @Switch('d') boolean debug) throws WorldEditException { + public void deleteAllUnclaimed(Player player, int inhabitedTicks, @Optional("60000") int fileDurationMillis, @Switch( + 'd') boolean debug) throws WorldEditException { String folder = player.getWorld().getName(); DeleteUnclaimedFilter filter = new DeleteUnclaimedFilter(player.getWorld(), fileDurationMillis, inhabitedTicks, fileDurationMillis); - if (debug) filter.enableDebug(); + if (debug) { + filter.enableDebug(); + } DeleteUnclaimedFilter result = runWithWorld(player, folder, filter, true); - if (result != null) player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + if (result != null) { + player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + } } @Command( @@ -231,15 +236,20 @@ public class AnvilCommands { max = 3 ) @CommandPermissions("worldedit.anvil.deleteunclaimed") - public void deleteUnclaimed(Player player, EditSession editSession, @Selection Region selection, int inhabitedTicks, @Optional("60000") int fileDurationMillis, @Switch('d') boolean debug) throws WorldEditException { + public void deleteUnclaimed(Player player, EditSession editSession, @Selection Region selection, int inhabitedTicks, @Optional( + "60000") int fileDurationMillis, @Switch('d') boolean debug) throws WorldEditException { DeleteUnclaimedFilter filter = new DeleteUnclaimedFilter(player.getWorld(), fileDurationMillis, inhabitedTicks, fileDurationMillis); - if (debug) filter.enableDebug(); + if (debug) { + filter.enableDebug(); + } DeleteUnclaimedFilter result = runWithSelection(player, editSession, selection, filter); - if (result != null) player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + if (result != null) { + player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + } } @Command( - aliases = {"deletealloldregions", "deloldreg" }, + aliases = {"deletealloldregions", "deloldreg"}, usage = "