diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle index f194b7fd5..be0cc651e 100644 --- a/worldedit-bukkit/build.gradle +++ b/worldedit-bukkit/build.gradle @@ -18,31 +18,39 @@ configurations.all { Configuration it -> } } +task downloadJarsToLibs(){ + def f = new File('lib/spigot-1.14.jar') + if (!f.exists()) { + new URL('https://ci.athion.net/job/BuildTools/lastSuccessfulBuild/artifact/spigot-1.14.jar').withInputStream{ i -> f.withOutputStream{ it << i }} + } +} + dependencies { api project(':worldedit-core') api project(':worldedit-libs:bukkit') - compile 'net.milkbowl.vault:VaultAPI:1.7' - 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' + testCompile 'org.mockito:mockito-core:1.9.0-rc1' + implementation('org.apache.logging.log4j:log4j-slf4j-impl:2.8.1'){transitive = false} + compile 'com.destroystokyo.paper:paper-api:1.14.3-R0.1-SNAPSHOT' + implementation('io.papermc:paperlib:1.0.2'){transitive = false} 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' - compile 'com.massivecraft:factions:2.8.0' - compile 'com.drtshock:factions:1.6.9.5' - compile 'com.factionsone:FactionsOne:1.2.2' - compile 'me.ryanhamshire:GriefPrevention:11.5.2' - compile 'com.massivecraft:mcore:7.0.1' - compile 'net.sacredlabyrinth.Phaed:PreciousStones:10.0.4-SNAPSHOT' - compile 'net.jzx7:regios:5.9.9' - compile 'com.bekvon.bukkit.residence:Residence:4.5._13.1' - compile 'com.palmergames.bukkit:towny:0.84.0.9' - compile 'com.thevoxelbox.voxelsniper:voxelsniper:5.171.0' - compile 'com.comphenix.protocol:ProtocolLib-API:4.4.0-SNAPSHOT' - compile 'com.wasteofplastic:askyblock:3.0.8.2' - compileOnly 'com.sk89q.worldguard:worldguard-core:7.0.0-20190215.210421-39' - compileOnly 'com.sk89q.worldguard:worldguard-legacy:7.0.0-20190215.210421-39' +// 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} + implementation('me.ryanhamshire:GriefPrevention:11.5.2'){transitive = false} + implementation('com.massivecraft:mcore:7.0.1'){transitive = false} + implementation('net.sacredlabyrinth.Phaed:PreciousStones:10.0.4-SNAPSHOT'){transitive = false} + implementation('net.jzx7:regios:5.9.9'){transitive = false} + implementation('com.bekvon.bukkit.residence:Residence:4.5._13.1'){transitive = false} + implementation('com.palmergames.bukkit:towny:0.84.0.9'){transitive = false} + implementation('com.thevoxelbox.voxelsniper:voxelsniper:5.171.0'){transitive = false} + implementation('com.comphenix.protocol:ProtocolLib-API:4.4.0-SNAPSHOT'){transitive = false} + implementation('com.wasteofplastic:askyblock:3.0.8.2'){transitive = false} } processResources { 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 7a785843d..35acd8310 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; @@ -30,6 +33,7 @@ import com.boydti.fawe.bukkit.v0.BukkitQueue_All; import com.boydti.fawe.bukkit.v0.ChunkListener_8; import com.boydti.fawe.bukkit.v0.ChunkListener_9; import com.boydti.fawe.bukkit.v1_13.BukkitQueue_1_13; +import com.boydti.fawe.bukkit.v1_14.BukkitQueue_1_14; import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.FaweCommand; @@ -43,6 +47,7 @@ import com.boydti.fawe.util.image.ImageViewer; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.world.World; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.command.PluginCommand; import org.bukkit.entity.Player; @@ -50,9 +55,11 @@ 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; +import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.FileOutputStream; @@ -150,6 +157,11 @@ public class FaweBukkit implements IFawe, Listener { // } // } + @Override + public QueueHandler getQueueHandler() { + return new BukkitQueueHandler(); + } + @Override public synchronized ImageViewer getImageViewer(FawePlayer fp) { if (listeningImages && imageListener == null) return null; @@ -575,6 +587,7 @@ public class FaweBukkit implements IFawe, Listener { } public enum Version { + v1_14_R1, v1_13_R2, NONE, } @@ -583,6 +596,8 @@ public class FaweBukkit implements IFawe, Listener { switch (getVersion()) { case v1_13_R2: return new BukkitQueue_1_13(world); + case v1_14_R1: + return new BukkitQueue_1_14(world); default: case NONE: return new BukkitQueue_All(world); @@ -593,6 +608,8 @@ public class FaweBukkit implements IFawe, Listener { switch (getVersion()) { case v1_13_R2: return new BukkitQueue_1_13(world); + case v1_14_R1: + return new BukkitQueue_1_14(world); default: case NONE: return new BukkitQueue_All(world); 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 d16684bcd..076d57d6f 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 @@ -102,16 +102,16 @@ public final class Spigot_v1_13_R2 extends CachedBukkitAdapter implements Bukkit nbtCreateTagMethod.setAccessible(true); } - public int[] idbToStateOrdinal; + public char[] idbToStateOrdinal; - private boolean init() { + private synchronized 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; } @@ -533,8 +533,18 @@ 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); + } + } + + public char adaptToChar(IBlockData ibd) { + try { + int id = Block.REGISTRY_ID.getId(ibd); + return idbToStateOrdinal[id]; + } catch (NullPointerException 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 new file mode 100644 index 000000000..3987e02de --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java @@ -0,0 +1,352 @@ +package com.boydti.fawe.bukkit.beta; + +import com.boydti.fawe.Fawe; +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IQueueExtent; +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.util.MemUtil; +import com.boydti.fawe.util.ReflectionUtils; +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.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_14_R1.block.CraftBlock; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.util.Collection; +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; + +public class BukkitChunkHolder> extends ChunkHolder { + @Override + public void init(final IQueueExtent extent, final int X, final int Z) { + super.init(extent, X, Z); + } + + @Override + public IChunkGet get() { + BukkitQueue extent = (BukkitQueue) getExtent(); + return new BukkitGetBlocks(extent.getNmsWorld(), getX(), getZ(), MemUtil.isMemoryFree()); + } + + 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.clone(); + } + if (get.sections[layer] != section) { + get.sections[layer] = section; + } + get.blocks[layer] = arr; + } + } + + @Override + public synchronized T call() { + try { + int X = getX(); + int Z = getZ(); + BukkitQueue extent = (BukkitQueue) getExtent(); + BukkitGetBlocks get = (BukkitGetBlocks) getOrCreateGet(); + IChunkSet set = getOrCreateSet(); + + 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; + if (!set.hasSection(layer)) { + continue; + } + if (set.getBlock(lx, ly, lz).getOrdinal() != 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; + + for (int layer = 0; layer < 16; layer++) { + if (!set.hasSection(layer)) continue; + + bitMask |= 1 << layer; + + char[] setArr = set.getArray(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 (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); + } + } + 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); + } + } + } + } + + // Biomes + BiomeType[] biomes = set.getBiomes(); + if (biomes != null) { + // set biomes + final BiomeBase[] currentBiomes = nmsChunk.getBiomeIndex(); + 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); + } + } + } + + Runnable[] syncTasks = null; + + net.minecraft.server.v1_14_R1.World nmsWorld = nmsChunk.getWorld(); + int bx = X << 4; + int bz = Z << 4; + + Set entityRemoves = set.getEntityRemoves(); + if (entityRemoves != null && !entityRemoves.isEmpty()) { + if (syncTasks == null) syncTasks = new Runnable[3]; + + 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 (entityRemoves.contains(entity.getUniqueID())) { + iter.remove(); + entity.b(false); + entity.die(); + entity.valid = false; + } + } + } + } + } + }; + } + + Set entities = set.getEntities(); + if (entities != null && !entities.isEmpty()) { + if (syncTasks == null) syncTasks = new Runnable[2]; + + syncTasks[1] = new Runnable() { + @Override + public void run() { + 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"); + 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 + Map tiles = set.getTiles(); + if (tiles != null && !tiles.isEmpty()) { + if (syncTasks == null) syncTasks = new Runnable[1]; + + 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); + } + } + } + } + }; + } + + 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); + }; + } + 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(); + } + } + if (callback == null) { + extent.returnToPool(BukkitChunkHolder.this); + return null; + } else { + return queueHandler.async(callback, null); + } + } + }; + return (T) (Future) queueHandler.sync(chain); + } else { + if (callback == null) { + extent.returnToPool(BukkitChunkHolder.this); + } else { + callback.run(); + } + } + } + return null; + } catch (Throwable e) { + e.printStackTrace(); + return null; + } + } +} \ No newline at end of file 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..da1506fd7 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java @@ -0,0 +1,208 @@ +package com.boydti.fawe.bukkit.beta; + +import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; +import com.boydti.fawe.bukkit.v1_14.BukkitQueue_1_14; +import com.boydti.fawe.bukkit.v1_14.adapter.Spigot_v1_14_R1; +import com.boydti.fawe.jnbt.anvil.BitArray4096; +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.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockTypes; +import net.minecraft.server.v1_14_R1.BiomeBase; +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 net.minecraft.server.v1_14_R1.WorldServer; +import org.bukkit.craftbukkit.v1_14_R1.block.CraftBlock; + +import java.util.Arrays; + +public class BukkitGetBlocks extends CharGetBlocks { + public ChunkSection[] sections; + public Chunk nmsChunk; + public World nmsWorld; + public int X, Z; + private boolean forceLoad; + + public BukkitGetBlocks(World nmsWorld, int X, int Z, boolean forceLoad) { + this.nmsWorld = nmsWorld; + this.X = X; + this.Z = Z; + if (forceLoad) { + ((WorldServer) nmsWorld).setForceLoaded(X, Z, this.forceLoad = true); + } + } + + @Override + protected void finalize() { + if (forceLoad) { + ((WorldServer) nmsWorld).setForceLoaded(X, Z, forceLoad = false); + } + } + + @Override + public BiomeType getBiomeType(int x, int z) { + BiomeBase base = getChunk().getBiomeIndex()[(z << 4) + x]; + return BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(base)); + } + + @Override + public CompoundTag getTag(int x, int y, int z) { + // TODO + return null; + } + + @Override + public char[] load(int layer) { + return load(layer, null); + } + + @Override + public synchronized 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]; + } + DelegateLock lock = BukkitQueue.applyLock(section); + synchronized (lock) { + lock.untilFree(); + lock.setModified(false); + // Efficiently convert ChunkSection to raw data + try { + 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); + + 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_14_R1) 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 { + final int size = num_palette; + if (size != 1) { + for (int i = 0; i < size; i++) { + char ordinal = ordinal(palette.a(i)); + paletteToBlockChars[i] = ordinal; + } + 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++) { + paletteToBlockChars[i] = Character.MAX_VALUE; + } + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + return data; + } + } + + private final char ordinal(IBlockData ibd) { + if (ibd == null) { + return BlockTypes.AIR.getDefaultState().getOrdinalChar(); + } else { + return ((Spigot_v1_14_R1) getAdapter()).adaptToChar(ibd); + } + } + + public ChunkSection[] getSections() { + ChunkSection[] tmp = sections; + if (tmp == null) { + synchronized (this) { + tmp = sections; + if (tmp == null) { + Chunk chunk = getChunk(); + sections = tmp = chunk.getSections().clone(); + } + } + } + return tmp; + } + + public Chunk getChunk() { + Chunk tmp = nmsChunk; + if (tmp == null) { + synchronized (this) { + tmp = nmsChunk; + if (tmp == null) { + nmsChunk = tmp = BukkitQueue.ensureLoaded(nmsWorld, 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 new file mode 100644 index 000000000..79b37e1eb --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java @@ -0,0 +1,369 @@ +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.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; +import net.jpountz.util.UnsafeUtils; +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.ChunkStatus; +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_14_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_14_R1.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.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.Supplier; + +import sun.misc.Unsafe; + +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() { +// return new BukkitFullChunk(); +// } +// }; + + @Override + public IChunk create(boolean full) { +// 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; + + private final static Field fieldDirtyCount; + private final static Field fieldDirtyBits; + + private static final int CHUNKSECTION_BASE; + private static final int CHUNKSECTION_SHIFT; + + private static final Field fieldLock; + + 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); + + fieldDirtyCount = PlayerChunk.class.getDeclaredField("dirtyCount"); + fieldDirtyCount.setAccessible(true); + fieldDirtyBits = PlayerChunk.class.getDeclaredField("h"); + fieldDirtyBits.setAccessible(true); + + { + 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"); + modifiersField.setAccessible(true); + 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); + 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) { + rethrow.printStackTrace(); + throw new RuntimeException(rethrow); + } + } + + 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); + } + return false; + } + + protected static DelegateLock applyLock(ChunkSection section) { + try { + synchronized (section) { + DataPaletteBlock blocks = section.getBlocks(); + Lock currentLock = (Lock) 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) { + return ensureLoaded(nmsWorld, X, Z); + } + + public static Chunk ensureLoaded(net.minecraft.server.v1_14_R1.World nmsWorld, int X, int Z) { + ChunkProviderServer provider = (ChunkProviderServer) nmsWorld.getChunkProvider(); + + + Chunk nmsChunk = (Chunk) provider.getChunkAt(X, Z, ChunkStatus.FEATURES, false);; + 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)); + } + + 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 + */ + + public static ChunkSection newChunkSection(final int layer, final char[] blocks) { + ChunkSection section = new ChunkSection(layer << 4); + 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/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/beta/DelegateLock.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/DelegateLock.java new file mode 100644 index 000000000..6d79d967e --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/DelegateLock.java @@ -0,0 +1,123 @@ +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 Lock parent; + private volatile boolean modified; + private final AtomicInteger count; + + public DelegateLock(Lock parent) { + this.parent = parent; + if (!(parent instanceof ReentrantLock)) { + count = new AtomicInteger(); + } else { + count = null; + } + } + + public boolean isModified() { + return modified; + } + + public void setModified(boolean modified) { + this.modified = modified; + } + + @Override + public synchronized void lock() { + modified = true; + parent.lock(); + if (count != null) { + count.incrementAndGet(); + } + } + + @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 void unlock() { + modified = true; + parent.unlock(); + if (count != null) { + if (count.getAndDecrement() <= 0) { + count.incrementAndGet(); + } + } + } + + public Lock getParent() { + return parent; + } + + @Override + public synchronized Condition newCondition() { + return parent.newCondition(); + } + + @Override + public synchronized int getHoldCount() { + throw new UnsupportedOperationException(); + } + + @Override + public synchronized boolean isHeldByCurrentThread() { + throw new UnsupportedOperationException(); + } + + @Override + public synchronized boolean 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) { + throw new UnsupportedOperationException(); + } + + @Override + public synchronized int getWaitQueueLength(Condition condition) { + throw new UnsupportedOperationException(); + } + + @Override + public synchronized String toString() { + return parent.toString(); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java index 3ea479f8e..325038d8e 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java @@ -220,34 +220,9 @@ public abstract class BukkitQueue_0 extends NMSMa } } - public static ConcurrentHashMap keepLoaded = new ConcurrentHashMap<>(8, 0.9f, 1); - - - @EventHandler - public static void onChunkLoad(ChunkLoadEvent event) { - Chunk chunk = event.getChunk(); - long pair = MathMan.pairInt(chunk.getX(), chunk.getZ()); - keepLoaded.putIfAbsent(pair, Fawe.get().getTimer().getTickStart()); - } - - @EventHandler - public static void onChunkUnload(ChunkUnloadEvent event) { - Chunk chunk = event.getChunk(); - long pair = MathMan.pairInt(chunk.getX(), chunk.getZ()); - Long lastLoad = keepLoaded.get(pair); - if (lastLoad != null) { - if (Fawe.get().getTimer().getTickStart() - lastLoad < 10000) { - event.setCancelled(true); - } else { - keepLoaded.remove(pair); - } - } - } - @Override public boolean queueChunkLoad(int cx, int cz) { if (super.queueChunkLoad(cx, cz)) { - keepLoaded.put(MathMan.pairInt(cx, cz), System.currentTimeMillis()); return true; } return false; @@ -282,7 +257,6 @@ public abstract class BukkitQueue_0 extends NMSMa @Override public boolean regenerateChunk(World world, int x, int z, BiomeType biome, Long seed) { - if (!keepLoaded.isEmpty()) keepLoaded.remove(MathMan.pairInt(x, z)); return world.regenerateChunk(x, z); } 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 b027a7008..863345ec4 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 @@ -233,19 +233,11 @@ public class BukkitQueue_All extends BukkitQueue_0 { } return this; } -} +} \ No newline at end of file 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 39a82d01a..05c0609e0 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 @@ -40,7 +40,7 @@ import java.util.concurrent.atomic.LongAdder; public class BukkitQueue_1_13 extends BukkitQueue_0 { - protected final static Field fieldBits; + final static Field fieldBits; final static Field fieldPalette; final static Field fieldSize; @@ -604,83 +604,82 @@ public class BukkitQueue_1_13 extends BukkitQueue_0> 6; - if (num_palette == 1) { - for (int i = 0; i < blockBitArrayEnd; i++) blockstates[i] = 0; - } else { - BitArray4096 bitArray = new BitArray4096(blockstates, bitsPerEntry); - bitArray.fromRaw(blocksCopy); - } - - // set palette & data bits - 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 = new DataPaletteLinear<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::d); - - // set palette - for (int i = 0; i < num_palette; i++) { - int ordinal = paletteToBlock[i]; - blockToPalette[ordinal] = Integer.MAX_VALUE; - BlockState state = BlockTypes.states[ordinal]; - 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 (IllegalAccessException | NoSuchFieldException e) { - throw new RuntimeException(e); - } - - return section; - } catch (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 + } + + 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); + bitArray.fromRaw(blocksCopy); + } + + // set palette & data bits + 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 = new DataPaletteLinear<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::d); + + // set palette + for (int i = 0; i < num_palette; i++) { + int ordinal = paletteToBlock[i]; + blockToPalette[ordinal] = Integer.MAX_VALUE; + BlockState state = BlockTypes.states[ordinal]; + 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 (IllegalAccessException | NoSuchFieldException e) { + throw new RuntimeException(e); + } + + return section; + } catch (Throwable e){ + Arrays.fill(blockToPalette, Integer.MAX_VALUE); + throw e; } } @@ -719,4 +718,4 @@ public class BukkitQueue_1_13 extends BukkitQueue_0() { + @Override + public void run(Boolean value) { + this.value = parent.unloadChunkRequest(x, z); + } + }); + } + return true; + } + @Override public boolean regenerateChunk(final int x, final int z) { return TaskManager.IMP.sync(new RunnableVal() { diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncDataContainer.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncDataContainer.java new file mode 100644 index 000000000..f5807c7f4 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncDataContainer.java @@ -0,0 +1,114 @@ +package com.boydti.fawe.bukkit.wrapper.state; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Objects; +import java.util.Map.Entry; + +import com.boydti.fawe.FaweCache; +import com.boydti.fawe.util.ReflectionUtils; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.Tag; +import net.minecraft.server.v1_14_R1.NBTBase; +import net.minecraft.server.v1_14_R1.NBTTagCompound; +import org.apache.commons.lang.Validate; +import org.bukkit.NamespacedKey; +import org.bukkit.craftbukkit.v1_14_R1.persistence.CraftPersistentDataAdapterContext; +import org.bukkit.craftbukkit.v1_14_R1.persistence.CraftPersistentDataTypeRegistry; +import org.bukkit.persistence.PersistentDataAdapterContext; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; + +public final class AsyncDataContainer implements PersistentDataContainer { + private final CompoundTag root; + + public AsyncDataContainer(CompoundTag root) { + this.root = root; + } + + private CompoundTag root() { + CompoundTag value = (CompoundTag) root.getValue().get("PublicBukkitValues"); + return value; + } + + private Map get() { + return get(true); + } + + private Map get(boolean create) { + CompoundTag tag = root(); + Map raw; + if (tag == null) { + if (!create) return Collections.emptyMap(); + Map map = ReflectionUtils.getMap(root.getValue()); + map.put("PublicBukkitValues", new CompoundTag(raw = new HashMap<>())); + } else { + raw = ReflectionUtils.getMap(tag.getValue()); + } + return raw; + } + + public void set(NamespacedKey key, PersistentDataType type, Z value) { + Validate.notNull(key, "The provided key for the custom value was null"); + Validate.notNull(type, "The provided type for the custom value was null"); + Validate.notNull(value, "The provided value for the custom value was null"); + get().put(key.toString(), FaweCache.asTag(type.toPrimitive(value, null))); + } + + public boolean has(NamespacedKey key, PersistentDataType type) { + Validate.notNull(key, "The provided key for the custom value was null"); + Validate.notNull(type, "The provided type for the custom value was null"); + Tag value = get(false).get(key.toString()); + if (value == null) return type == null; + return type.getPrimitiveType() == value.getValue().getClass(); + } + + public Z get(NamespacedKey key, PersistentDataType type) { + Validate.notNull(key, "The provided key for the custom value was null"); + Validate.notNull(type, "The provided type for the custom value was null"); + Tag value = get(false).get(key.toString()); + return (Z) value.toRaw(); + } + + public Z getOrDefault(NamespacedKey key, PersistentDataType type, Z defaultValue) { + Z z = this.get(key, type); + return z != null ? z : defaultValue; + } + + public void remove(NamespacedKey key) { + Validate.notNull(key, "The provided key for the custom value was null"); + get(false).remove(key.toString()); + } + + public boolean isEmpty() { + return get(false).isEmpty(); + } + + public PersistentDataAdapterContext getAdapterContext() { + return null; + } + + public boolean equals(Object obj) { + if (!(obj instanceof AsyncDataContainer)) { + return false; + } else { + Map myRawMap = this.getRaw(); + Map theirRawMap = ((AsyncDataContainer)obj).getRaw(); + return Objects.equals(myRawMap, theirRawMap); + } + } + + public Map getRaw() { + return get(false); + } + + public int hashCode() { + return get(false).hashCode(); + } + + public Map serialize() { + return new CompoundTag(get(false)).toRaw(); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncSign.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncSign.java index 1dfb8ab9d..9525f601f 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncSign.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncSign.java @@ -8,7 +8,13 @@ import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import java.util.Map; + +import net.minecraft.server.v1_14_R1.TileEntitySign; +import org.bukkit.DyeColor; import org.bukkit.block.Sign; +import org.bukkit.persistence.PersistentDataContainer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class AsyncSign extends AsyncBlockState implements Sign { public AsyncSign(AsyncBlock block, int combined) { @@ -63,4 +69,28 @@ public class AsyncSign extends AsyncBlockState implements Sign { public void setEditable(boolean arg0) { this.isEditable = arg0; } + + @Override + public @NotNull PersistentDataContainer getPersistentDataContainer() { + return new AsyncDataContainer(getNbtData()); + } + + @Override + public @Nullable DyeColor getColor() { + CompoundTag nbt = getNbtData(); + if (nbt != null) { + String color = nbt.getString("Color").toUpperCase(); + if (color != null) return DyeColor.valueOf(color); + } + return DyeColor.BLACK; + } + + @Override + public void setColor(DyeColor color) { + CompoundTag nbt = getNbtData(); + if (nbt != null) { + Map map = ReflectionUtils.getMap(nbt.getValue()); + map.put("Color", new StringTag(color.name().toLowerCase())); + } + } } 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..4191c424b 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 @@ -438,11 +438,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-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java index 15b79a4d9..238f19325 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 @@ -23,7 +23,7 @@ import com.bekvon.bukkit.residence.commands.message; import com.bekvon.bukkit.residence.containers.cmd; 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.v1_14.adapter.Spigot_v1_14_R1; import com.boydti.fawe.util.MainUtil; import com.google.common.base.Joiner; @@ -322,7 +322,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-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1$1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1$1.class deleted file mode 100644 index efa78dacc..000000000 Binary files a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1$1.class and /dev/null differ diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1.class deleted file mode 100644 index 9655a35a6..000000000 Binary files a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1.class and /dev/null differ diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2$1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2$1.class deleted file mode 100644 index 97a809b53..000000000 Binary files a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2$1.class and /dev/null differ diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2_2$1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2_2$1.class deleted file mode 100644 index e294143a7..000000000 Binary files a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2_2$1.class and /dev/null differ diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2_2.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2_2.class deleted file mode 100644 index 5377fe96c..000000000 Binary files a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2_2.class and /dev/null differ 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/Fawe.java b/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java index fb751c22b..f36c8e522 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; @@ -30,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 *

@@ -81,6 +82,8 @@ public class Fawe { private DefaultTransformParser transformParser; private ChatManager chatManager = new PlainChatManager(); + private QueueHandler queueHandler; + /** * Get the implementation specific class * @@ -183,6 +186,17 @@ public class Fawe { public void onDisable() { } + public QueueHandler getQueueHandler() { + if (queueHandler == null) { + synchronized (this) { + if (queueHandler == null) { + queueHandler = IMP.getQueueHandler(); + } + } + } + return queueHandler; + } + public ChatManager getChatManager() { return chatManager; } 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..f570ffd80 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/FaweAPI.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/FaweAPI.java @@ -8,6 +8,7 @@ import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.RegionWrapper; import com.boydti.fawe.object.changeset.DiskStorageHistory; +import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.object.schematic.Schematic; import com.boydti.fawe.regions.FaweMaskManager; import com.boydti.fawe.util.EditSessionBuilder; @@ -262,7 +263,7 @@ public class FaweAPI { */ public static void cancelEdit(Extent extent, BBC reason) { try { - WEManager.IMP.cancelEdit(extent, reason); + WEManager.IMP.cancelEdit(extent, new FaweException(reason)); } catch (WorldEditException ignore) { } } 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..fa24ab1dd 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,47 @@ 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; 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; 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]; + + /* + Palette buffers / cache + */ + + @Override + public boolean trim(boolean aggressive) { + BLOCK_TO_PALETTE.clean(); + PALETTE_TO_BLOCK.clean(); + BLOCK_STATES.clean(); + SECTION_BLOCKS.clean(); + PALETTE_CACHE.clean(); + PALETTE_TO_BLOCK_CHAR.clean(); + + MUTABLE_VECTOR3.clean(); + MUTABLE_BLOCKVECTOR3.clean(); + return false; + } -public class FaweCache { public static final IterableThreadLocal BLOCK_TO_PALETTE = new IterableThreadLocal() { @Override public int[] init() { @@ -21,7 +54,16 @@ public class FaweCache { 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; } }; @@ -39,6 +81,141 @@ public class FaweCache { } }; + /** + * 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 + */ + 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 layerOffset + * @param blocks + * @return palette + */ + public static Palette toPalette(int layerOffset, char[] blocks) { + return toPalette(layerOffset, null, blocks); + } + + /** + * Convert raw int array to palette + * @param layerOffset + * @param blocks + * @return palette + */ + public static Palette toPalette(int layerOffset, int[] blocks) { + return toPalette(layerOffset, blocks, null); + } + + 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 = layerOffset << 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; + } + } + + /* + * 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 + */ public static Map asMap(Object... pairs) { HashMap map = new HashMap<>(pairs.length >> 1); for (int i = 0; i < pairs.length; i += 2) { @@ -179,4 +356,16 @@ public class FaweCache { 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/IFawe.java b/worldedit-core/src/main/java/com/boydti/fawe/IFawe.java index 304d9d1cb..1f7310186 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; @@ -57,4 +58,6 @@ public interface IFawe { return ""; } + QueueHandler getQueueHandler(); + } 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..8e29eecd2 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/ArrayFilterBlock.java @@ -0,0 +1,89 @@ +package com.boydti.fawe.beta; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.Extent; +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 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 setBlock(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 getBlock() { + return BlockTypes.states[ordinal]; + } + + @Override + public BaseBlock getFullBlock() { + return getBlock().toBaseBlock(); + } + + @Override + public CompoundTag getNbtData() { + return null; + } + + @Override + public void setNbtData(@Nullable CompoundTag nbtData) {} + + @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 new file mode 100644 index 000000000..b1d6589c9 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java @@ -0,0 +1,418 @@ +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.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; +import com.sk89q.worldedit.world.registry.BlockMaterial; + +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; + private @Nullable char[] setArr; + private SetDelegate delegate; + + // local + private int layer, index, x, y, z, xx, yy, zz, X, Z; + + public CharFilterBlock(IQueueExtent queueExtent) { + super(queueExtent); + } + + @Override + public final ChunkFilterBlock init(final int X, final int Z, final IChunkGet chunk) { + this.get = (CharGetBlocks) chunk; + this.X = X; + this.Z = Z; + this.xx = X << 4; + this.zz = Z << 4; + return this; + } + + 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) != null) { + 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); + } + } + } + } + + @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 null; + 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; + return this; + } + + @Override + 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); + } + } + } + } + + @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++) { + int absZ = zz + z; + for (x = 0; x < 16; x++, index++) { + int absX = xx + x; + if (region.contains(absX, absY, absZ)) { + filter.applyBlock(this); + } + } + } + } + } + + @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++) { + filter.applyBlock(this); + } + } + } + } + + @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 setBlock(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; + } + + @Override + public final int getY() { + return yy + y; + } + + @Override + public final int getZ() { + return zz + z; + } + + @Override + public final int getLocalX() { + return x; + } + + @Override + public final int getLocalY() { + return y; + } + + @Override + public final int getLocalZ() { + return z; + } + + @Override + public final int getChunkX() { + return X; + } + + @Override + public final int getChunkZ() { + return Z; + } + + public final char getOrdinalChar() { + return getArr[index]; + } + + @Override + public final int getOrdinal() { + return getArr[index]; + } + + @Override + public final BlockState getBlock() { + final int ordinal = getArr[index]; + return BlockTypes.states[ordinal]; + } + + @Override + public final BaseBlock getFullBlock() { + final BlockState state = getBlock(); + final BlockMaterial material = state.getMaterial(); + if (material.hasContainer()) { + final CompoundTag tag = get.getTag(x, y + yy, z); + return state.toBaseBlock(tag); + } + return state.toBaseBlock(); + } + + @Override + public final CompoundTag getNbtData() { + return get.getTag(x, y + (layer << 4), z); + } + + @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]]; + } + if (layer > 0) { + final int newLayer = layer - 1; + final CharGetBlocks chunk = this.get; + return states[chunk.sections[newLayer].get(chunk, newLayer, index + 3840)]; + } + return BlockTypes.__RESERVED__.getDefaultState(); + } + + @Override + public final BlockState getBlockAbove() { + if (y < 16) { + return states[getArr[index + 256]]; + } + if (layer < 16) { + final int newLayer = layer + 1; + final CharGetBlocks chunk = this.get; + return states[chunk.sections[newLayer].get(chunk, newLayer, index - 3840)]; + } + return BlockTypes.__RESERVED__.getDefaultState(); + } + + @Override + public final BlockState getBlockRelativeY(final int y) { + final int newY = this.y + y; + final int layerAdd = newY >> 4; + switch (layerAdd) { + case 0: + return states[getArr[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: { + final int newLayer = layer + layerAdd; + if (newLayer < 16) { + final int index = this.index + ((y & 15) << 8); + 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 = this.index + ((y & 15) << 8); + return states[get.sections[newLayer].get(get, newLayer, index)]; + } + break; + } + } + return BlockTypes.__RESERVED__.getDefaultState(); + } + + /* + Extent + */ + @Override + public char getOrdinalChar(Extent orDefault) { + return getOrdinalChar(); + } + + /* + Set delegate + */ + private SetDelegate initSet() { + setArr = set.getArray(layer); + return delegate = FULL; + } + + @Override + public BiomeType getBiomeType(int x, int z) { + if ((x >> 4) == X && (z >> 4) == Z) { + return get.getBiomeType(x & 15, z & 15); + } + return getExtent().getBiomeType(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, y, z & 15, biome); + } + return getExtent().setBiome(x, y, z, biome); + } + + 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/ChunkFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFilterBlock.java new file mode 100644 index 000000000..bc1957f51 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFilterBlock.java @@ -0,0 +1,30 @@ +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 SimpleFilterBlock { + public ChunkFilterBlock(Extent extent) { + super(extent); + } + + 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(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/ChunkFuture.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFuture.java new file mode 100644 index 000000000..264eb4509 --- /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(final IChunk chunk) { + this.chunk = chunk; + } + + public IChunk getChunk() { + return chunk; + } + + @Override + public boolean cancel(final 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(final long timeout, final 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/DelegateFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilter.java new file mode 100644 index 000000000..5bc48aa80 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilter.java @@ -0,0 +1,13 @@ +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; + } +} 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..1dab05925 --- /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 getBiomeType(int x, int z) { + return parent.getBiomeType(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/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/Filter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java new file mode 100644 index 000000000..2f19852c3 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java @@ -0,0 +1,70 @@ +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 + */ +public interface Filter { + /** + * Check whether a chunk should be read + * + * @param cx + * @param cz + * @return + */ + default boolean appliesChunk(final int cx, final 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 + */ + default IChunk applyChunk(final IChunk chunk, @Nullable Region region) { + return chunk; + } + + default boolean appliesLayer(IChunk chunk, int layer) { + return true; + } + + /** + * Make changes to the block here
+ * - e.g. block.setId(...)
+ * - Note: Performance is critical here
+ * + * @param block + */ + default void applyBlock(final FilterBlock block) { + } + + /** + * Do something with the IChunk after block filtering
+ * + * @param chunk + * @return + */ + 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; + } + + 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 new file mode 100644 index 000000000..ed2a84be4 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java @@ -0,0 +1,169 @@ +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.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; + +import javax.annotation.Nullable; + +import static com.sk89q.worldedit.world.block.BlockTypes.states; + +public abstract class FilterBlock extends BlockVector3 implements Extent, TileEntityBlock { + public abstract Extent getExtent(); + + public abstract void setOrdinal(int ordinal); + + 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 getBlock(); + + public abstract BaseBlock getFullBlock(); + + public abstract CompoundTag getNbtData(); + + public abstract void setNbtData(@Nullable CompoundTag nbtData); + + public boolean hasNbtData() { + return getNbtData() != null; + } + + @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 getExtent().getBlock(x, y, z); + } + + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + return getExtent().getFullBlock(x, y, z); + } + + public BlockState getBlockBelow() { + return getBlock(getX(), getY() - 1, getZ()); + } + + public BlockState getBlockAbove() { + return getBlock(getX(), getY() + 1, getZ()); + } + + public BlockState getBlockNorth() { + return getBlock(getX(), getY(), getZ() - 1); + } + + public BlockState getBlockEast() { + return getBlock(getX() + 1, getY(), 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 + public abstract int getX(); + + @Override + public abstract int getY(); + + @Override + public abstract int getZ(); + + public int getLocalX() { + return getX() & 15; + } + + public int getLocalY() { + return getY() & 15; + } + + public int getLocalZ() { + return getZ() & 15; + } + + public int getChunkX() { + return getX() >> 4; + } + + 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/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..602da196b --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/Flood.java @@ -0,0 +1,193 @@ +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 + TODO + } + } + + 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/IBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IBlocks.java new file mode 100644 index 000000000..fce4a574d --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IBlocks.java @@ -0,0 +1,10 @@ +package com.boydti.fawe.beta; + +/** + * Shared interface for IGetBlocks and ISetBlocks + */ +public interface IBlocks extends Trimable { + boolean hasSection(int layer); + + 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 new file mode 100644 index 000000000..26be59e53 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java @@ -0,0 +1,89 @@ +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; + +/** + * Represents a chunk in the queue {@link IQueueExtent} + * Used for getting and setting blocks / biomes / entities + */ +public interface IChunk> extends Trimable, Callable { + /** + * Initialize at the location + * @param extent + * @param X + * @param Z + */ + void init(IQueueExtent extent, int X, int Z); + + int getX(); + + int getZ(); + + /** + * If the chunk is a delegate, returns it's paren'ts root + * @return root IChunk + */ + default IChunk getRoot() { + return this; + } + + /** + * @return true if no changes are queued for this chunk + */ + boolean isEmpty(); + + /** + * 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 + */ + 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; + } + + /** + * 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 filterBlocks(Filter filter, ChunkFilterBlock block, @Nullable Region region); + + void flood(Flood flood, FilterBlockMask mask, ChunkFilterBlock block); + + /* set - queues a change */ + boolean setBiome(int x, int y, int z, BiomeType biome); + + boolean setBlock(int x, int y, int z, BlockStateHolder block); + + /* 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/IChunkGet.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkGet.java new file mode 100644 index 000000000..a76894912 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkGet.java @@ -0,0 +1,30 @@ +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; + +/** + * Interface for getting blocks + */ +public interface IChunkGet extends IBlocks, Trimable, InputExtent { + @Override + BaseBlock getFullBlock(int x, int y, int z); + + @Override + BiomeType getBiomeType(int x, int z); + + @Override + BlockState getBlock(int x, int y, int z); + + CompoundTag getTag(int x, int y, int z); + + @Override + boolean trim(boolean aggressive); + + default void optimize() { + + } +} 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 new file mode 100644 index 000000000..35efd352a --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkSet.java @@ -0,0 +1,51 @@ +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.Map; +import java.util.Set; +import java.util.UUID; + +/** + * Interface for setting blocks + */ +public interface IChunkSet extends IBlocks, OutputExtent { + boolean setBiome(int x, int y, int z, BiomeType biome); + + boolean setBlock(int x, int y, int z, BlockStateHolder holder); + + boolean isEmpty(); + + void setTile(int x, int y, int z, CompoundTag tile); + + void setEntity(CompoundTag tag); + + void removeEntity(UUID uuid); + + BlockState getBlock(int x, int y, int z); + + char[] getArray(int layer); + + BiomeType[] getBiomes(); + + Map getTiles(); + + Set getEntities(); + + Set getEntityRemoves(); + + @Override + IChunkSet 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 new file mode 100644 index 000000000..e36529fc8 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java @@ -0,0 +1,109 @@ +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; + +/** + * Delegate for IChunk + * @param parent class + */ +public interface IDelegateChunk extends IChunk { + U getParent(); + + default IChunk getRoot() { + IChunk root = getParent(); + while (root instanceof IDelegateChunk) { + root = ((IDelegateChunk) root).getParent(); + } + return root; + } + + @Override + default void flood(Flood flood, FilterBlockMask mask, ChunkFilterBlock 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); + } + + @Override + 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(final int x, final int z) { + return getParent().getBiome(x, z); + } + + @Override + default BlockState getBlock(final int x, final int y, final int z) { + return getParent().getBlock(x, y, z); + } + + @Override + default BaseBlock getFullBlock(final int x, final int y, final int z) { + return getParent().getFullBlock(x, y, z); + } + + @Override + default void init(final IQueueExtent extent, final int X, final int Z) { + getParent().init(extent, X, Z); + } + + @Override + default int getX() { + return getParent().getX(); + } + + @Override + default int getZ() { + return getParent().getZ(); + } + + + @Override + default boolean trim(final boolean aggressive) { + return getParent().trim(aggressive); + } + + @Override + default Future call() { + return getParent().call(); + } + + @Override + default void join() throws ExecutionException, InterruptedException { + getParent().join(); + } + + @Override + default void filterBlocks(Filter filter, ChunkFilterBlock block, @Nullable Region region) { + getParent().filterBlocks(filter, block, region); + } + + @Override + default boolean isEmpty() { + return getParent().isEmpty(); + } + + default T findParent(final Class clazz) { + IChunk root = getParent(); + if (clazz.isAssignableFrom(root.getClass())) return (T) root; + while (root instanceof IDelegateChunk) { + root = ((IDelegateChunk) root).getParent(); + if (clazz.isAssignableFrom(root.getClass())) return (T) root; + } + return null; + } +} 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..e85587e59 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateFilter.java @@ -0,0 +1,50 @@ +package com.boydti.fawe.beta; + +import com.sk89q.worldedit.regions.Region; + +import javax.annotation.Nullable; + +public interface IDelegateFilter extends Filter { + Filter getParent(); + + @Override + default boolean appliesChunk(int cx, int cz) { + return getParent().appliesChunk(cx, cz); + } + + @Override + default IChunk applyChunk(IChunk chunk, @Nullable Region region) { + return getParent().applyChunk(chunk, region); + } + + @Override + default boolean appliesLayer(IChunk chunk, int layer) { + return getParent().appliesLayer(chunk, layer); + } + + @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() { + 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/IDelegateQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateQueueExtent.java new file mode 100644 index 000000000..f05a1b2e5 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateQueueExtent.java @@ -0,0 +1,47 @@ +package com.boydti.fawe.beta; + +import com.boydti.fawe.beta.implementation.WorldChunkCache; + +import java.util.concurrent.Future; + +/** + * Delegate for IQueueExtent + */ +public interface IDelegateQueueExtent extends IQueueExtent { + IQueueExtent getParent(); + + @Override + default void init(final WorldChunkCache cache) { + getParent().init(cache); + } + + @Override + default IChunk getCachedChunk(final int X, final int Z) { + return getParent().getCachedChunk(X, Z); + } + + @Override + default Future submit(final IChunk chunk) { + return getParent().submit(chunk); + } + + @Override + default IChunk create(final boolean full) { + return getParent().create(full); + } + + @Override + default IChunk wrap(final IChunk root) { + return getParent().wrap(root); + } + + @Override + default void flush() { + getParent().flush(); + } + + @Override + default boolean trim(final boolean aggressive) { + return getParent().trim(aggressive); + } +} 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..633dad3a8 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java @@ -0,0 +1,103 @@ +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; + +import java.io.Flushable; +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, Extent { + 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 + * @param Z + * @return IChunk + */ + IChunk getCachedChunk(int X, int Z); + + /** + * Submit the chunk so that it's changes are applied to the world + * @param chunk + * @return result + */ + > 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); + 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); + } + + @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
+ * - 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 / limits etc.) + * @param root + * @return wrapped chunk + */ + default IChunk wrap(final IChunk root) { + return root; + } + + /** + * Flush all changes to the world + * - Best to call this async so it doesn't hang the server + */ + @Override + void flush(); + + ChunkFilterBlock initFilterBlock(); +} \ No newline at end of file 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..94279a6aa --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/NorthVector.java @@ -0,0 +1,92 @@ +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.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 new file mode 100644 index 000000000..b8d865aec --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/SimpleFilterBlock.java @@ -0,0 +1,16 @@ +package com.boydti.fawe.beta; + +import com.sk89q.worldedit.extent.Extent; + +public abstract class SimpleFilterBlock extends FilterBlock { + private final Extent extent; + + public SimpleFilterBlock(Extent extent) { + this.extent = extent; + } + + @Override + 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..39a2c04a0 --- /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/Trimable.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/Trimable.java new file mode 100644 index 000000000..34efe59ae --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/Trimable.java @@ -0,0 +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/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/filters/CountFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/CountFilter.java new file mode 100644 index 000000000..988b60161 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/CountFilter.java @@ -0,0 +1,68 @@ +package com.boydti.fawe.beta.filters; + +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 extends ForkedFilter { + private final int[] counter = new int[BlockTypes.states.length]; + + public CountFilter() { + super(null); + } + + private CountFilter(CountFilter root) { + super(root); + } + + @Override + 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()]++; + } + + public List> getDistribution() { + final List> distribution = new ArrayList<>(); + for (int i = 0; i < counter.length; i++) { + final int count = counter[i]; + if (count != 0) { + distribution.add(new Countable<>(BlockTypes.states[i], count)); + } + } + Collections.sort(distribution); + return distribution; + } + + 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); + actor.print(BBC.getPrefix() + str); + } + } +} 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/filters/SetFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/SetFilter.java new file mode 100644 index 000000000..841defd43 --- /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.setBlock(state); + } +} 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/QueueHandler.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java new file mode 100644 index 000000000..665f4043f --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java @@ -0,0 +1,203 @@ +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.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.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; + +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.Callable; +import java.util.concurrent.ConcurrentLinkedQueue; +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; + +/** + * Class which handles all the queues {@link IQueueExtent} + */ +public abstract class QueueHandler implements Trimable, Runnable { + private ForkJoinPool forkJoinPoolPrimary = new ForkJoinPool(); + private ForkJoinPool forkJoinPoolSecondary = new ForkJoinPool(); + private ThreadPoolExecutor blockingExecutor = FaweCache.newBlockingExecutor(); + private ConcurrentLinkedQueue syncTasks = new ConcurrentLinkedQueue(); + + private Map> chunkCache = new HashMap<>(); + private IterableThreadLocal queuePool = new IterableThreadLocal() { + @Override + public IQueueExtent init() { + return create(); + } + }; + + 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(final Callable call) { + return forkJoinPoolSecondary.submit(call); + } + + public Future sync(final Runnable run, final T value) { + final FutureTask result = new FutureTask<>(run, value); + syncTasks.add(result); + return result; + } + + public Future sync(final Runnable run) { + final FutureTask result = new FutureTask<>(run, null); + syncTasks.add(result); + return result; + } + + public Future sync(final Callable call) { + final FutureTask result = new FutureTask<>(call); + syncTasks.add(result); + return result; + } + + public > T submit(final IChunk chunk) { + if (MemUtil.isMemoryFree()) { +// return (T) forkJoinPoolSecondary.submit(chunk); + } + return (T) blockingExecutor.submit(chunk); + } + + /** + * 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) { + 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 IQueueExtent getQueue(final World world) { + final IQueueExtent queue = queuePool.get(); + queue.init(getOrCreate(world)); + return queue; + } + + @Override + 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 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 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] = forkJoinPoolPrimary.submit(new Runnable() { + @Override + public void run() { + final Filter newFilter = filter.fork(); + // Create a chunk that we will reuse/reset for each operation + final IQueueExtent queue = getQueue(world); + synchronized (queue) { + ChunkFilterBlock block = null; + + while (true) { + // Get the next chunk posWeakChunk + final int X, Z; + synchronized (chunksIter) { + if (!chunksIter.hasNext()) break; + final BlockVector2 pos = chunksIter.next(); + X = pos.getX(); + Z = pos.getZ(); + } + if (!newFilter.appliesChunk(X, Z)) { + continue; + } + IChunk chunk = queue.getCachedChunk(X, Z); + // Initialize + chunk.init(queue, X, Z); + + IChunk newChunk = newFilter.applyChunk(chunk, region); + if (newChunk != null) { + chunk = newChunk; + if (block == null) block = queue.initFilterBlock(); + chunk.filterBlocks(newFilter, block, region); + } + queue.submit(chunk); + } + queue.flush(); + } + } + }); + } + // Join filters + for (int i = 0; i < tasks.length; i++) { + final ForkJoinTask task = tasks[i]; + if (task != null) { + task.quietlyJoin(); + } + } + filter.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..b341c7021 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java @@ -0,0 +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 ChunkFilterBlock initFilterBlock() { + return new CharFilterBlock(this); + } +} 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..661868e8f --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SingleThreadQueueExtent.java @@ -0,0 +1,252 @@ +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; +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; + +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +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; + private ConcurrentLinkedQueue submissions = new ConcurrentLinkedQueue<>(); + + /** + * 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"); + } + } + + @Override + public WorldChunkCache getCache() { + return cache; + } + + /** + * Reset the queue + */ + protected synchronized void reset() { + checkThread(); + cache = null; + if (!chunks.isEmpty()) { + CHUNK_POOL.addAll(chunks.values()); + chunks.clear(); + } + lastChunk = null; + lastPair = Long.MAX_VALUE; + currentThread = null; + } + + /** + * Initialize the queue + * @param cache + */ + @Override + public synchronized void init(final WorldChunkCache cache) { + if (this.cache != null) { + reset(); + } + currentThread = Thread.currentThread(); + checkNotNull(cache); + 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<>(); + // Pool discarded chunks for reuse (can safely be cleared by another thread) + private static final ConcurrentLinkedQueue CHUNK_POOL = new ConcurrentLinkedQueue<>(); + + 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); + } + + if (Fawe.isMainThread()) { + return chunk.call(); + } + + return Fawe.get().getQueueHandler().submit(chunk); + } + + @Override + public synchronized boolean trim(final boolean aggressive) { + // TODO trim individial chunk sections + CHUNK_POOL.clear(); + if (Thread.currentThread() == currentThread) { + lastChunk = null; + 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; + } + } + + /** + * 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 = (((long) X) << 32) | (Z & 0xffffffffL); + 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(); + final boolean lowMem = MemUtil.isMemoryLimited(); + if (lowMem || size > Settings.IMP.QUEUE.TARGET_SIZE) { + chunk = chunks.removeFirst(); + final Future future = submitUnchecked(chunk); + if (future != null && !future.isDone()) { + final 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); + chunk = wrap(chunk); + + chunks.put(pair, chunk); + lastPair = pair; + lastChunk = chunk; + + return chunk; + } + + 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 (final 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 (final InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + } else { + return; + } + } + submissions.poll(); + } + } + } + + @Override + public synchronized void flush() { + checkThread(); + if (!chunks.isEmpty()) { + if (MemUtil.isMemoryLimited()) { + 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); + } + } + } else { + for (final IChunk chunk : chunks.values()) { + final Future future = submitUnchecked(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/WorldChunkCache.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/WorldChunkCache.java new file mode 100644 index 000000000..243bc23c5 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/WorldChunkCache.java @@ -0,0 +1,72 @@ +package com.boydti.fawe.beta.implementation; + +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; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +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; + + protected WorldChunkCache(final World world) { + this.world = world; + this.getCache = new Long2ObjectLinkedOpenHashMap<>(); + } + + public World getWorld() { + return world; + } + + public synchronized int size() { + 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 IChunkGet get(final long index, final Supplier provider) { + final WeakReference ref = getCache.get(index); + if (ref != null) { + final IChunkGet blocks = ref.get(); + if (blocks != null) return blocks; + } + final IChunkGet 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 IChunkGet igb = value.get(); + if (igb == null) iter.remove(); + else { + result = false; + if (!aggressive) return result; + synchronized (igb) { + igb.trim(aggressive); + } + } + } + } + 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..1c50695f2 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java @@ -0,0 +1,114 @@ +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; + 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]; + 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] == EMPTY) { + blocks[i] = null; + } else { + result = false; + } + } + return result; + } + + @Override + public IChunkSet reset() { + for (int i = 0; i < 16; i++) sections[i] = EMPTY; + return null; + } + + public void reset(final int layer) { + sections[layer] = EMPTY; + } + + public char[] load(final int layer) { + return new char[4096]; + } + + 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(final int layer) { + return sections[layer] == FULL; + } + + 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 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); + } + + /* + Section + */ + + public static abstract class Section { + public abstract char[] get(CharBlocks blocks, int layer); + + public final char get(final CharBlocks blocks, final int layer, final int index) { + return get(blocks, layer)[index]; + } + + 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 EMPTY = new Section() { + @Override + public final char[] get(final CharBlocks blocks, final 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(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 new file mode 100644 index 000000000..7c5dcf613 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java @@ -0,0 +1,34 @@ +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; + +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(); + } + + @Override + public BlockState getBlock(final int x, final int y, final int z) { + return BlockTypes.states[get(x, y, z)]; + } + + @Override + public boolean trim(final boolean aggressive) { + for (int i = 0; i < 16; i++) { + sections[i] = EMPTY; + blocks[i] = null; + } + return true; + } + + @Override + 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 new file mode 100644 index 000000000..23db45a27 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java @@ -0,0 +1,124 @@ +package com.boydti.fawe.beta.implementation.blocks; + +import com.boydti.fawe.beta.IChunkSet; +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 IChunkSet { + public BiomeType[] biomes; + public HashMap tiles; + 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); + } + + @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) { + biomes = new BiomeType[256]; + } + biomes[x + (z << 4)] = biome; + 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()); + return true; + } + + @Override + public void setTile(final int x, final int y, final int z, final CompoundTag tile) { + if (tiles == null) { + tiles = new HashMap<>(); + } + final short pair = MathMan.tripleBlockCoord(x, y, z); + tiles.put(pair, tile); + } + + @Override + public void setEntity(final CompoundTag tag) { + if (entities == null) { + entities = new HashSet<>(); + } + entities.add(tag); + } + + @Override + public void removeEntity(final UUID uuid) { + if (entityRemoves == null) { + entityRemoves = new HashSet<>(); + } + entityRemoves.add(uuid); + } + + @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 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/holder/ChunkHolder.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java new file mode 100644 index 000000000..d0a192063 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java @@ -0,0 +1,311 @@ +package com.boydti.fawe.beta.implementation.holder; + +import com.boydti.fawe.beta.ChunkFilterBlock; +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.FilterBlockMask; +import com.boydti.fawe.beta.Flood; +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; +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; + +/** + * Abstract IChunk class that implements basic get/set blocks + */ +public abstract class ChunkHolder implements IChunk, Supplier { + private IChunkGet get; + private IChunkSet set; + private IBlockDelegate delegate; + private IQueueExtent extent; + private int X,Z; + + public ChunkHolder() { + this.delegate = NULL; + } + + public ChunkHolder(final IBlockDelegate delegate) { + this.delegate = delegate; + } + + @Override + public void flood(Flood flood, FilterBlockMask mask, ChunkFilterBlock block) { +// block.flood(get, set, mask, block, ); + } + + @Override + public void filterBlocks(final Filter filter, ChunkFilterBlock block, @Nullable Region region) { + final IChunkGet get = getOrCreateGet(); + final IChunkSet set = getOrCreateSet(); + try { + if (region != null) { + 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); + } + } + } finally { + filter.finishChunk(this); + } + } + + @Override + public boolean trim(final boolean aggressive) { + if (set != null) { + final 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(); + } + + public final IChunkGet getOrCreateGet() { + if (get == null) get = newGet(); + return get; + } + + public final IChunkSet getOrCreateSet() { + if (set == null) set = set(); + return set; + } + + public IChunkSet set() { + return new CharSetBlocks(); + } + + private IChunkGet newGet() { + if (extent instanceof SingleThreadQueueExtent) { + final WorldChunkCache cache = ((SingleThreadQueueExtent) extent).getCache(); + return cache.get(MathMan.pairInt(X, Z), this); + } + return get(); + } + + @Override + public void init(final IQueueExtent extent, final int X, final int Z) { + this.extent = extent; + this.X = X; + this.Z = Z; + if (set != null) { + set.reset(); + delegate = SET; + } else { + delegate = NULL; + } + get = null; + } + + public IQueueExtent getExtent() { + return 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.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.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.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.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.getOrCreateGet(); + 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.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.getOrCreateSet(); + 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.getBiomeType(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.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.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.getOrCreateGet(); + 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.getBiomeType(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-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 new file mode 100644 index 000000000..88c6269db --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java @@ -0,0 +1,33 @@ +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 + * @param + */ +public class DelegateChunk implements IDelegateChunk { + private T parent; + + public DelegateChunk(final T parent) { + this.parent = parent; + } + + public final T getParent() { + return 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..ca599ae94 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/FinalizedChunk.java @@ -0,0 +1,31 @@ +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, final IQueueExtent queueExtent) { + super(parent); + this.queueExtent = queueExtent; + } + + /** + * Submit the chunk to the queue + * @throws Throwable + */ + @Override + protected void finalize() throws Throwable { + if (getParent() != null) { + // 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/implementation/holder/ReferenceChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ReferenceChunk.java new file mode 100644 index 000000000..cb88a839e --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ReferenceChunk.java @@ -0,0 +1,28 @@ +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; + +/** + * 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; + + public ReferenceChunk(final IChunk parent, final 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..361b7083d --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/SoftChunk.java @@ -0,0 +1,22 @@ +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; + +/** + * Soft reference implementation of {@link ReferenceChunk} + */ +public class SoftChunk extends ReferenceChunk { + + public SoftChunk(final IChunk parent, final IQueueExtent queueExtent) { + super(parent, queueExtent); + } + + @Override + protected Reference toRef(final FinalizedChunk parent) { + return new SoftReference<>(parent); + } +} 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 new file mode 100644 index 000000000..a97c915d5 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/WeakChunk.java @@ -0,0 +1,21 @@ +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, final IQueueExtent queueExtent) { + super(parent, queueExtent); + } + + @Override + protected Reference toRef(final FinalizedChunk parent) { + return new WeakReference<>(parent); + } +} 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 feff6cd22..ae3a4a327 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/config/Settings.java b/worldedit-core/src/main/java/com/boydti/fawe/config/Settings.java index 1d0e4c183..462fb8633 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/NBTStreamer.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/NBTStreamer.java index 172f5f67c..2cc2ebc7a 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/NBTStreamer.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/NBTStreamer.java @@ -42,7 +42,7 @@ public class NBTStreamer { try { is.readNamedTagLazy(node -> { if (readers.isEmpty()) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MANUAL); + throw FaweException.MANUAL; } return readers.remove(node); }); 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..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; @@ -159,4 +158,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/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java index faee31462..77b8d2048 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; @@ -1023,7 +1029,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) { @@ -1046,12 +1052,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)); } 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 2fb4ba534..887acd28e 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 @@ -77,9 +77,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); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java index b274b241c..4bac59bac 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java @@ -79,7 +79,7 @@ public class MCAFile { this.queue = parent; this.file = file; if (!file.exists()) { - throw new FaweException.FaweChunkLoadException(); + throw FaweException.CHUNK; } String[] split = file.getName().split("\\."); X = Integer.parseInt(split[1]); 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 25e4bb415..4c76a6c86 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 @@ -149,7 +149,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; } @@ -173,8 +173,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: @@ -191,7 +191,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/FawePlayer.java b/worldedit-core/src/main/java/com/boydti/fawe/object/FawePlayer.java index a758c866b..73dfccd85 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/FawePlayer.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/FawePlayer.java @@ -243,9 +243,9 @@ public abstract class FawePlayer extends Metadatable { Region[] allowed = WEManager.IMP.getMask(this, FaweMaskManager.MaskType.OWNER); HashSet allowedSet = new HashSet<>(Arrays.asList(allowed)); if (allowed.length == 0) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_NO_REGION); + throw FaweException.NO_REGION; } else if (!WEManager.IMP.regionContains(wrappedSelection, allowedSet)) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + throw FaweException.OUTSIDE_REGION; } } 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 855336431..8b8c328ca 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 { return BlockState.getFromInternalId(combinedId4Data); 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 83e26f098..058724112 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 @@ -29,7 +29,6 @@ public class HistoryExtent extends AbstractDelegateExtent { private FaweChangeSet changeSet; private final FaweQueue queue; - private final EditSession session; /** * Create a new instance. @@ -37,12 +36,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() { @@ -55,9 +53,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/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/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/brush/SplineBrush.java b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/SplineBrush.java index c4f7d817d..a021c1782 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/SplineBrush.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/SplineBrush.java @@ -68,7 +68,7 @@ public class SplineBrush implements Brush, ResettableTool { this.position = position; if (newPos) { if (positionSets.size() >= MAX_POINTS) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); + throw FaweException.MAX_CHECKS; } final ArrayList points = new ArrayList<>(); if (size > 0) { 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/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/changeset/BlockBagChangeSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/changeset/BlockBagChangeSet.java index 4e742229b..dbda97050 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/changeset/BlockBagChangeSet.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/changeset/BlockBagChangeSet.java @@ -1,6 +1,5 @@ package com.boydti.fawe.object.changeset; -import com.boydti.fawe.FaweCache; import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.util.ReflectionUtils; import com.sk89q.jnbt.CompoundTag; @@ -10,7 +9,6 @@ import com.sk89q.worldedit.extent.inventory.BlockBagException; import com.sk89q.worldedit.extent.inventory.UnplaceableBlockException; 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.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; @@ -89,10 +87,10 @@ public class BlockBagChangeSet extends AbstractDelegateChangeSet { try { blockBag.fetchPlacedBlock(typeTo.getDefaultState()); } catch (UnplaceableBlockException e) { - throw new FaweException.FaweBlockBagException(); + throw FaweException.BLOCK_BAG; } catch (BlockBagException e) { missingBlocks[typeTo.getInternalId()]++; - throw new FaweException.FaweBlockBagException(); + throw FaweException.BLOCK_BAG; } } if (mine) { 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 0254fe2e2..78d49acca 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 @@ -78,7 +78,7 @@ public class EmptyClipboard implements Clipboard { } @Override - public BlockState getLazyBlock(BlockVector3 position) { + public BlockState getBlock(BlockVector3 position) { return BlockTypes.AIR.getDefaultState(); } 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 b406d553c..681c13636 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 @@ -38,13 +38,15 @@ public class BlockVectorSet extends AbstractCollection implements int newSize = count + size; if (newSize > index) { int localIndex = index - count; - BlockVector3 pos = mutable.setComponents(set.getIndex(localIndex)); - int pair = entry.getIntKey(); - int cx = MathMan.unpairX(pair); - int cz = MathMan.unpairY(pair); - pos = pos.mutX((cx << 11) + pos.getBlockX()); - pos = pos.mutZ((cz << 11) + pos.getBlockZ()); - return pos; + BlockVector3 pos = set.getIndex(localIndex); + if (pos != null) { + int pair = entry.getIntKey(); + int cx = MathMan.unpairX(pair); + int cz = MathMan.unpairY(pair); + pos = pos.mutX((cx << 11) + pos.getBlockX()); + pos = pos.mutZ((cz << 11) + pos.getBlockZ()); + return pos; + } } count += newSize; } 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/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) { 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 e1c83573f..0fe0d9f15 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 @@ -101,7 +101,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/exception/FaweException.java b/worldedit-core/src/main/java/com/boydti/fawe/object/exception/FaweException.java index 78e66b366..1c3726905 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/exception/FaweException.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/exception/FaweException.java @@ -3,6 +3,17 @@ package com.boydti.fawe.object.exception; import com.boydti.fawe.config.BBC; public class FaweException extends RuntimeException { + public static final FaweChunkLoadException CHUNK = new FaweChunkLoadException(); + public static final FaweBlockBagException BLOCK_BAG = new FaweBlockBagException(); + public static final FaweException MANUAL = new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MANUAL); + public static final FaweException NO_REGION = new FaweException(BBC.WORLDEDIT_CANCEL_REASON_NO_REGION); + public static final FaweException OUTSIDE_REGION = new FaweException(BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + public static final FaweException MAX_CHECKS = new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); + public static final FaweException MAX_CHANGES = new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES); + public static final FaweException LOW_MEMORY = new FaweException(BBC.WORLDEDIT_CANCEL_REASON_LOW_MEMORY); + public static final FaweException MAX_ENTITIES = new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_ENTITIES); + public static final FaweException MAX_TILES = new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_TILES); + private final BBC message; public FaweException(BBC reason) { @@ -42,7 +53,7 @@ public class FaweException extends RuntimeException { } /** - * Faster exception throwing if you don't fill the stacktrace + * Faster exception throwing/handling if you don't fill the stacktrace * * @return */ 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/FastWorldEditExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/FastWorldEditExtent.java index 5d94300bd..0c9984bdd 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 @@ -126,12 +126,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); return type.withStateId(combinedId4Data); @@ -161,11 +161,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/FaweRegionExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/FaweRegionExtent.java index b7f86660c..3d13b8bdc 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 @@ -2,6 +2,7 @@ package com.boydti.fawe.object.extent; import com.boydti.fawe.config.BBC; import com.boydti.fawe.object.FaweLimit; +import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.util.WEManager; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; @@ -56,44 +57,22 @@ 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)) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return false; } 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)) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return false; } @@ -104,18 +83,29 @@ public abstract class FaweRegionExtent extends ResettableExtent { public BiomeType getBiome(BlockVector2 position) { if (!contains(position)) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return null; } return super.getBiome(position); } + @Override + public BiomeType getBiomeType(int x, int z) { + if (!contains(x, z)) { + if (!limit.MAX_FAILS()) { + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); + } + return null; + } + return super.getBiomeType(x, z); + } + @Override public BaseBlock getFullBlock(BlockVector3 position) { if (!contains(position)) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return BlockTypes.AIR.getDefaultState().toBaseBlock(); } @@ -126,40 +116,18 @@ public abstract class FaweRegionExtent extends ResettableExtent { public BlockState getBlock(BlockVector3 position) { if (!contains(position)) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return BlockTypes.AIR.getDefaultState(); } 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 BlockTypes.AIR.getDefaultState(); - } - 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 BlockTypes.AIR.getDefaultState(); - } - return super.getLazyBlock(x, y, z); - } - @Override public int getBlockLight(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); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return 0; } @@ -170,7 +138,7 @@ public abstract class FaweRegionExtent extends ResettableExtent { public int getBrightness(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); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return 0; } @@ -181,7 +149,7 @@ public abstract class FaweRegionExtent extends ResettableExtent { public int getLight(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); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return 0; } @@ -192,7 +160,7 @@ public abstract class FaweRegionExtent extends ResettableExtent { public int getOpacity(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); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return 0; } @@ -203,7 +171,7 @@ public abstract class FaweRegionExtent extends ResettableExtent { public int getSkyLight(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); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return 0; } @@ -215,7 +183,7 @@ public abstract class FaweRegionExtent extends ResettableExtent { public Entity createEntity(Location location, BaseEntity entity) { if (!contains(location.getBlockX(), location.getBlockY(), location.getBlockZ())) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return null; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/MemoryCheckingExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/MemoryCheckingExtent.java index 9503ade76..72f7583cb 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/MemoryCheckingExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/MemoryCheckingExtent.java @@ -2,6 +2,7 @@ package com.boydti.fawe.object.extent; import com.boydti.fawe.config.BBC; import com.boydti.fawe.object.FawePlayer; +import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.util.MemUtil; import com.boydti.fawe.util.Perm; import com.boydti.fawe.util.WEManager; @@ -30,7 +31,7 @@ public class MemoryCheckingExtent extends AbstractDelegateExtent { BBC.WORLDEDIT_OOM_ADMIN.send(this.player); } } - WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_LOW_MEMORY); + WEManager.IMP.cancelEdit(this, FaweException.LOW_MEMORY); return false; } return true; 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..50f69f855 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 @@ -25,7 +25,7 @@ import java.util.List; public class NullExtent extends FaweRegionExtent { - private final BBC reason; + private final FaweException reason; /** * Create a new instance. @@ -33,13 +33,16 @@ public class NullExtent extends FaweRegionExtent { * @param extent the extent */ public NullExtent(Extent extent, BBC failReason) { + this(extent, new FaweException(failReason)); + } + + public NullExtent(Extent extent, FaweException exception) { super(extent, FaweLimit.MAX); - this.reason = failReason; + this.reason = exception; } public NullExtent() { - super(new com.sk89q.worldedit.extent.NullExtent(), FaweLimit.MAX); - this.reason = BBC.WORLDEDIT_CANCEL_REASON_MANUAL; + this(new com.sk89q.worldedit.extent.NullExtent(), FaweException.MANUAL); } @Override @@ -50,7 +53,7 @@ public class NullExtent extends FaweRegionExtent { @Override public BiomeType getBiome(final BlockVector2 arg0) { if(reason != null) { - throw new FaweException(reason); + throw reason; }else { return null; } @@ -59,25 +62,34 @@ public class NullExtent extends FaweRegionExtent { @Override public BlockState getBlock(final BlockVector3 arg0) { if(reason != null) { - throw new FaweException(reason); + throw reason; }else { return null; } } @Override - public BlockState getLazyBlock(final BlockVector3 arg0) { + public BlockState getBlock(int x, int y, int z) { if(reason != null) { - throw new FaweException(reason); + throw reason; }else { return null; } } + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + if(reason != null) { + throw reason; + }else { + return null; + } + } + @Override public boolean setBiome(final BlockVector2 arg0, final BiomeType arg1) { if(reason != null) { - throw new FaweException(reason); + throw reason; }else { return false; } @@ -86,7 +98,7 @@ public class NullExtent extends FaweRegionExtent { @Override public boolean setBlock(final BlockVector3 arg0, final BlockStateHolder arg1) throws WorldEditException { if(reason != null) { - throw new FaweException(reason); + throw reason; }else { return false; } @@ -95,25 +107,16 @@ public class NullExtent extends FaweRegionExtent { @Override public boolean setBlock(int x, int y, int z, BlockStateHolder block) throws WorldEditException { if(reason != null) { - throw new FaweException(reason); + throw reason; }else { return false; } } - @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) { - throw new FaweException(reason); + throw reason; }else { return null; } @@ -142,7 +145,7 @@ public class NullExtent extends FaweRegionExtent { @Override public boolean contains(int x, int z) { if(reason != null) { - throw new FaweException(reason); + throw reason; }else { return false; } @@ -151,7 +154,7 @@ public class NullExtent extends FaweRegionExtent { @Override public boolean contains(int x, int y, int z) { if(reason != null) { - throw new FaweException(reason); + throw reason; }else { return false; } @@ -176,7 +179,7 @@ public class NullExtent extends FaweRegionExtent { @Override public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) { if(reason != null) { - throw new FaweException(reason); + throw reason; }else { return -1; } @@ -185,7 +188,7 @@ public class NullExtent extends FaweRegionExtent { @Override public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) { if(reason != null) { - throw new FaweException(reason); + throw reason; }else { return -1; } @@ -194,7 +197,7 @@ public class NullExtent extends FaweRegionExtent { @Override public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) { if(reason != null) { - throw new FaweException(reason); + throw reason; }else { return -1; } 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 29d8eae5b..c984a7ca9 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 @@ -46,13 +46,8 @@ 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 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 d9a331f82..3584098d5 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 @@ -2,6 +2,7 @@ package com.boydti.fawe.object.extent; import com.boydti.fawe.config.BBC; import com.boydti.fawe.object.FaweLimit; +import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.util.WEManager; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; @@ -40,7 +41,7 @@ public class ProcessedWEExtent extends AbstractDelegateExtent { return null; } if (!limit.MAX_ENTITIES()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_ENTITIES); + WEManager.IMP.cancelEditSafe(this, FaweException.MAX_ENTITIES); return null; } return super.createEntity(location, entity); @@ -62,19 +63,19 @@ 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); + WEManager.IMP.cancelEditSafe(this, FaweException.MAX_CHECKS); return BlockTypes.AIR.getDefaultState(); } else { - return extent.getLazyBlock(x, y, z); + return extent.getBlock(x, y, z); } } @Override public BaseBlock getFullBlock(BlockVector3 pos) { if (!limit.MAX_CHECKS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); + WEManager.IMP.cancelEditSafe(this, FaweException.MAX_CHECKS); return BlockTypes.AIR.getDefaultState().toBaseBlock(); } else { return extent.getFullBlock(pos); @@ -87,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 @@ -96,18 +97,18 @@ public class ProcessedWEExtent extends AbstractDelegateExtent { boolean hasNbt = block instanceof BaseBlock && ((BaseBlock)block).hasNbtData(); if (hasNbt) { if (!limit.MAX_BLOCKSTATES()) { - WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_TILES); + WEManager.IMP.cancelEdit(this, FaweException.MAX_TILES); return false; } else { if (!limit.MAX_CHANGES()) { - WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES); + WEManager.IMP.cancelEdit(this, FaweException.MAX_CHANGES); return false; } return extent.setBlock(x, y, z, block); } } if (!limit.MAX_CHANGES()) { - WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES); + WEManager.IMP.cancelEdit(this, FaweException.MAX_CHANGES); return false; } else { return extent.setBlock(x, y, z, block); @@ -117,7 +118,7 @@ public class ProcessedWEExtent extends AbstractDelegateExtent { @Override public boolean setBiome(final BlockVector2 position, final BiomeType biome) { if (!limit.MAX_CHANGES()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES); + WEManager.IMP.cancelEditSafe(this, FaweException.MAX_CHANGES); return false; } return super.setBiome(position, biome); 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 6005c0d8d..96e61de59 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 @@ -57,19 +57,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 910c7a9e8..f2be69cf1 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; public TransformExtent(Extent parent) { @@ -50,43 +52,34 @@ 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))); - } - - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return transform(super.getLazyBlock(getPos(position))); - } - - @Override - public BlockState getBlock(BlockVector3 position) { - return transform(super.getBlock(getPos(position))); + 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 @@ -95,11 +88,9 @@ public class TransformExtent extends BlockTransformExtent { } @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 getBiomeType(int x, int z) { + BlockVector3 p = getPos(x, 0, z); + return super.getBiomeType(p.getX(), p.getZ()); } @Override @@ -114,10 +105,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/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/AngleColorPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AngleColorPattern.java index f11fc4896..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,7 +1,6 @@ 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.sk89q.worldedit.WorldEditException; @@ -12,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 TextureHolder util; + protected transient TextureHolder holder; - public AngleColorPattern(Extent extent, TextureHolder util, int distance) { + public AngleColorPattern(Extent extent, TextureHolder holder, int distance) { super(extent, distance); - this.util = util; + this.holder = holder.getTextureUtil(); } public int getColor(int color, int slope) { @@ -34,24 +31,24 @@ public class AngleColorPattern extends DataAnglePattern { @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.getTextureUtil().getColor(block.getBlockType()); + int color = holder.getTextureUtil().getColor(block.getBlockType()); if (color == 0) return block; int newColor = getColor(color, slope); - return util.getTextureUtil().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(); 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; } @@ -61,20 +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.getTextureUtil().getColor(block.getBlockType()); + int color = holder.getTextureUtil().getColor(block.getBlockType()); if (color == 0) return false; int newColor = getColor(color, slope); - BlockType newBlock = util.getTextureUtil().getNearestBlock(newColor); + BlockType newBlock = holder.getTextureUtil().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); + 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 aaf3ee200..36500403b 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 @@ -22,9 +22,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. @@ -34,7 +32,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"); } @@ -64,13 +61,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(); - } - } } 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 d49ca03ab..d58548a2c 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 @@ -12,8 +12,6 @@ import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.session.ClipboardHolder; -import java.io.IOException; -import java.io.NotSerializableException; import java.util.List; import java.util.concurrent.ThreadLocalRandom; @@ -24,18 +22,19 @@ 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 - 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(ThreadLocalRandom.current().nextInt(clipboards.size())); AffineTransform transform = new AffineTransform(); if (randomRotate) { @@ -52,9 +51,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; } @@ -63,8 +62,4 @@ public class RandomFullClipboardPattern extends AbstractPattern { public BaseBlock apply(BlockVector3 position) { throw new IllegalStateException("Incorrect use. This pattern can only be applied to an extent!"); } - - private void writeObject(java.io.ObjectOutputStream stream) throws IOException { - throw new NotSerializableException("Clipboard cannot be serialized!"); - } } 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 9a9df9241..03ee435a0 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,19 +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 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 +108,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 0eed3a025..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 @@ -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/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/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/schematic/visualizer/SchemVis.java b/worldedit-core/src/main/java/com/boydti/fawe/object/schematic/visualizer/SchemVis.java index cf393791c..5755c9aa2 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/schematic/visualizer/SchemVis.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/schematic/visualizer/SchemVis.java @@ -551,13 +551,13 @@ // public void sendChunk(int x, int z, int bitMask) { /* do nothing - never used*/ } // // @Override -// public BiomeType getBiomeType(int x, int z) throws FaweException.FaweChunkLoadException { +// public BiomeType getBiomeType(int x, int z) throws FaweException.CHUNK { // // TODO later (currently not used) // return BiomeTypes.FOREST; // } // // @Override -// public int getCombinedId4Data(int x, int y, int z) throws FaweException.FaweChunkLoadException { +// public int getCombinedId4Data(int x, int y, int z) throws FaweException.CHUNK { // MCAChunk chunk = getChunk(x >> 4, z >> 4); // if (y < 0 || y > 255) return 0; // return chunk.getBlockCombinedId(x & 15, y, z & 15); 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..5fdd439c8 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.UNIT_MINUS_X, + BlockVector3.UNIT_MINUS_Y, + BlockVector3.UNIT_MINUS_Z, + BlockVector3.UNIT_X, + BlockVector3.UNIT_Y, + BlockVector3.UNIT_Z + ); } @Override 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 fe6e585d4..9d5d45036 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; @@ -57,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; @@ -190,7 +218,274 @@ 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, FaweException.MANUAL); + } + final Extent toReturn = event.getExtent(); + if(toReturn instanceof com.sk89q.worldedit.extent.NullExtent) { + return new NullExtent(toReturn, FaweException.MANUAL); + } + 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; + } + + 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) { + 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 FaweException.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.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(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 = world == null ? 255 : world.getMaxY(); + if (allowedRegions != null) { + if (allowedRegions.length == 0) { + this.extent = new NullExtent(this.extent, FaweException.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/boydti/fawe/util/TextureUtil.java b/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java index 36de2fbc3..e978949e9 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,15 +1,14 @@ package com.boydti.fawe.util; import com.boydti.fawe.Fawe; +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.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.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; @@ -66,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); } } @@ -491,7 +491,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/util/WEManager.java b/worldedit-core/src/main/java/com/boydti/fawe/util/WEManager.java index 7d08000be..878a18b7b 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/WEManager.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/WEManager.java @@ -24,7 +24,7 @@ public class WEManager { public final ArrayDeque managers = new ArrayDeque<>(); - public void cancelEditSafe(Extent parent, BBC reason) throws FaweException { + public void cancelEditSafe(Extent parent, FaweException reason) throws FaweException { try { final Field field = AbstractDelegateExtent.class.getDeclaredField("extent"); field.setAccessible(true); @@ -35,10 +35,10 @@ public class WEManager { } catch (final Exception e) { e.printStackTrace(); } - throw new FaweException(reason); + throw reason; } - public void cancelEdit(Extent parent, BBC reason) throws WorldEditException { + public void cancelEdit(Extent parent, FaweException reason) throws WorldEditException { cancelEditSafe(parent, reason); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/web/SchemSync.java b/worldedit-core/src/main/java/com/boydti/fawe/web/SchemSync.java index 67a97478d..79d18c637 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/web/SchemSync.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/web/SchemSync.java @@ -53,7 +53,7 @@ public class SchemSync implements Runnable { private void close(Error error) throws IOException { this.clientSocket.getOutputStream().write(error.ordinal()); - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MANUAL); + throw FaweException.MANUAL; } @Override 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/jnbt/CompoundTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java index 04649bd5f..a12e58d69 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java @@ -424,6 +424,16 @@ public class CompoundTag extends Tag { } } + @Override + public Map toRaw() { + HashMap raw = new HashMap<>(); + if (this.value.isEmpty()) return raw; + for (Map.Entry entry : value.entrySet()) { + raw.put(entry.getKey(), entry.getValue().toRaw()); + } + return raw; + } + @Override public String toString() { StringBuilder bldr = new StringBuilder(); diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java index e29da1c0a..42732d92a 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java @@ -21,6 +21,7 @@ package com.sk89q.jnbt; import static com.google.common.base.Preconditions.checkNotNull; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -416,6 +417,18 @@ public final class ListTag extends Tag { } } + @Override + public ArrayList toRaw() { + ArrayList raw = new ArrayList<>(); + if (this.value.isEmpty()) { + return raw; + } + for (Tag elem : this.value) { + raw.add(elem.toRaw()); + } + return raw; + } + @Override public String toString() { StringBuilder bldr = new StringBuilder(); diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java index 47d501f09..d7c273b17 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java @@ -31,4 +31,8 @@ public abstract class Tag { */ public abstract Object getValue(); + public Object toRaw() { + return getValue(); + } + } 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 9cdfe5543..035797f12 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -50,6 +50,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; @@ -150,7 +151,10 @@ 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; import java.util.Set; @@ -203,26 +207,23 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, return this.displayName; } } - - @SuppressWarnings("ProtectedField") - protected final World world; - private String worldName; - private FaweQueue queue; + private final World world; + private final String worldName; + private final FaweQueue queue; private boolean wrapped; private boolean fastMode; - private AbstractDelegateExtent extent; - private HistoryExtent history; + private final HistoryExtent history; private AbstractDelegateExtent bypassHistory; private AbstractDelegateExtent bypassAll; - private FaweLimit originalLimit; - private FaweLimit limit; - private FawePlayer player; + private final FaweLimit originalLimit; + private final FaweLimit limit; + private final FawePlayer player; private 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 +235,25 @@ 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() : world.getName() : worldName; - if (world == null && this.worldName != null) world = FaweAPI.getWorld(this.worldName); + 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)); + } - this.world = world; - - if (bus == null) { - bus = WorldEdit.getInstance().getEventBus(); - } - 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()); - } - 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); - setExtent(this.extent); + public EditSession(EditSessionBuilder 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(); } /** @@ -406,6 +269,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) * @@ -417,7 +284,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); } @@ -456,7 +323,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(); } @@ -468,15 +335,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 * @@ -488,18 +346,17 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, } public boolean cancel() { - ExtentTraverser traverser = new ExtentTraverser(this.extent); - NullExtent nullExtent = new NullExtent(world, BBC.WORLDEDIT_CANCEL_REASON_MANUAL); + ExtentTraverser traverser = new ExtentTraverser(this); + NullExtent nullExtent = new NullExtent(world, FaweException.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()) { @@ -553,46 +410,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, return queue; } - @Deprecated - private AbstractDelegateExtent wrapExtent(Extent extent, EventBus eventBus, EditSessionEvent event, 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 (AbstractDelegateExtent) 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 (AbstractDelegateExtent) extent; - } - // pkg private for TracedEditSession only, may later become public API boolean commitRequired() { return false; @@ -740,7 +557,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; } @@ -750,28 +567,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(); } @@ -789,7 +597,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) { @@ -797,7 +605,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); } } @@ -806,13 +615,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); } @@ -828,7 +637,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) { @@ -836,7 +645,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); } } @@ -846,13 +656,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; } } @@ -879,7 +688,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(); @@ -887,11 +696,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); @@ -926,12 +735,12 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @param blockBag the block bag to set, or null to use none */ public void setBlockBag(BlockBag blockBag) { - this.blockBag = blockBag; + throw new UnsupportedOperationException("TODO - this is never called anyway"); } @Override public String toString() { - return super.toString() + ":" + extent; + return super.toString() + ":" + getExtent(); } /** @@ -952,7 +761,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 { @@ -1020,20 +829,20 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, } @Override - public BiomeType getBiome(BlockVector2 position) { - return this.extent.getBiome(position); + public BiomeType getBiome(final BlockVector2 position) { + return this.getExtent().getBiome(position); } @Override public boolean setBiome(BlockVector2 position, 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 @@ -1061,27 +870,18 @@ 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 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); } /** @@ -1089,7 +889,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) { @@ -1136,7 +936,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, public BlockType getBlockType(int x, int y, int z) { if (!limit.MAX_CHECKS()) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); + throw FaweException.MAX_CHECKS; } int combinedId4Data = queue.getCombinedId4DataDebug(x, y, z, BlockTypes.AIR.getInternalId(), this); return BlockTypes.getFromStateId(combinedId4Data); @@ -1155,7 +955,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: @@ -1201,7 +1001,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) { @@ -1212,7 +1012,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); } @@ -1222,7 +1022,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); } @@ -1232,7 +1032,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); } @@ -1240,7 +1040,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; @@ -1277,7 +1077,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, @Override @Nullable public Entity createEntity(com.sk89q.worldedit.util.Location location, final BaseEntity entity) { - return this.extent.createEntity(location, entity); + return getExtent().createEntity(location, entity); } /** @@ -1350,30 +1150,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(Region region) { - return this.extent.getEntities(region); + return getExtent().getEntities(region); } @Override public List getEntities() { - return this.extent.getEntities(); + return getExtent().getEntities(); } /** @@ -1394,7 +1186,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, @Override public @Nullable Operation commit() { - return extent.commit(); + return getExtent().commit(); } /** @@ -1493,7 +1285,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @return the number of blocks that matched the pattern */ public int countBlocks(Region region, 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 { @@ -1741,7 +1533,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 @@ -1769,12 +1561,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++; } } @@ -2230,7 +2022,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, blockMask ); - BlockReplace replace = new BlockReplace(this, (fluid.getDefaultState())); + BlockReplace replace = new BlockReplace(this, fluid.getDefaultState()); NonRisingVisitor visitor = new NonRisingVisitor(mask, replace); // Around the origin in a 3x3 block @@ -2502,8 +2294,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public int makeSphere(BlockVector3 pos, Pattern block, double radiusX, double radiusY, double radiusZ, boolean filled) throws MaxChangedBlocksException { - int affected = 0; - radiusX += 0.5; radiusY += 0.5; radiusZ += 0.5; @@ -3091,6 +2881,10 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public int hollowOutRegion(Region region, int thickness, Pattern pattern) throws MaxChangedBlocksException { + 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(); @@ -3106,22 +2900,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); } } @@ -3150,7 +2944,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); @@ -3364,28 +3158,29 @@ 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(); queue.add(origin); while (!queue.isEmpty()) { - BlockVector3 current = queue.getIndex(0); - queue.remove(current); - final BlockState block = getBlock(current); - if (block.getBlockType().getMaterial().isMovementBlocker()) { - continue; - } + Iterator iter = queue.iterator(); + while (iter.hasNext()) { + final BlockVector3 current = iter.next(); + iter.remove(); + if (mask.test(current)) { + continue; + } + if (!outside.add(current)) { + continue; + } - if (!outside.add(current)) { - continue; - } + if (!region.contains(current)) { + continue; + } - if (!region.contains(current)) { - continue; - } - - for (BlockVector3 recurseDirection : recurseDirections) { - queue.add(current.add(recurseDirection)); - } + for (BlockVector3 recurseDirection : recurseDirections) { + queue.add(current.add(recurseDirection)); + } + } } } @@ -3460,8 +3255,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; @@ -3504,7 +3298,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, BlockVector3 max = region.getMaximumPoint(); BlockVector3 min = region.getMinimumPoint(); if (!fe.contains(max.getBlockX(), max.getBlockY(), max.getBlockZ()) && !fe.contains(min.getBlockX(), min.getBlockY(), min.getBlockZ())) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + throw FaweException.OUTSIDE_REGION; } } final Set chunks = region.getChunks(); 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/ClipboardCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java index 050908187..54ef32531 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -128,7 +128,7 @@ public class ClipboardCommands extends MethodCommands { long volume = (((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min.getZ() + 1)); FaweLimit limit = FawePlayer.wrap(player).getLimit(); if (volume >= limit.MAX_CHECKS) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); + throw FaweException.MAX_CHECKS; } session.setClipboard(null); final BlockVector3 origin = region.getMinimumPoint(); @@ -168,7 +168,7 @@ public class ClipboardCommands extends MethodCommands { long volume = (((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min.getZ() + 1)); FaweLimit limit = FawePlayer.wrap(player).getLimit(); if (volume >= limit.MAX_CHECKS) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); + throw FaweException.MAX_CHECKS; } BlockVector3 pos = session.getPlacementPosition(player); fp.checkConfirmationRegion(() -> { @@ -218,10 +218,10 @@ public class ClipboardCommands extends MethodCommands { long volume = (((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min.getZ() + 1)); FaweLimit limit = FawePlayer.wrap(player).getLimit(); if (volume >= limit.MAX_CHECKS) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); + throw FaweException.MAX_CHECKS; } if (volume >= limit.MAX_CHANGES) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES); + throw FaweException.MAX_CHANGES; } session.setClipboard(null); final BlockVector3 origin = region.getMinimumPoint(); @@ -258,10 +258,10 @@ public class ClipboardCommands extends MethodCommands { long volume = (((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min.getZ() + 1)); FaweLimit limit = FawePlayer.wrap(player).getLimit(); if (volume >= limit.MAX_CHECKS) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); + throw FaweException.MAX_CHECKS; } if (volume >= limit.MAX_CHANGES) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES); + throw FaweException.MAX_CHANGES; } BlockVector3 pos = session.getPlacementPosition(player); fp.checkConfirmationRegion(() -> { @@ -497,7 +497,7 @@ public class ClipboardCommands extends MethodCommands { if (holder instanceof URIClipboardHolder) uri = ((URIClipboardHolder) holder).getURI(clipboard); PasteEvent event = new PasteEvent(player, clipboard, uri, editSession, to); worldEdit.getEventBus().post(event); - if (event.isCancelled()) throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MANUAL); + if (event.isCancelled()) throw FaweException.MANUAL; } @Command( 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/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index c1cc532f0..fd43d0064 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.filters.SetFilter; +import com.boydti.fawe.beta.implementation.QueueHandler; +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; @@ -45,6 +50,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; @@ -65,10 +71,14 @@ 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.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.registry.BiomeRegistry; import java.util.ArrayList; @@ -104,6 +114,43 @@ public class RegionCommands extends MethodCommands { this.worldEdit = worldEdit; } + + @Command( + aliases = {"debugtest"}, + usage = "", + desc = "debugtest", + help = "debugtest" + ) + @CommandPermissions("fawe.admin.debug") + 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" + ) + @CommandPermissions("fawe.admin.debug") + 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", @@ -465,7 +512,7 @@ public class RegionCommands extends MethodCommands { long volume = (((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min.getZ() + 1)); FaweLimit limit = FawePlayer.wrap(player).getLimit(); if (volume >= limit.MAX_CHECKS) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); + throw FaweException.MAX_CHECKS; } player.checkConfirmationRegion(() -> { try { @@ -733,7 +780,9 @@ 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 ) @@ -743,9 +792,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); } 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 bb1e3e37f..f75db497e 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 @@ -24,6 +24,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; @@ -694,7 +695,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()); } @@ -702,7 +703,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("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 8e893f2a8..5d0888e56 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; @@ -67,6 +69,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/command/tool/AreaPickaxe.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java index 9f42647db..4b356ad57 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 @@ -68,7 +68,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 (editSession.getLazyBlock(x, y, z).getBlockType() != initialType) { + 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/BrushTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java index 783a6a402..7b6a0ec3d 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 @@ -634,15 +634,16 @@ 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); + 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/command/tool/brush/GravityBrush.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java index 8e2754779..aa0bc2662 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, BlockTypes.AIR.getDefaultState()); 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 08bc96511..8c1ea1534 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 @@ -65,7 +65,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; /** @@ -83,14 +82,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. * @@ -168,9 +159,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/extension/factory/PatternFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java index 8f7ead81a..8d95c766c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java @@ -21,12 +21,7 @@ package com.sk89q.worldedit.extension.factory; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.factory.parser.pattern.BlockCategoryPatternParser; -import com.sk89q.worldedit.extension.factory.parser.pattern.ClipboardPatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.DefaultPatternParser; -import com.sk89q.worldedit.extension.factory.parser.pattern.RandomPatternParser; -import com.sk89q.worldedit.extension.factory.parser.pattern.RandomStatePatternParser; -import com.sk89q.worldedit.extension.factory.parser.pattern.SingleBlockPatternParser; -import com.sk89q.worldedit.extension.factory.parser.pattern.TypeOrStateApplyingPatternParser; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.registry.AbstractFactory; 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 fb3bbe620..d83fdc331 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 @@ -48,9 +48,8 @@ import java.util.List; /** * A base class for {@link Extent}s that merely passes extents onto another. */ -public class AbstractDelegateExtent implements LightingExtent { - private transient final Extent extent; - protected MutableBlockVector3 mutable = new MutableBlockVector3(0, 0, 0); +public class AbstractDelegateExtent implements Extent, LightingExtent { + private final Extent extent; /** * Create a new instance. @@ -62,11 +61,27 @@ public class AbstractDelegateExtent implements LightingExtent { this.extent = extent; } - 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 Extent getExtent() { + return extent; + } + + /* + Bounds + */ + + @Override + public BlockVector3 getMinimumPoint() { + return extent.getMinimumPoint(); + } + + @Override + public BlockVector3 getMaximumPoint() { + return extent.getMaximumPoint(); } @Override @@ -74,11 +89,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 getBiomeType(int x, int z) { + return extent.getBiomeType(x, z); + } + + @Override + public boolean setBiome(int x, int y, int z, BiomeType biome) { + return extent.setBiome(x, y, 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) { @@ -91,7 +135,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 @@ -106,164 +150,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 @@ -281,6 +181,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 49ac534bb..9e8f3e944 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 @@ -120,33 +120,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; } @@ -170,20 +148,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)); } @@ -192,15 +170,15 @@ 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) { - return layer + offset << 4; + return ((layer + offset) << 4) + 0; } data1 = PropertyGroup.LEVEL.get(block); } } 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)); } @@ -255,33 +233,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; 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 601643652..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 @@ -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(BlockVector3)} 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 getBiomeType(position.getX(), position.getZ()); + } + default BiomeType getBiomeType(int x, int z) { + return getBiome(MutableBlockVector2.get(x, z)); + } } 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 2d59364ea..cb31e893d 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 @@ -73,15 +73,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/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/extent/clipboard/BlockArrayClipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java index 96adbf2bf..dd2eec2ac 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 @@ -197,11 +197,6 @@ public class BlockArrayClipboard implements Clipboard, LightingExtent, Closeable return BlockTypes.AIR.getDefaultState(); } - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return getBlock(position); - } - @Override public BaseBlock getFullBlock(BlockVector3 position) { if(region.contains(position)) { @@ -286,11 +281,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(); } } 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 c6e508058..a65134097 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 @@ -44,7 +44,7 @@ public class BlockBagExtent extends AbstractDelegateExtent { private final boolean mine; private int[] missingBlocks = new int[BlockTypes.size()]; - private BlockBag blockBag; + private final BlockBag blockBag; /** * Create a new instance. @@ -72,15 +72,6 @@ public class BlockBagExtent extends AbstractDelegateExtent { return blockBag; } - /** - * Set the block bag. - * - * @param blockBag a block bag, which may be null if none is used - */ - public void setBlockBag(@Nullable BlockBag blockBag) { - this.blockBag = blockBag; - } - /** * Gets the list of missing blocks and clears the list for the next * operation. @@ -106,31 +97,27 @@ public class BlockBagExtent extends AbstractDelegateExtent { @Override public > boolean setBlock(int x, int y, int z, B block) throws WorldEditException { - if (blockBag != null) { - BlockState existing = getLazyBlock(x, y, z); - - if (!block.getBlockType().equals(existing.getBlockType())) { - if (!block.getBlockType().getMaterial().isAir()) { - try { - blockBag.fetchPlacedBlock(block.toImmutableState()); - } catch (UnplaceableBlockException e) { - throw new FaweException.FaweBlockBagException(); - } catch (BlockBagException e) { - missingBlocks[block.getBlockType().getInternalId()]++; - throw new FaweException.FaweBlockBagException(); - } + BlockState existing = getBlock(x, y, z); + if (!block.getBlockType().equals(existing.getBlockType())) { + if (!block.getBlockType().getMaterial().isAir()) { + try { + blockBag.fetchPlacedBlock(block.toImmutableState()); + } catch (UnplaceableBlockException e) { + throw FaweException.BLOCK_BAG; + } catch (BlockBagException e) { + missingBlocks[block.getBlockType().getInternalId()]++; + throw FaweException.BLOCK_BAG; } - if (mine) { - if (!existing.getBlockType().getMaterial().isAir()) { - try { - blockBag.storeDroppedBlock(existing); - } catch (BlockBagException ignored) { - } + } + if (mine) { + if (!existing.getBlockType().getMaterial().isAir()) { + try { + blockBag.storeDroppedBlock(existing); + } catch (BlockBagException ignored) { } } } } - return super.setBlock(x, y, z, block); } } 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 3d1fc566b..0984d3422 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 @@ -494,13 +494,8 @@ public class BlockTransformExtent extends ResettableExtent { } @Override - public BlockState getLazyBlock(int x, int y, int z) { - return transform(super.getLazyBlock(x, y, z)); - } - - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return transform(super.getLazyBlock(position)); + public BlockState getBlock(int x, int y, int z) { + return transform(super.getBlock(x, y, z)); } @Override 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/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 e17ea0b14..07ea67857 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 @@ -19,260 +19,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 static com.google.common.base.Preconditions.checkNotNull; import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.extent.NullExtent; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.registry.state.AbstractProperty; -import com.sk89q.worldedit.registry.state.Property; 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; -import javax.annotation.Nullable; -import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; -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.

- * @deprecated use BlockMaskBuilder - */ -@Deprecated -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; + } /** - * Create a new block mask. - * - * @param extent the extent - * @param blocks a list of blocks to match + * @deprecated NBT not supported by this mask */ + @Deprecated public BlockMask(Extent extent, Collection blocks) { - super(extent); - MainUtil.warnDeprecated(BlockMaskBuilder.class); - checkNotNull(blocks); - 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; } /** - * Create a new block mask. - * - * @param extent the extent - * @param block an array of blocks to match + * @deprecated NBT not supported by this mask */ - public BlockMask(Extent extent, BaseBlock... block) { - super(extent); - MainUtil.warnDeprecated(BlockMaskBuilder.class); - checkNotNull(block); - this.bitSets = new BlockMaskBuilder().addBlocks(block).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); + @Deprecated + 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; - } - } 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 db4ea88e9..0e0b20503 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; @@ -259,17 +262,22 @@ public class BlockMaskBuilder { public BlockMaskBuilder addAll() { for (int i = 0; i < bitSets.length; i++) { - bitSets[i] = BlockMask.ALL; + bitSets[i] = ALL; } - optimizedStates = true; + reset(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; } @@ -283,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; } @@ -311,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); @@ -321,7 +329,7 @@ public class BlockMaskBuilder { FastBitSet.set(states, stateId); else bitSets[i] = null; - optimizedStates = true; + reset(true); } return this; } @@ -350,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); } } } @@ -367,7 +375,7 @@ public class BlockMaskBuilder { } public BlockMaskBuilder add(BlockType type) { - bitSets[type.getInternalId()] = BlockMask.ALL; + bitSets[type.getInternalId()] = ALL; return this; } @@ -375,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; } @@ -410,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; @@ -419,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; @@ -434,7 +442,7 @@ public class BlockMaskBuilder { bitSets[i] = states = FastBitSet.create(type.getMaxStateId() + 1); } FastBitSet.set(states, localI); - optimizedStates = false; + reset(false); } } } @@ -446,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; @@ -455,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; } @@ -466,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; } @@ -518,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) { @@ -526,7 +534,7 @@ public class BlockMaskBuilder { bitSets[i] = null; continue; } else { - bitSets[i] = BlockMask.ALL; + bitSets[i] = ALL; continue; } } @@ -541,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 c27e82481..da7b92559 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 @@ -19,15 +19,12 @@ 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.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -39,6 +36,9 @@ import java.util.Set; *

This mask checks for ONLY the block type. If state should also be checked, * use {@link BlockMask}.

*/ +import static com.google.common.base.Preconditions.checkNotNull; + +@Deprecated public class BlockTypeMask extends AbstractExtentMask { private final boolean[] types; @@ -111,11 +111,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 d8ddcc704..d8e3990c4 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 1283b0bb2..d23af2b16 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; 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 051f904f8..dba2b6743 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 @@ -178,10 +178,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 3023c62ce..dd85587c7 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 @@ -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.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; @@ -140,7 +141,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 c870d4786..854d9471d 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 e5df3b153..a5d40b12f 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 @@ -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 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 ea5fd15b3..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,28 +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 a16c0109a..d493960bf 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 @@ -2,10 +2,11 @@ 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.world.block.BlockTypes; -public class SingleBlockTypeMask extends AbstractExtentMask { +public class SingleBlockTypeMask extends ABlockMask { private final int internalId; public SingleBlockTypeMask(Extent extent, BlockType type) { @@ -15,12 +16,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 b73bbb32b..80673fb1d 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 @@ -20,38 +20,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.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 6fb46180f..6ad68f5f9 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 @@ -21,6 +21,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; @@ -66,5 +67,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/FawePattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/FawePattern.java index 8edd7942c..f062bb075 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 @@ -14,17 +14,17 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; */ @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; } 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 2c000c668..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 @@ -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; @@ -42,6 +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)); + 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 601567ef9..b9f2bc2ba 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 @@ -19,6 +19,7 @@ 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; @@ -84,8 +85,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 12add6726..0746ac06b 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/function/visitor/BreadthFirstSearch.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java index e7b678d27..eb037d381 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 @@ -39,6 +39,9 @@ import com.sk89q.worldedit.util.Direction; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; import java.util.List; /** @@ -82,12 +85,12 @@ public abstract class BreadthFirstSearch implements Operation { } private final RegionFunction function; + private BlockVector3[] directions; private BlockVectorSet visited; private final MappedFaweQueue mFaweQueue; private BlockVectorSet queue; private int currentDepth = 0; private final int maxDepth; - private List directions = new ArrayList<>(); private int affected = 0; private int maxBranch = Integer.MAX_VALUE; @@ -114,21 +117,16 @@ 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])); } /** @@ -139,34 +137,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.UNIT_MINUS_Y); - directions.add(BlockVector3.UNIT_Y); - directions.add(BlockVector3.UNIT_MINUS_X); - directions.add(BlockVector3.UNIT_X); - directions.add(BlockVector3.UNIT_MINUS_Z); - directions.add(BlockVector3.UNIT_Z); + public void addAxes() { + HashSet set = new HashSet<>(Arrays.asList(directions)); + set.add(BlockVector3.UNIT_MINUS_Y); + set.add(BlockVector3.UNIT_Y); + set.add(BlockVector3.UNIT_MINUS_X); + set.add(BlockVector3.UNIT_X); + set.add(BlockVector3.UNIT_MINUS_Z); + set.add(BlockVector3.UNIT_Z); + setDirections(set); } /** * Add the diagonal directions as directions to visit. */ - protected void addDiagonal() { - directions.add(Direction.NORTHEAST.toBlockVector()); - directions.add(Direction.SOUTHEAST.toBlockVector()); - directions.add(Direction.SOUTHWEST.toBlockVector()); - directions.add(Direction.NORTHWEST.toBlockVector()); + public void addDiagonal() { + HashSet set = new HashSet<>(Arrays.asList(directions)); + set.add(Direction.NORTHEAST.toBlockVector()); + set.add(Direction.SOUTHEAST.toBlockVector()); + set.add(Direction.SOUTHWEST.toBlockVector()); + set.add(Direction.NORTHWEST.toBlockVector()); + setDirections(set); } /** @@ -207,21 +207,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 @@ -245,7 +230,9 @@ public abstract class BreadthFirstSearch implements Operation { @Override public Operation resume(RunContext run) throws WorldEditException { MutableBlockVector3 mutable = new MutableBlockVector3(); - IntegerTrio[] dirs = getIntDirections(); +// MutableBlockVector3 mutable2 = new MutableBlockVector3(); + boolean shouldTrim = false; + BlockVector3[] dirs = directions; BlockVectorSet tempQueue = new BlockVectorSet(); BlockVectorSet chunkLoadSet = new BlockVectorSet(); for (currentDepth = 0; !queue.isEmpty() && currentDepth <= maxDepth; currentDepth++) { @@ -253,11 +240,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; } @@ -274,13 +261,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, mutable.setComponents(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 e20007841..33a1dde10 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 @@ -57,13 +57,13 @@ public class DownwardVisitor extends RecursiveVisitor { this.baseY = baseY; - Collection directions = getDirections(); - directions.clear(); - directions.add(BlockVector3.UNIT_X); - directions.add(BlockVector3.UNIT_MINUS_X); - directions.add(BlockVector3.UNIT_Z); - directions.add(BlockVector3.UNIT_MINUS_Z); - directions.add(BlockVector3.UNIT_MINUS_Y); + setDirections( + BlockVector3.UNIT_X, + BlockVector3.UNIT_MINUS_X, + BlockVector3.UNIT_Z, + BlockVector3.UNIT_MINUS_Z, + BlockVector3.UNIT_MINUS_Y + ); } @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 cc74ffce7..e932d8c2d 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 @@ -44,13 +44,13 @@ 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.UNIT_X); - directions.add(BlockVector3.UNIT_MINUS_X); - directions.add(BlockVector3.UNIT_Z); - directions.add(BlockVector3.UNIT_MINUS_Z); - directions.add(BlockVector3.UNIT_MINUS_Y); + setDirections( + BlockVector3.UNIT_X, + BlockVector3.UNIT_MINUS_X, + BlockVector3.UNIT_Z, + BlockVector3.UNIT_MINUS_Z, + BlockVector3.UNIT_MINUS_Y + ); } } 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..96ce3ca37 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/ScanChunk.java @@ -0,0 +1,342 @@ +package com.sk89q.worldedit.function.visitor; + +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.objects.ObjectIterator; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; + +/** + * 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 visits; + private final Long2ObjectOpenHashMap queues; + + public ScanChunk(final RegionFunction function) { + this.function = function; + this.directions = DEFAULT_DIRECTIONS; + + this.queues = new Long2ObjectOpenHashMap<>(); + this.visits = 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 = visits.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)) { + push(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[][] arrs = visits.get(pair); + if (arrs == null) { + visits.put(pair, arrs = new long[16][]); + } + int layer = y >> 4; + long[] section = arrs[layer]; + if (section == null) { + arrs[layer] = section = new long[64]; + } + set(section, getLocalIndex(x & 15, y & 15, z & 15)); + } + + 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); + 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; + } + } + + 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); +// // 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)); + } + + 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) (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 8fb8da940..68ac4d813 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,43 +22,43 @@ 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; /** * 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 UNIT_MINUS_X = new BlockVector3(-1, 0, 0); - public static final BlockVector3 UNIT_MINUS_Y = new BlockVector3(0, -1, 0); - public static final BlockVector3 UNIT_MINUS_Z = new BlockVector3(0, 0, -1); - public static final BlockVector3 ONE = new BlockVector3(1, 1, 1); + public static final BlockVector3 ZERO = BlockVector3.at(0, 0, 0); + public static final BlockVector3 UNIT_X = BlockVector3.at(1, 0, 0); + public static final BlockVector3 UNIT_Y = BlockVector3.at(0, 1, 0); + public static final BlockVector3 UNIT_Z = BlockVector3.at(0, 0, 1); + public static final BlockVector3 UNIT_MINUS_X = BlockVector3.at(-1, 0, 0); + public static final BlockVector3 UNIT_MINUS_Y = BlockVector3.at(0, -1, 0); + public static final BlockVector3 UNIT_MINUS_Z = BlockVector3.at(0, 0, -1); + public static final BlockVector3 ONE = BlockVector3.at(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) -> { - //noinspection SuspiciousNameCombination - 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. @@ -67,24 +67,7 @@ public class BlockVector3 { * 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) { @@ -96,37 +79,71 @@ 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); } + 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. * * @return the x coordinate */ - public int getX() { - return x; - } + public abstract int getX(); /** * Get the X coordinate. @@ -134,7 +151,7 @@ public class BlockVector3 { * @return the x coordinate */ public int getBlockX() { - return x; + return getX(); } /** @@ -144,7 +161,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()); } /** @@ -152,9 +169,7 @@ public class BlockVector3 { * * @return the y coordinate */ - public int getY() { - return y; - } + public abstract int getY(); /** * Get the Y coordinate. @@ -162,7 +177,7 @@ public class BlockVector3 { * @return the y coordinate */ public int getBlockY() { - return y; + return getY(); } /** @@ -172,7 +187,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()); } /** @@ -180,9 +195,7 @@ public class BlockVector3 { * * @return the z coordinate */ - public int getZ() { - return z; - } + public abstract int getZ(); /** * Get the Z coordinate. @@ -190,7 +203,7 @@ public class BlockVector3 { * @return the z coordinate */ public int getBlockZ() { - return z; + return getZ(); } /** @@ -200,7 +213,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); } /** @@ -210,7 +223,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()); } /** @@ -222,7 +235,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); } /** @@ -233,12 +246,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); @@ -252,7 +265,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()); } /** @@ -265,7 +278,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); } /** @@ -276,12 +289,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); @@ -294,7 +307,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()); } /** @@ -306,7 +319,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); } /** @@ -316,12 +329,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); @@ -344,7 +357,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()); } /** @@ -356,7 +369,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); } /** @@ -384,7 +397,7 @@ public class BlockVector3 { * @return length, squared */ public int lengthSq() { - return x * x + y * y + z * z; + return getX() * getX() + getY() * getY() + getZ() * getZ(); } /** @@ -404,9 +417,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; } @@ -418,9 +431,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); } @@ -431,7 +444,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(); } /** @@ -441,10 +454,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() ); } @@ -456,7 +469,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(); } /** @@ -468,11 +481,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; } @@ -516,7 +529,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())); } /** @@ -532,8 +545,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; @@ -541,7 +554,7 @@ public class BlockVector3 { return BlockVector3.at( x2 + aboutX + translateX, - y, + getY(), z2 + aboutZ + translateZ ); } @@ -587,10 +600,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()) ); } @@ -601,44 +614,110 @@ 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()) ); } + /* + 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. * * @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..dd7399c64 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3Imp.java @@ -0,0 +1,92 @@ +/* + * 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 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); + 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 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 88eb28a71..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,25 +1,37 @@ package com.sk89q.worldedit.math; +import com.boydti.fawe.FaweCache; + public class MutableBlockVector3 extends BlockVector3 { - private static ThreadLocal MUTABLE_CACHE = ThreadLocal.withInitial(() -> new MutableBlockVector3()); + 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); + return FaweCache.MUTABLE_BLOCKVECTOR3.get().setComponents(x, y, z); } 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 @@ -30,6 +42,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/math/MutableVector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableVector3.java index 27edc3437..27c9fd75f 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,7 +1,17 @@ package com.sk89q.worldedit.math; +import com.boydti.fawe.FaweCache; + 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/regions/CuboidRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java index e78422cd8..8e3840772 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,6 +19,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.boydti.fawe.config.Settings; import com.boydti.fawe.object.collection.BlockVectorSet; import com.sk89q.worldedit.math.BlockVector2; @@ -394,14 +399,8 @@ 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); - } - @NotNull @Override + @Override public Iterator iterator() { if (Settings.IMP.HISTORY.COMPRESSION_LEVEL >= 9 || useOldIterator) { return iterator_old(); @@ -612,5 +611,50 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { return new CuboidRegion(origin.subtract(size), origin.add(size)); } + @Override + public int getMinY() { + return minY; + } + @Override + public int getMaxY() { + return maxY; + } + + @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); + } + } } 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 263c2b2a1..ae33ef8c8 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 @@ -20,6 +20,12 @@ 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.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; @@ -287,26 +293,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; } - //todo the following lines can possibly be removed and replaced with upstream - 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. * @@ -361,6 +363,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 @@ -380,4 +392,16 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { 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 c1184afb9..a84a1aa62 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 @@ -19,6 +19,13 @@ 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.util.MathMan; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; @@ -44,6 +51,7 @@ public class EllipsoidRegion extends AbstractRegion { private Vector3 radius; private Vector3 radiusSqr; + private Vector3 inverseRadius; private int radiusLengthSqr; private boolean sphere; @@ -184,6 +192,7 @@ public class EllipsoidRegion extends AbstractRegion { } else { this.sphere = false; } + inverseRadius = Vector3.ONE.divide(radius); } @Override @@ -210,30 +219,50 @@ public class EllipsoidRegion extends AbstractRegion { return chunks; } + @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 = z - center.getBlockZ(); + int cz2 = cz * cz; + if (cz2 > radiusSqr.getBlockZ()) { + return false; + } + int cy = y - center.getBlockY(); + int cy2 = cy * cy; + if (radiusSqr.getBlockY() < 255 && cy2 > radiusSqr.getBlockY()) { + return false; + } + if (sphere) { + return cx2 + cy2 + cz2 <= radiusLengthSqr; + } + double cxd = cx2 * inverseRadius.getX(); + double cyd = cy2 * inverseRadius.getY(); + double czd = cz2 * inverseRadius.getZ(); + return cxd + cyd + czd <= 1; + } + @Override - public boolean contains(BlockVector3 position) { - int cx = position.getBlockX() - center.getBlockX(); + public boolean contains(int x, 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 cy2 = cy * cy; - if (radiusSqr.getBlockY() < 255 && cy2 > radiusSqr.getBlockY()) { - return false; - } if (sphere) { - return cx2 + cy2 + cz2 <= radiusLengthSqr; + return cx2 + cz2 <= radiusLengthSqr; } - double cxd = (double) cx / radius.getBlockX(); - double cyd = (double) cy / radius.getBlockY(); - double czd = (double) cz / radius.getBlockZ(); - return cxd * cxd + cyd * cyd + czd * czd <= 1; + double cxd = cx2 * inverseRadius.getX(); + double czd = cz2 * inverseRadius.getZ(); + return cxd + czd <= 1; } /** @@ -256,4 +285,113 @@ 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 - cx; + int cx2 = tx - cx; + 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 - cz; + int cz2 = tz - cz; + 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) { + // Does not contain chunk + if (cxMin2 + czMin2 >= radiusLengthSqr) { + return; + } + int diffY2 = radiusLengthSqr - cxMax2 - czMax2; + // (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); + } + + if (yTopFull != 255) { + int yTopPartial = Math.min(255, cy + diffYPartial); + filterSpherePartial(yTopFull + 1, yTopPartial - 1, bx, bz, filter, block, get, set); + } + } + } + + + } else { + super.filter(chunk, filter, block, get, set); // TODO optimize non spheres + } + } } 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 4076c6cd0..c3dc4d55a 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,12 +19,20 @@ 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; 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; @@ -128,7 +136,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. @@ -172,4 +182,63 @@ public interface Region extends Iterable, Cloneable { * @return the points. */ List polygonize(int maxPoints); + + default int getMinY() { + return getMinimumPoint().getY(); + } + + 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 9442deaca..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,9 +19,6 @@ package com.sk89q.worldedit.regions; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - import com.google.common.collect.Iterators; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.World; @@ -31,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/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..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 @@ -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; 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 271c356ed..066bc7ea9 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,17 +20,16 @@ package com.sk89q.worldedit.world; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.extension.platform.Platform; -import com.sk89q.worldedit.function.mask.BlockTypeMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.util.Direction; -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; @@ -63,7 +62,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 @@ -90,11 +89,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/NullWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java index c3ef611d8..ff1ac5edc 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 @@ -81,12 +81,12 @@ public class NullWorld extends AbstractWorld { } @Override - public BiomeType getBiome(BlockVector2 position) { + public BiomeType getBiomeType(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; } @@ -132,13 +132,18 @@ public class NullWorld extends AbstractWorld { } @Override - public BlockState getBlock(BlockVector3 position) { + public BlockState getBlock(int x, int y, int z) { return BlockTypes.AIR.getDefaultState(); } @Override - public BlockState getLazyBlock(BlockVector3 position) { - return getBlock(position); + public BaseBlock getFullBlock(int x, int y, int z) { + return BlockTypes.AIR.getDefaultState().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 c6040cd60..04e7d05c1 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 @@ -61,7 +61,7 @@ public interface SimpleWorld extends World { @Override default BaseBlock getFullBlock(BlockVector3 position) { - return getLazyBlock(position).toBaseBlock(); + return getBlock(position).toBaseBlock(); } @Override @@ -74,7 +74,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 0b0997992..c6d7b82e5 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 @@ -45,9 +45,8 @@ import java.util.Objects; * may be missing.

*/ public class BaseBlock implements BlockStateHolder { - - private BlockState blockState; - @Nullable protected CompoundTag nbtData; + private final BlockState blockState; + private final CompoundTag nbtData; @Deprecated public BaseBlock() { @@ -70,6 +69,7 @@ public class BaseBlock implements BlockStateHolder { */ public BaseBlock(BlockState blockState) { this.blockState = blockState; + nbtData = null; } /** @@ -180,7 +180,7 @@ public class BaseBlock implements BlockStateHolder { @Override public void setNbtData(@Nullable CompoundTag nbtData) { - this.nbtData = nbtData; + throw new UnsupportedOperationException("Immutable"); } /** @@ -232,7 +232,12 @@ public class BaseBlock implements BlockStateHolder { } @Override - public BaseBlock toBaseBlock() { + public final char getOrdinalChar() { + return blockState.getOrdinalChar(); + } + + @Override + public final BaseBlock toBaseBlock() { return this; } @@ -247,6 +252,10 @@ public class BaseBlock implements BlockStateHolder { } } + public BlockState toBlockState() { + return blockState; + } + @Override public int hashCode() { return getOrdinal(); @@ -254,7 +263,8 @@ 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 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/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index 4fe002ee7..389f8f5ed 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; @@ -49,6 +50,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; @@ -57,7 +59,8 @@ public class BlockState implements BlockStateHolder, FawePattern { this.blockType = blockType; this.internalId = internalId; this.ordinal = ordinal; - this.emptyBaseBlock = new BaseBlock(this); + this.ordinalChar = (char) ordinal; + this.emptyBaseBlock = new ImmutableBaseBlock(this); } /** @@ -215,7 +218,7 @@ public class BlockState implements BlockStateHolder, FawePattern { } @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - return extent.setBlock(set, this); + return set.setBlock(extent, this); } @Override @@ -261,6 +264,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 Map, Object> getStates() { BlockType type = this.getBlockType(); @@ -327,10 +348,15 @@ public class BlockState implements BlockStateHolder, FawePattern { return material; } - @Override - public int getOrdinal() { - return this.ordinal; - } + @Override + public final 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 eed1c68eb..5b8e12032 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 @@ -64,6 +64,9 @@ public interface BlockStateHolder> extends FawePat @Deprecated int getOrdinal(); + @Deprecated + char getOrdinalChar(); + BlockMaterial getMaterial(); /** * Get type id (legacy uses) 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 cf2f0a8dc..1e1d4a823 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,7 +21,6 @@ package com.sk89q.worldedit.world.block; import static com.google.common.base.Preconditions.checkArgument; -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 +32,12 @@ import com.sk89q.worldedit.registry.Keyed; 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; @@ -181,10 +178,15 @@ public class BlockType implements FawePattern, Keyed { * * @return The default state */ - public BlockState getDefaultState() { + public final BlockState getDefaultState() { return this.settings.defaultState; } + /** + * @Deprecated use a Mask instead + * @return + */ + @Deprecated public FuzzyBlockState getFuzzyMatcher() { // return new FuzzyBlockState(this); } @@ -296,7 +298,7 @@ public class BlockType implements FawePattern, Keyed { @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - return extent.setBlock(set, this.getDefaultState()); + return set.setBlock(extent, getDefaultState()); } @Override 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 dcf1baba6..db7f2443d 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 @@ -52,6 +52,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; @@ -66,7 +70,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; @@ -150,7 +153,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; @@ -615,7 +617,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; 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..708e9c70e --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/ImmutableBaseBlock.java @@ -0,0 +1,50 @@ +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 com.sk89q.worldedit.registry.state.Property; + +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 String getNbtId() { + return ""; + } + + @Override + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + return set.setBlock(extent, toBlockState()); + } + + @Override + public BaseBlock with(Property property, V value) { + return toImmutableState().with(property, value).toBaseBlock(); + } + + @Override + public BaseBlock toBaseBlock(CompoundTag compoundTag) { + if (compoundTag != null) { + return new BaseBlock(this.toImmutableState(), compoundTag); + } + return this; + } +} diff --git a/worldedit-core/src/main/java/net/jpountz/util/UnsafeUtils.java b/worldedit-core/src/main/java/net/jpountz/util/UnsafeUtils.java new file mode 100644 index 000000000..665616011 --- /dev/null +++ b/worldedit-core/src/main/java/net/jpountz/util/UnsafeUtils.java @@ -0,0 +1,151 @@ +package net.jpountz.util; + +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.lang.reflect.Field; +import java.nio.ByteOrder; +import sun.misc.Unsafe; + + +import static net.jpountz.util.Utils.NATIVE_BYTE_ORDER; + +public enum UnsafeUtils { + ; + + private static final Unsafe UNSAFE; + private static final long BYTE_ARRAY_OFFSET; + private static final int BYTE_ARRAY_SCALE; + private static final long INT_ARRAY_OFFSET; + private static final int INT_ARRAY_SCALE; + private static final long SHORT_ARRAY_OFFSET; + private static final int SHORT_ARRAY_SCALE; + + static { + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + UNSAFE = (Unsafe) theUnsafe.get(null); + BYTE_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(byte[].class); + BYTE_ARRAY_SCALE = UNSAFE.arrayIndexScale(byte[].class); + INT_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(int[].class); + INT_ARRAY_SCALE = UNSAFE.arrayIndexScale(int[].class); + SHORT_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(short[].class); + SHORT_ARRAY_SCALE = UNSAFE.arrayIndexScale(short[].class); + } catch (IllegalAccessException e) { + throw new ExceptionInInitializerError("Cannot access Unsafe"); + } catch (NoSuchFieldException e) { + throw new ExceptionInInitializerError("Cannot access Unsafe"); + } catch (SecurityException e) { + throw new ExceptionInInitializerError("Cannot access Unsafe"); + } + } + + public static void checkRange(byte[] buf, int off) { + SafeUtils.checkRange(buf, off); + } + + public static void checkRange(byte[] buf, int off, int len) { + SafeUtils.checkRange(buf, off, len); + } + + public static void checkLength(int len) { + SafeUtils.checkLength(len); + } + + public static byte readByte(byte[] src, int srcOff) { + return UNSAFE.getByte(src, BYTE_ARRAY_OFFSET + BYTE_ARRAY_SCALE * srcOff); + } + + public static void writeByte(byte[] src, int srcOff, byte value) { + UNSAFE.putByte(src, BYTE_ARRAY_OFFSET + BYTE_ARRAY_SCALE * srcOff, (byte) value); + } + + public static void writeByte(byte[] src, int srcOff, int value) { + writeByte(src, srcOff, (byte) value); + } + + public static long readLong(byte[] src, int srcOff) { + return UNSAFE.getLong(src, BYTE_ARRAY_OFFSET + srcOff); + } + + public static long readLongLE(byte[] src, int srcOff) { + long i = readLong(src, srcOff); + if (NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) { + i = Long.reverseBytes(i); + } + return i; + } + + public static void writeLong(byte[] dest, int destOff, long value) { + UNSAFE.putLong(dest, BYTE_ARRAY_OFFSET + destOff, value); + } + + public static int readInt(byte[] src, int srcOff) { + return UNSAFE.getInt(src, BYTE_ARRAY_OFFSET + srcOff); + } + + public static int readIntLE(byte[] src, int srcOff) { + int i = readInt(src, srcOff); + if (NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) { + i = Integer.reverseBytes(i); + } + return i; + } + + public static void writeInt(byte[] dest, int destOff, int value) { + UNSAFE.putInt(dest, BYTE_ARRAY_OFFSET + destOff, value); + } + + public static short readShort(byte[] src, int srcOff) { + return UNSAFE.getShort(src, BYTE_ARRAY_OFFSET + srcOff); + } + + public static int readShortLE(byte[] src, int srcOff) { + short s = readShort(src, srcOff); + if (NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) { + s = Short.reverseBytes(s); + } + return s & 0xFFFF; + } + + public static void writeShort(byte[] dest, int destOff, short value) { + UNSAFE.putShort(dest, BYTE_ARRAY_OFFSET + destOff, value); + } + + public static void writeShortLE(byte[] buf, int off, int v) { + writeByte(buf, off, (byte) v); + writeByte(buf, off + 1, (byte) (v >>> 8)); + } + + public static int readInt(int[] src, int srcOff) { + return UNSAFE.getInt(src, INT_ARRAY_OFFSET + INT_ARRAY_SCALE * srcOff); + } + + public static void writeInt(int[] dest, int destOff, int value) { + UNSAFE.putInt(dest, INT_ARRAY_OFFSET + INT_ARRAY_SCALE * destOff, value); + } + + public static int readShort(short[] src, int srcOff) { + return UNSAFE.getShort(src, SHORT_ARRAY_OFFSET + SHORT_ARRAY_SCALE * srcOff) & 0xFFFF; + } + + 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; + } +}