some minor refactoring

This commit is contained in:
Jesse Boyd 2019-08-18 02:09:09 +01:00
parent d1af07b6ae
commit d434dfcfdd
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
64 changed files with 1892 additions and 812 deletions

View File

@ -13,16 +13,11 @@ import com.boydti.fawe.bukkit.util.BukkitTaskMan;
import com.boydti.fawe.bukkit.util.ItemUtil;
import com.boydti.fawe.bukkit.util.VaultUtil;
import com.boydti.fawe.bukkit.util.image.BukkitImageViewer;
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
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.Settings;
import com.boydti.fawe.object.FaweCommand;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.regions.FaweMaskManager;
import com.boydti.fawe.util.Jars;
import com.boydti.fawe.util.MainUtil;
@ -40,9 +35,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.WorldLoadEvent;
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;
@ -52,6 +49,9 @@ import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class FaweBukkit implements IFawe, Listener {
@ -279,102 +279,6 @@ public class FaweBukkit implements IFawe, Listener {
return new BukkitTaskMan(plugin);
}
private boolean hasNMS = true;
private boolean playerChunk = false;
@Override
public FaweQueue getNewQueue(String world, boolean fast) {
if (playerChunk != (playerChunk = true)) {
try {
Field fieldDirtyCount = BukkitReflectionUtils.getRefClass("{nms}.PlayerChunk").getField("dirtyCount").getRealField();
fieldDirtyCount.setAccessible(true);
int mod = fieldDirtyCount.getModifiers();
if ((mod & Modifier.VOLATILE) == 0) {
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(fieldDirtyCount, mod + Modifier.VOLATILE);
}
} catch (Throwable ignore) {}
}
try {
return getQueue(world);
} catch (Throwable throwable) {
// Disable incompatible settings
Settings.IMP.QUEUE.PARALLEL_THREADS = 1; // BukkitAPI placer is too slow to parallel thread at the chunk level
Settings.IMP.HISTORY.COMBINE_STAGES = false; // Performing a chunk copy (if possible) wouldn't be faster using the BukkitAPI
if (hasNMS) {
debug("====== NO NMS BLOCK PLACER FOUND ======");
debug("FAWE couldn't find a fast block placer");
debug("Bukkit version: " + Bukkit.getVersion());
debug("NMS label: " + plugin.getClass().getSimpleName().split("_")[1]);
debug("Fallback placer: " + BukkitQueue_All.class);
debug("=======================================");
debug("Download the version of FAWE for your platform");
debug(" - http://ci.athion.net/job/FastAsyncWorldEdit/lastSuccessfulBuild/artifact/target");
debug("=======================================");
throwable.printStackTrace();
debug("=======================================");
TaskManager.IMP.laterAsync(
() -> MainUtil.sendAdmin("&cNo NMS placer found, see console!"), 1);
hasNMS = false;
}
return new BukkitQueue_All(world);
}
}
/**
* The FaweQueue is a core part of block placement<br>
* - The queue returned here is used in the SetQueue class (SetQueue handles the implementation specific queue)<br>
* - Block changes are grouped by chunk (as it's more efficient for lighting/packet sending)<br>
* - The FaweQueue returned here will provide the wrapper around the chunk object (FaweChunk)<br>
* - When a block change is requested, the SetQueue will first check if the chunk exists in the queue, or it will create and add it<br>
*/
@Override
public FaweQueue getNewQueue(World world, boolean fast) {
if (fast) {
if (playerChunk != (playerChunk = true)) {
try {
Field fieldDirtyCount = BukkitReflectionUtils.getRefClass("{nms}.PlayerChunk").getField("dirtyCount").getRealField();
fieldDirtyCount.setAccessible(true);
int mod = fieldDirtyCount.getModifiers();
if ((mod & Modifier.VOLATILE) == 0) {
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(fieldDirtyCount, mod + Modifier.VOLATILE);
}
} catch (Throwable ignore) {
}
}
Throwable error;
try {
return getQueue(world);
} catch (Throwable throwable) {
error = throwable;
}
// Disable incompatible settings
Settings.IMP.QUEUE.PARALLEL_THREADS = 1; // BukkitAPI placer is too slow to parallel thread at the chunk level
Settings.IMP.HISTORY.COMBINE_STAGES = false; // Performing a chunk copy (if possible) wouldn't be faster using the BukkitAPI
if (hasNMS) {
debug("====== NO NMS BLOCK PLACER FOUND ======");
debug("FAWE couldn't find a fast block placer");
debug("Bukkit version: " + Bukkit.getVersion());
debug("NMS label: " + plugin.getClass().getSimpleName());
debug("Fallback placer: " + BukkitQueue_All.class);
debug("=======================================");
debug("Download the version of FAWE for your platform");
debug(" - http://ci.athion.net/job/FastAsyncWorldEdit/lastSuccessfulBuild/artifact/target");
debug("=======================================");
error.printStackTrace();
debug("=======================================");
TaskManager.IMP.laterAsync(
() -> MainUtil.sendAdmin("&cNo NMS placer found, see console!"), 1);
hasNMS = false;
}
}
return new BukkitQueue_All(world);
}
public Plugin getPlugin() {
return plugin;
}
@ -479,6 +383,25 @@ public class FaweBukkit implements IFawe, Listener {
return managers;
}
private volatile boolean keepUnloaded;
@EventHandler(priority = EventPriority.MONITOR)
public void onWorldLoad(WorldLoadEvent event) {
if (keepUnloaded) {
org.bukkit.World world = event.getWorld();
world.setKeepSpawnInMemory(false);
}
}
public synchronized <T> T createWorldUnloaded(Supplier<T> task) {
keepUnloaded = true;
try {
return task.get();
} finally {
keepUnloaded = false;
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
@ -520,51 +443,4 @@ public class FaweBukkit implements IFawe, Listener {
return null;
// return ((BlocksHubBukkit) blocksHubPlugin).getApi();
}
private Version version = null;
public Version getVersion() {
Version tmp = this.version;
if (tmp == null) {
tmp = Version.NONE;
for (Version v : Version.values()) {
try {
BukkitQueue_0.checkVersion(v.name());
this.version = tmp = v;
break;
} catch (IllegalStateException ignored) {}
}
}
return tmp;
}
public enum Version {
v1_14_R1,
v1_13_R2,
NONE,
}
private FaweQueue getQueue(World world) {
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);
}
}
private FaweQueue getQueue(String world) {
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);
}
}
}

View File

@ -1,54 +1,76 @@
package com.boydti.fawe.bukkit.beta;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.implementation.QueueHandler;
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.boydti.fawe.object.collection.BitArray4096;
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.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.internal.Constants;
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.BlockPosition;
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.Entity;
import net.minecraft.server.v1_14_R1.EntityTypes;
import net.minecraft.server.v1_14_R1.IBlockData;
import net.minecraft.server.v1_14_R1.World;
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 net.minecraft.server.v1_14_R1.WorldServer;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.craftbukkit.v1_14_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_14_R1.block.CraftBlock;
import org.bukkit.event.entity.CreatureSpawnEvent;
import java.util.Arrays;
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 BukkitGetBlocks extends CharGetBlocks {
public ChunkSection[] sections;
public Chunk nmsChunk;
public World nmsWorld;
public CraftWorld world;
public int X, Z;
private boolean forceLoad;
public BukkitGetBlocks(World nmsWorld, int X, int Z, boolean forceLoad) {
this.nmsWorld = nmsWorld;
public BukkitGetBlocks(World world, int X, int Z, boolean forceLoad) {
this.world = (CraftWorld) world;
this.X = X;
this.Z = Z;
if (forceLoad) {
((WorldServer) nmsWorld).setForceLoaded(X, Z, this.forceLoad = true);
this.world.getHandle().setForceLoaded(X, Z, this.forceLoad = true);
}
}
@Override
protected void finalize() {
if (forceLoad) {
((WorldServer) nmsWorld).setForceLoaded(X, Z, forceLoad = false);
this.world.getHandle().setForceLoaded(X, Z, forceLoad = false);
}
}
@ -69,14 +91,310 @@ public class BukkitGetBlocks extends CharGetBlocks {
return load(layer, null);
}
private void updateGet(BukkitGetBlocks get, Chunk nmsChunk, ChunkSection[] sections, ChunkSection section, char[] arr, int layer) {
synchronized (get) {
if (this.nmsChunk != nmsChunk) {
this.nmsChunk = nmsChunk;
this.sections = sections.clone();
this.reset();
}
if (this.sections == null) {
this.sections = sections.clone();
}
if (this.sections[layer] != section) {
this.sections[layer] = section;
}
this.blocks[layer] = arr;
}
}
private void removeEntity(Entity entity) {
entity.die();
entity.valid = false;
}
@Override
public <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
try {
WorldServer nmsWorld = world.getHandle();
Chunk nmsChunk = BukkitQueue.ensureLoaded(nmsWorld, X, Z);
// Remove existing tiles
{
Map<BlockPosition, TileEntity> tiles = nmsChunk.getTileEntities();
if (!tiles.isEmpty()) {
final Iterator<Map.Entry<BlockPosition, TileEntity>> iterator = tiles.entrySet().iterator();
while (iterator.hasNext()) {
final Map.Entry<BlockPosition, TileEntity> 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.n();
tile.invalidateBlockCache();
}
}
}
}
int bitMask = 0;
synchronized (nmsChunk) {
ChunkSection[] sections = nmsChunk.getSections();
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 = BukkitQueue.newChunkSection(layer, setArr);
if (BukkitQueue.setSectionAtomic(sections, null, newSection, layer)) {
updateGet(this, 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 (this) {
synchronized (lock) {
lock.untilFree();
ChunkSection getSection;
if (this.nmsChunk != nmsChunk) {
this.nmsChunk = nmsChunk;
this.sections = null;
this.reset();
} else {
getSection = this.getSections()[layer];
if (getSection != existingSection) {
this.sections[layer] = existingSection;
this.reset();
} else if (lock.isModified()) {
this.reset(layer);
}
}
char[] getArr = this.load(layer);
for (int i = 0; i < 4096; i++) {
char value = setArr[i];
if (value != 0) {
getArr[i] = value;
}
}
newSection = BukkitQueue.newChunkSection(layer, getArr);
if (!BukkitQueue.setSectionAtomic(sections, existingSection, newSection, layer)) {
System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer);
continue;
} else {
updateGet(this, 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;
int bx = X << 4;
int bz = Z << 4;
Set<UUID> 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<Entity>[] entities = nmsChunk.getEntitySlices();
for (int i = 0; i < entities.length; i++) {
final Collection<Entity> ents = entities[i];
if (!ents.isEmpty()) {
final Iterator<Entity> iter = ents.iterator();
while (iter.hasNext()) {
final Entity entity = iter.next();
if (entityRemoves.contains(entity.getUniqueID())) {
iter.remove();
removeEntity(entity);
}
}
}
}
}
};
}
Set<CompoundTag> 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<String, Tag> 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();
EntityTypes<?> type = EntityTypes.a(id).orElse(null);
if (type != null) {
Entity entity = type.a(nmsWorld);
if (entity != null) {
UUID uuid = entity.getUniqueID();
entityTagMap.put("UUIDMost", new LongTag(uuid.getMostSignificantBits()));
entityTagMap.put("UUIDLeast", new LongTag(uuid.getLeastSignificantBits()));
if (nativeTag != null) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
final NBTTagCompound tag = (NBTTagCompound) adapter.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<Short, CompoundTag> 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<Short, CompoundTag> 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 (nmsWorld) {
TileEntity tileEntity = nmsWorld.getTileEntity(pos);
if (tileEntity == null || tileEntity.isRemoved()) {
nmsWorld.removeTileEntity(pos);
tileEntity = nmsWorld.getTileEntity(pos);
}
if (tileEntity != null) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
final NBTTagCompound tag = (NBTTagCompound) adapter.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.d(true); // Set Modified
nmsChunk.mustNotSave = false;
nmsChunk.markDirty();
// send to player
BukkitQueue.sendChunk(nmsWorld, X, Z, finalMask);
if (finalizer != null) finalizer.run();
};
}
if (syncTasks != null) {
QueueHandler queueHandler = Fawe.get().getQueueHandler();
Runnable[] finalSyncTasks = syncTasks;
// Chain the sync tasks and the callback
Callable<Future> chain = new Callable<Future>() {
@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) {
if (finalizer != null) finalizer.run();
return null;
} else {
return queueHandler.async(callback, null);
}
}
};
return (T) (Future) queueHandler.sync(chain);
} else {
if (callback == null) {
if (finalizer != null) finalizer.run();
} else {
callback.run();
}
}
}
return null;
} catch (Throwable e) {
e.printStackTrace();
return 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;
return FaweCache.IMP.EMPTY_CHAR_4096;
}
if (data == null || data == FaweCache.EMPTY_CHAR_4096) {
if (data == null || data == FaweCache.IMP.EMPTY_CHAR_4096) {
data = new char[4096];
}
DelegateLock lock = BukkitQueue.applyLock(section);
@ -88,8 +406,8 @@ public class BukkitGetBlocks extends CharGetBlocks {
Spigot_v1_14_R1 adapter = ((Spigot_v1_14_R1) WorldEditPlugin.getInstance().getBukkitImplAdapter());
final DataPaletteBlock<IBlockData> blocks = section.getBlocks();
final DataBits bits = (DataBits) BukkitQueue_1_14.fieldBits.get(blocks);
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitQueue_1_14.fieldPalette.get(blocks);
final DataBits bits = (DataBits) BukkitQueue.fieldBits.get(blocks);
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitQueue.fieldPalette.get(blocks);
final int bitsPerEntry = bits.c();
final long[] blockStates = bits.a();
@ -103,8 +421,8 @@ public class BukkitGetBlocks extends CharGetBlocks {
num_palette = ((DataPaletteHash<IBlockData>) palette).b();
} else {
num_palette = 0;
int[] paletteToBlockInts = FaweCache.PALETTE_TO_BLOCK.get();
char[] paletteToBlockChars = FaweCache.PALETTE_TO_BLOCK_CHAR.get();
int[] paletteToBlockInts = FaweCache.IMP.PALETTE_TO_BLOCK.get();
char[] paletteToBlockChars = FaweCache.IMP.PALETTE_TO_BLOCK_CHAR.get();
try {
for (int i = 0; i < 4096; i++) {
char paletteVal = data[i];
@ -130,7 +448,7 @@ public class BukkitGetBlocks extends CharGetBlocks {
return data;
}
char[] paletteToBlockChars = FaweCache.PALETTE_TO_BLOCK_CHAR.get();
char[] paletteToBlockChars = FaweCache.IMP.PALETTE_TO_BLOCK_CHAR.get();
try {
final int size = num_palette;
if (size != 1) {
@ -188,7 +506,7 @@ public class BukkitGetBlocks extends CharGetBlocks {
synchronized (this) {
tmp = nmsChunk;
if (tmp == null) {
nmsChunk = tmp = BukkitQueue.ensureLoaded(nmsWorld, X, Z);
nmsChunk = tmp = BukkitQueue.ensureLoaded(this.world.getHandle(), X, Z);
}
}
}

View File

@ -2,15 +2,18 @@ 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.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.implementation.SimpleCharQueueExtent;
import com.boydti.fawe.beta.implementation.WorldChunkCache;
import com.boydti.fawe.beta.implementation.IChunkCache;
import com.boydti.fawe.bukkit.v1_14.adapter.BlockMaterial_1_14;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.collection.BitArray4096;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.wrappers.WorldWrapper;
import com.sk89q.worldedit.bukkit.BukkitWorld;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockID;
import com.sk89q.worldedit.world.block.BlockState;
@ -42,30 +45,19 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.locks.Lock;
import java.util.function.Supplier;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkNotNull;
public class BukkitQueue extends SimpleCharQueueExtent {
private org.bukkit.World bukkitWorld;
private WorldServer nmsWorld;
@Override
public void enableQueue() {
public BukkitQueue() {
}
@Override
public void disableQueue() {
}
@Override
public synchronized void init(WorldChunkCache cache) {
World world = cache.getWorld();
public synchronized void init(Extent extent, IChunkCache<IChunkGet> get, IChunkCache<IChunkSet> set) {
World world = WorldWrapper.unwrap(extent);
if (world == null) throw new IllegalArgumentException("Get must be a world.");
if (world instanceof BukkitWorld) {
this.bukkitWorld = ((BukkitWorld) world).getWorld();
} else {
@ -74,15 +66,7 @@ public class BukkitQueue extends SimpleCharQueueExtent {
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;
super.init(extent, get, set);
}
@Override
@ -90,22 +74,6 @@ public class BukkitQueue extends SimpleCharQueueExtent {
super.reset();
}
// private static final IterableThreadLocal<BukkitFullChunk> FULL_CHUNKS = new IterableThreadLocal<BukkitFullChunk>() {
// @Override
// public BukkitFullChunk init() {
// return new BukkitFullChunk();
// }
// };
@Override
public IChunk create(boolean isFull) {
// if (full) {
// //TODO implement
// return FULL_CHUNKS.get();
// }
return new BukkitChunkHolder();
}
/*
NMS fields
*/
@ -235,7 +203,7 @@ public class BukkitQueue extends SimpleCharQueueExtent {
return TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(X, Z));
}
private PlayerChunk getPlayerChunk(final int cx, final int cz) {
private static PlayerChunk getPlayerChunk(net.minecraft.server.v1_14_R1.WorldServer nmsWorld, final int cx, final int cz) {
PlayerChunkMap chunkMap = nmsWorld.getChunkProvider().playerChunkMap;
PlayerChunk playerChunk = chunkMap.visibleChunks.get(ChunkCoordIntPair.pair(cx, cz));
if (playerChunk == null) {
@ -244,9 +212,8 @@ public class BukkitQueue extends SimpleCharQueueExtent {
return playerChunk;
}
@Override
public void sendChunk(final int X, final int Z, final int mask) {
PlayerChunk playerChunk = getPlayerChunk(X, Z);
public static void sendChunk(net.minecraft.server.v1_14_R1.WorldServer nmsWorld, int X, int Z, int mask) {
PlayerChunk playerChunk = getPlayerChunk(nmsWorld, X, Z);
if (playerChunk == null) {
return;
}
@ -256,7 +223,7 @@ public class BukkitQueue extends SimpleCharQueueExtent {
// sections[layer] = new ChunkSection(layer << 4);
// }
// }
if (playerChunk.k()) {
if (playerChunk.hasBeenLoaded()) {
TaskManager.IMP.sync(new Supplier<Object>() {
@Override
public Object get() {
@ -284,6 +251,11 @@ public class BukkitQueue extends SimpleCharQueueExtent {
return;
}
@Override
public void sendChunk(final int X, final int Z, final int mask) {
sendChunk(nmsWorld, X, Z, mask);
}
/*
NMS conversion
*/
@ -293,10 +265,10 @@ public class BukkitQueue extends SimpleCharQueueExtent {
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();
final int[] blockToPalette = FaweCache.IMP.BLOCK_TO_PALETTE.get();
final int[] paletteToBlock = FaweCache.IMP.PALETTE_TO_BLOCK.get();
final long[] blockStates = FaweCache.IMP.BLOCK_STATES.get();
final int[] blocksCopy = FaweCache.IMP.SECTION_BLOCKS.get();
try {
int num_palette = 0;
int air = 0;

View File

@ -1,11 +1,78 @@
package com.boydti.fawe.bukkit.beta;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.beta.IQueueExtent;
import com.boydti.fawe.beta.implementation.QueueHandler;
import com.boydti.fawe.bukkit.v0.ChunkListener;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class BukkitQueueHandler extends QueueHandler {
@Override
public IQueueExtent create() {
return new BukkitQueue();
}
}
private volatile boolean timingsEnabled;
private static boolean alertTimingsChange = true;
private static Field fieldTimingsEnabled;
private static Field fieldAsyncCatcherEnabled;
private static Method methodCheck;
static {
try {
fieldAsyncCatcherEnabled = Class.forName("org.spigotmc.AsyncCatcher").getField("enabled");
fieldAsyncCatcherEnabled.setAccessible(true);
} catch (Throwable ignore) {}
try {
fieldTimingsEnabled = Class.forName("co.aikar.timings.Timings").getDeclaredField("timingsEnabled");
fieldTimingsEnabled.setAccessible(true);
methodCheck = Class.forName("co.aikar.timings.TimingsManager").getDeclaredMethod("recheckEnabled");
methodCheck.setAccessible(true);
} catch (Throwable ignore){}
}
@Override
public void startSet(boolean parallel) {
ChunkListener.physicsFreeze = true;
if (parallel) {
try {
if (fieldAsyncCatcherEnabled != null) {
fieldAsyncCatcherEnabled.set(null, false);
}
if (fieldTimingsEnabled != null) {
timingsEnabled = (boolean) fieldTimingsEnabled.get(null);
if (timingsEnabled) {
if (alertTimingsChange) {
alertTimingsChange = false;
Fawe.debug("Having `parallel-threads` > 1 interferes with the timings.");
}
fieldTimingsEnabled.set(null, false);
methodCheck.invoke(null);
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}
@Override
public void endSet(boolean parallel) {
ChunkListener.physicsFreeze = false;
if (parallel) {
try {
if (fieldAsyncCatcherEnabled != null) {
fieldAsyncCatcherEnabled.set(null, true);
}
if (fieldTimingsEnabled != null && timingsEnabled) {
fieldTimingsEnabled.set(null, true);
methodCheck.invoke(null);
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}
}

View File

@ -1,11 +1,11 @@
package com.boydti.fawe.bukkit.listener;
import com.boydti.fawe.beta.IQueueExtent;
import com.boydti.fawe.bukkit.util.image.BukkitImageViewer;
import com.boydti.fawe.command.CFICommands;
import com.boydti.fawe.object.brush.visualization.cfi.HeightMapMCAGenerator;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.brush.BrushSettings;
import com.boydti.fawe.object.extent.FastWorldEditExtent;
import com.boydti.fawe.util.EditSessionBuilder;
import com.boydti.fawe.util.ExtentTraverser;
import com.boydti.fawe.util.TaskManager;
@ -16,6 +16,7 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.command.tool.InvalidToolBindException;
import com.sk89q.worldedit.command.tool.brush.Brush;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@ -286,7 +287,8 @@ public class BukkitImageListener implements Listener {
.combineStages(false).autoQueue(false).blockBag(null).limitUnlimited()
.build();
ExtentTraverser last = new ExtentTraverser(es.getExtent()).last();
if (last.get() instanceof FastWorldEditExtent) {
Extent extent = last.get();
if (extent instanceof IQueueExtent) {
last = last.previous();
}
last.setNext(generator);

View File

@ -1,12 +1,9 @@
package com.boydti.fawe.bukkit.listener;
import com.boydti.fawe.command.CFICommands;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.RunnableVal3;
import com.boydti.fawe.object.brush.visualization.VirtualWorld;
import com.boydti.fawe.util.SetQueue;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
@ -58,98 +55,99 @@ public class CFIPacketListener implements Listener {
this.plugin = plugin;
this.protocolmanager = ProtocolLibrary.getProtocolManager();
// Direct digging to the virtual world
registerBlockEvent(PacketType.Play.Client.BLOCK_DIG, false, new RunnableVal3<PacketEvent, VirtualWorld, BlockVector3>() {
@Override
public void run(Builder event, URI gen, String pt) {
try {
Player plr = event.getPlayer();
BlockVector3 realPos = pt.add(gen.getOrigin().toBlockPoint());
if (!sendBlockChange(plr, gen, pt, Interaction.HIT)) {
gen.setBlock(pt, BlockTypes.AIR.getDefaultState());
}
} catch (WorldEditException e) {
e.printStackTrace();
}
}
});
// Direct placing to the virtual world
RunnableVal3<PacketEvent, VirtualWorld, BlockVector3> placeTask = new RunnableVal3<PacketEvent, VirtualWorld, BlockVector3>() {
@Override
public void run(Builder event, URI gen, String pt) {
try {
Player plr = event.getPlayer();
List<EnumWrappers.Hand> hands = event.getPacket().getHands().getValues();
EnumWrappers.Hand enumHand = hands.isEmpty() ? EnumWrappers.Hand.MAIN_HAND : hands.get(0);
PlayerInventory inv = plr.getInventory();
ItemStack hand = enumHand == EnumWrappers.Hand.MAIN_HAND ? inv.getItemInMainHand() : inv.getItemInOffHand();
if (hand.getType().isBlock()) {
Material type = hand.getType();
switch (type) {
case AIR:
case CAVE_AIR:
case VOID_AIR:
break;
default: {
BlockStateHolder block = BukkitAdapter.asBlockState(hand);
if (block != null) {
gen.setBlock(pt, block);
return;
}
}
}
}
pt = getRelPos(event, gen);
sendBlockChange(plr, gen, pt, Interaction.OPEN);
} catch (WorldEditException e) {
e.printStackTrace();
}
}
};
registerBlockEvent(PacketType.Play.Client.BLOCK_PLACE, true, placeTask);
registerBlockEvent(PacketType.Play.Client.USE_ITEM, true, placeTask);
// Cancel block change packets where the real world overlaps with the virtual one
registerBlockEvent(PacketType.Play.Server.BLOCK_CHANGE, false, new RunnableVal3<PacketEvent, VirtualWorld, BlockVector3>() {
@Override
public void run(Builder event, URI gen, String pt) {
// Do nothing
}
});
// Modify chunk packets where the real world overlaps with the virtual one
protocolmanager.addPacketListener(new PacketAdapter(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.MAP_CHUNK) {
@Override
public void onPacketSending(PacketEvent event) {
if (!event.isServerPacket()) return;
VirtualWorld gen = getGenerator(event);
if (gen != null) {
BlockVector3 origin = gen.getOrigin().toBlockPoint();
PacketContainer packet = event.getPacket();
StructureModifier<Integer> ints = packet.getIntegers();
int cx = ints.read(0);
int cz = ints.read(1);
int ocx = origin.getBlockX() >> 4;
int ocz = origin.getBlockZ() >> 4;
if (gen.contains(BlockVector3.at((cx - ocx) << 4, 0, (cz - ocz) << 4))) {
event.setCancelled(true);
Player plr = event.getPlayer();
FaweQueue queue = SetQueue.IMP.getNewQueue(plr.getWorld().getName(), true, false);
FaweChunk toSend = gen.getSnapshot(cx - ocx, cz - ocz);
toSend.setLoc(gen, cx, cz);
queue.sendChunkUpdate(toSend, FawePlayer.wrap(plr));
}
}
}
});
// TODO NOT IMPLEMENTED
// // Direct digging to the virtual world
// registerBlockEvent(PacketType.Play.Client.BLOCK_DIG, false, new RunnableVal3<PacketEvent, VirtualWorld, BlockVector3>() {
// @Override
// public void run(Builder event, URI gen, String pt) {
// try {
// Player plr = event.getPlayer();
// BlockVector3 realPos = pt.add(gen.getOrigin().toBlockPoint());
// if (!sendBlockChange(plr, gen, pt, Interaction.HIT)) {
// gen.setBlock(pt, BlockTypes.AIR.getDefaultState());
// }
// } catch (WorldEditException e) {
// e.printStackTrace();
// }
// }
// });
//
// // Direct placing to the virtual world
// RunnableVal3<PacketEvent, VirtualWorld, BlockVector3> placeTask = new RunnableVal3<PacketEvent, VirtualWorld, BlockVector3>() {
// @Override
// public void run(Builder event, URI gen, String pt) {
// try {
// Player plr = event.getPlayer();
// List<EnumWrappers.Hand> hands = event.getPacket().getHands().getValues();
//
// EnumWrappers.Hand enumHand = hands.isEmpty() ? EnumWrappers.Hand.MAIN_HAND : hands.get(0);
// PlayerInventory inv = plr.getInventory();
// ItemStack hand = enumHand == EnumWrappers.Hand.MAIN_HAND ? inv.getItemInMainHand() : inv.getItemInOffHand();
// if (hand.getType().isBlock()) {
// Material type = hand.getType();
// switch (type) {
// case AIR:
// case CAVE_AIR:
// case VOID_AIR:
// break;
// default: {
// BlockStateHolder block = BukkitAdapter.asBlockState(hand);
// if (block != null) {
// gen.setBlock(pt, block);
// return;
// }
// }
// }
// }
// pt = getRelPos(event, gen);
// sendBlockChange(plr, gen, pt, Interaction.OPEN);
// } catch (WorldEditException e) {
// e.printStackTrace();
// }
// }
// };
// registerBlockEvent(PacketType.Play.Client.BLOCK_PLACE, true, placeTask);
// registerBlockEvent(PacketType.Play.Client.USE_ITEM, true, placeTask);
//
// // Cancel block change packets where the real world overlaps with the virtual one
// registerBlockEvent(PacketType.Play.Server.BLOCK_CHANGE, false, new RunnableVal3<PacketEvent, VirtualWorld, BlockVector3>() {
// @Override
// public void run(Builder event, URI gen, String pt) {
// // Do nothing
// }
// });
//
// // Modify chunk packets where the real world overlaps with the virtual one
// protocolmanager.addPacketListener(new PacketAdapter(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.MAP_CHUNK) {
// @Override
// public void onPacketSending(PacketEvent event) {
// if (!event.isServerPacket()) return;
//
// VirtualWorld gen = getGenerator(event);
// if (gen != null) {
// BlockVector3 origin = gen.getOrigin().toBlockPoint();
// PacketContainer packet = event.getPacket();
// StructureModifier<Integer> ints = packet.getIntegers();
// int cx = ints.read(0);
// int cz = ints.read(1);
//
// int ocx = origin.getBlockX() >> 4;
// int ocz = origin.getBlockZ() >> 4;
//
// if (gen.contains(BlockVector3.at((cx - ocx) << 4, 0, (cz - ocz) << 4))) {
// event.setCancelled(true);
//
// Player plr = event.getPlayer();
//
// FaweQueue queue = SetQueue.IMP.getNewQueue(plr.getWorld().getName(), true, false);
//
// FaweChunk toSend = gen.getSnapshot(cx - ocx, cz - ocz);
// toSend.setLoc(gen, cx, cz);
// queue.sendChunkUpdate(toSend, FawePlayer.wrap(plr));
// }
// }
// }
// });
// The following few listeners are to ignore block collisions where the virtual and real world overlap

View File

@ -3,16 +3,12 @@ package com.boydti.fawe.bukkit.regions;
import com.boydti.fawe.bukkit.wrapper.AsyncBlock;
import com.boydti.fawe.bukkit.wrapper.AsyncWorld;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.queue.NullFaweQueue;
import com.boydti.fawe.regions.FaweMask;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.block.BlockTypes;
import jdk.nashorn.internal.ir.Block;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventException;
@ -21,7 +17,6 @@ import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.plugin.RegisteredListener;
import java.util.ArrayList;
import org.bukkit.util.BlockVector;
public class FreeBuildRegion extends BukkitMaskManager {
private final ArrayList<RegisteredListener> listeners;
@ -60,7 +55,7 @@ public class FreeBuildRegion extends BukkitMaskManager {
BlockVector3 pos1 = BlockVector3.ZERO;
BlockVector3 pos2 = BlockVector3.ZERO;
AsyncBlock block = new AsyncBlock(asyncWorld, new NullFaweQueue(asyncWorld.getWorldName(), BlockTypes.STONE.getDefaultState()), 0, 0, 0);
AsyncBlock block = new AsyncBlock(asyncWorld, 0, 0, 0);
BlockBreakEvent event = new BlockBreakEvent(block, BukkitAdapter.adapt(player.toWorldEditPlayer()));
return new FaweMask(pos1, pos2) {

View File

@ -1,10 +1,14 @@
package com.boydti.fawe.bukkit.util;
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
import com.boydti.fawe.bukkit.beta.BukkitQueue;
import com.boydti.fawe.util.ReflectionUtils;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import org.bukkit.inventory.ItemStack;
@ -13,6 +17,8 @@ import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import static com.google.gson.internal.$Gson$Preconditions.checkNotNull;
public class ItemUtil {
private final Method methodAsNMSCopy;
@ -21,10 +27,13 @@ public class ItemUtil {
private final Method methodSetTag;
private final Method methodAsBukkitCopy;
private final Field fieldHandle;
private final BukkitImplAdapter adapter;
private SoftReference<Int2ObjectOpenHashMap<WeakReference<Tag>>> hashToNMSTag = new SoftReference(new Int2ObjectOpenHashMap<>());
public ItemUtil() throws Exception {
this.adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
checkNotNull(adapter);
Class<?> classCraftItemStack = BukkitReflectionUtils.getCbClass("inventory.CraftItemStack");
Class<?> classNMSItem = BukkitReflectionUtils.getNmsClass("ItemStack");
this.methodAsNMSCopy = ReflectionUtils.setAccessible(classCraftItemStack.getDeclaredMethod("asNMSCopy", ItemStack.class));
@ -68,7 +77,7 @@ public class ItemUtil {
Tag nativeTag = nativeTagRef.get();
if (nativeTag != null) return (CompoundTag) nativeTag;
}
Tag nativeTag = BukkitQueue_0.toNative(nmsTag);
Tag nativeTag = adapter.toNative(nmsTag);
map.put(nmsTag.hashCode(), new WeakReference<>(nativeTag));
return null;
}
@ -86,7 +95,7 @@ public class ItemUtil {
copy = true;
nmsItem = methodAsNMSCopy.invoke(null, item);
}
Object nmsTag = BukkitQueue_0.fromNative(tag);
Object nmsTag = adapter.fromNative(tag);
methodSetTag.invoke(nmsItem, nmsTag);
if (copy) return (ItemStack) methodAsBukkitCopy.invoke(null, nmsItem);
return item;

View File

@ -382,7 +382,7 @@
// int z = location.getBlockZ();
//
// org.bukkit.block.Block bukkitBlock = location.getBlock();
// BaseBlock block = FaweCache.getBlock(bukkitBlock.getTypeId(), bukkitBlock.getData());
// BaseBlock block = FaweCache.IMP.getBlock(bukkitBlock.getTypeId(), bukkitBlock.getData());
//
// // Read the NBT data
// Object nmsWorld = getHandleWorld.invoke(craftWorld);

View File

@ -51,6 +51,7 @@ import com.sk89q.worldedit.registry.state.EnumProperty;
import com.sk89q.worldedit.registry.state.IntegerProperty;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
@ -104,6 +105,7 @@ import org.bukkit.craftbukkit.v1_14_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_14_R1.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_14_R1.util.CraftMagicNumbers;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import org.slf4j.Logger;
@ -250,6 +252,21 @@ public final class Spigot_v1_14_R1 extends CachedBukkitAdapter implements Bukkit
// Code that is less likely to break
// ------------------------------------------------------------------------
@Override
public int getDataVersion() {
return CraftMagicNumbers.INSTANCE.getDataVersion();
}
@Override
public DataFixer getDataFixer() {
try {
Class<?> converter = Class.forName("com.sk89q.worldedit.bukkit.adapter.impl.DataConverters_1_14_R4");
return (DataFixer) converter.getDeclaredField("INSTANCE").get(null);
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
@SuppressWarnings("deprecation")
@Override
public BaseBlock getBlock(Location location) {
@ -409,15 +426,15 @@ public final class Spigot_v1_14_R1 extends CachedBukkitAdapter implements Bukkit
for (IBlockState state : blockStateList.d()) {
Property property;
if (state instanceof BlockStateBoolean) {
property = new BooleanProperty(state.a(), ImmutableList.copyOf(state.d()));
property = new BooleanProperty(state.a(), ImmutableList.copyOf(state.getValues()));
} else if (state instanceof BlockStateDirection) {
property = new DirectionalProperty(state.a(),
(List<Direction>) state.d().stream().map(e -> Direction.valueOf(((INamable) e).getName().toUpperCase())).collect(Collectors.toList()));
(List<Direction>) state.getValues().stream().map(e -> Direction.valueOf(((INamable) e).getName().toUpperCase())).collect(Collectors.toList()));
} else if (state instanceof BlockStateEnum) {
property = new EnumProperty(state.a(),
(List<String>) state.d().stream().map(e -> ((INamable) e).getName()).collect(Collectors.toList()));
(List<String>) state.getValues().stream().map(e -> ((INamable) e).getName()).collect(Collectors.toList()));
} else if (state instanceof BlockStateInteger) {
property = new IntegerProperty(state.a(), ImmutableList.copyOf(state.d()));
property = new IntegerProperty(state.a(), ImmutableList.copyOf(state.getValues()));
} else {
throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName());
}

View File

@ -1,13 +1,14 @@
package com.boydti.fawe.bukkit.wrapper;
import com.boydti.fawe.bukkit.wrapper.state.AsyncSign;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.util.TaskManager;
import com.destroystokyo.paper.block.BlockSoundGroup;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.world.biome.BiomeType;
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.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import org.bukkit.FluidCollisionMode;
@ -34,12 +35,10 @@ public class AsyncBlock implements Block {
public int z;
public int y;
public int x;
public final FaweQueue queue;
public final AsyncWorld world;
public AsyncBlock(AsyncWorld world, FaweQueue queue, int x, int y, int z) {
public AsyncBlock(AsyncWorld world, int x, int y, int z) {
this.world = world;
this.queue = queue;
this.x = x;
this.y = Math.max(0, Math.min(255, y));
this.z = z;
@ -54,25 +53,24 @@ public class AsyncBlock implements Block {
@Override
@Deprecated
public byte getData() {
return (byte) (queue.getCachedCombinedId4Data(x, y, z, BlockTypes.AIR.getInternalId()) & 0xF);
return (byte) getPropertyId();
}
public int getPropertyId() {
return (queue.getCachedCombinedId4Data(x, y, z, BlockTypes.AIR.getInternalId()) >> BlockTypes.BIT_OFFSET);
return world.getBlock(x, y, z).getInternalId() >> BlockTypes.BIT_OFFSET;
}
public int getCombinedId() {
return queue.getCachedCombinedId4Data(x, y, z, BlockTypes.AIR.getInternalId());
return world.getBlock(x, y, z).getInternalId();
}
public int getTypeId() {
int id = (queue.getCachedCombinedId4Data(x, y, z, BlockTypes.AIR.getInternalId()));
return BlockTypes.getFromStateId(id).getInternalId();
return world.getBlock(x, y, z).getBlockType().getInternalId();
}
@NotNull @Override
public AsyncBlock getRelative(int modX, int modY, int modZ) {
return new AsyncBlock(world, queue, x + modX, y + modY, z + modZ);
return new AsyncBlock(world, x + modX, y + modY, z + modZ);
}
@NotNull @Override
@ -92,7 +90,7 @@ public class AsyncBlock implements Block {
@NotNull @Override
public BlockData getBlockData() {
return BukkitAdapter.getBlockData(queue.getCachedCombinedId4Data(x, y, z, BlockTypes.AIR.getInternalId()));
return BukkitAdapter.adapt(world.getBlock(x, y, z));
}
@Deprecated
@ -102,7 +100,7 @@ public class AsyncBlock implements Block {
@Deprecated
public boolean setCombinedId(int combinedId) {
return queue.setBlock(x, y, z, combinedId);
return world.setBlock(x, y, z, BlockState.getFromInternalId(combinedId));
}
@Deprecated
@ -112,7 +110,7 @@ public class AsyncBlock implements Block {
@Deprecated
public boolean setTypeId(int typeId) {
return queue.setBlock(x, y, z, BlockTypes.get(typeId).getDefaultState());
return world.setBlock(x, y, z, BlockTypes.get(typeId).getDefaultState());
}
@Deprecated
@ -122,17 +120,17 @@ public class AsyncBlock implements Block {
@Override
public byte getLightLevel() {
return (byte) queue.getLight(x, y, z);
return (byte) world.getLight(x, y, z);
}
@Override
public byte getLightFromSky() {
return (byte) queue.getSkyLight(x, y, z);
return (byte) world.getSkyLight(x, y, z);
}
@Override
public byte getLightFromBlocks() {
return (byte) queue.getEmmittedLight(x, y, z);
return (byte) world.getBlockLight(x, y, z);
}
@NotNull @Override
@ -179,7 +177,7 @@ public class AsyncBlock implements Block {
@Override
public void setBlockData(@NotNull BlockData blockData) {
try {
queue.setBlock(x, y, z, BukkitAdapter.adapt(blockData));
world.setBlock(x, y, z, BukkitAdapter.adapt(blockData));
} catch (WorldEditException e) {
throw new RuntimeException(e);
}
@ -193,7 +191,7 @@ public class AsyncBlock implements Block {
@Override
public void setType(@NotNull Material type) {
try {
queue.setBlock(x, y, z, BukkitAdapter.adapt(type).getDefaultState());
world.setBlock(x, y, z, BukkitAdapter.adapt(type).getDefaultState());
} catch (WorldEditException e) {
throw new RuntimeException(e);
}
@ -219,9 +217,8 @@ public class AsyncBlock implements Block {
@NotNull @Override
public AsyncBlockState getState() {
int combined = queue.getCombinedId4Data(x, y, z, 0);
BlockType type = BlockTypes.getFromStateId(combined);
switch (type.getInternalId()) {
BaseBlock state = world.getFullBlock(x, y, z);
switch (state.getBlockType().getInternalId()) {
case BlockID.ACACIA_SIGN:
case BlockID.SPRUCE_SIGN:
case BlockID.ACACIA_WALL_SIGN:
@ -234,9 +231,9 @@ public class AsyncBlock implements Block {
case BlockID.JUNGLE_WALL_SIGN:
case BlockID.OAK_SIGN:
case BlockID.OAK_WALL_SIGN:
return new AsyncSign(this, combined);
return new AsyncSign(this, state);
default:
return new AsyncBlockState(this, combined);
return new AsyncBlockState(this, state);
}
}
@ -248,13 +245,13 @@ public class AsyncBlock implements Block {
@NotNull @Override
public Biome getBiome() {
return world.getAdapter().adapt(queue.getBiomeType(x, z));
return world.getAdapter().adapt(world.getBiomeType(x, z));
}
@Override
public void setBiome(@NotNull Biome bio) {
BiomeType biome = world.getAdapter().adapt(bio);
queue.setBiome(x, z, biome);
world.setBiome(x, 0, z, biome);
}
@Override
@ -301,9 +298,7 @@ public class AsyncBlock implements Block {
@Override
public boolean isLiquid() {
int combined = queue.getCombinedId4Data(x, y, z, 0);
BlockType type = BlockTypes.getFromStateId(combined);
return type.getMaterial().isLiquid();
return world.getBlock(x, y, z).getMaterial().isLiquid();
}
@Override

View File

@ -6,6 +6,8 @@ import java.util.List;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import org.bukkit.Chunk;
import org.bukkit.Location;
@ -20,30 +22,26 @@ import org.bukkit.plugin.Plugin;
public class AsyncBlockState implements BlockState {
private int combinedId;
private BaseBlock state;
private BlockData blockData;
private CompoundTag nbt;
private final AsyncBlock block;
public AsyncBlockState(AsyncBlock block) {
this(block, block.queue.getCombinedId4Data(block.x, block.y, block.z, 0));
this(block, block.world.getFullBlock(block.x, block.y, block.z));
}
public AsyncBlockState(AsyncBlock block, int combined) {
this.combinedId = combined;
public AsyncBlockState(AsyncBlock block, BaseBlock state) {
this.state = state;
this.block = block;
this.blockData = BukkitAdapter.getBlockData(combined);
if (BlockTypes.getFromStateId(combined).getMaterial().hasContainer()) {
this.nbt = block.queue.getTileEntity(block.x, block.y, block.z);
}
this.blockData = BukkitAdapter.adapt(state);
}
public int getTypeId() {
return BlockTypes.getFromStateId(combinedId).getInternalId();
return state.getBlockType().getInternalId();
}
public int getPropertyId() {
return combinedId >> BlockTypes.BIT_OFFSET;
return state.getInternalId() >> BlockTypes.BIT_OFFSET;
}
@Override
@ -68,7 +66,7 @@ public class AsyncBlockState implements BlockState {
@Override
public byte getLightLevel() {
return (byte) BlockTypes.getFromStateId(combinedId).getMaterial().getLightValue();
return (byte) state.getMaterial().getLightValue();
}
@Override
@ -114,7 +112,14 @@ public class AsyncBlockState implements BlockState {
@Override
public void setBlockData(BlockData blockData) {
this.blockData = blockData;
this.combinedId = BukkitAdapter.adapt(blockData).getInternalId();
CompoundTag nbt = state.getNbtData();
BlockType oldType = state.getBlockType();
com.sk89q.worldedit.world.block.BlockState newState = BukkitAdapter.adapt(blockData);
if (nbt != null && newState.getBlockType() == oldType) {
state = newState.toBaseBlock(nbt);
} else {
state = newState.toBaseBlock();
}
}
@Override
@ -135,33 +140,30 @@ public class AsyncBlockState implements BlockState {
@Override
public boolean update(boolean force, boolean applyPhysics) {
try {
boolean result = block.queue.setBlock(block.x, block.y, block.z, BukkitAdapter.adapt(blockData));
if (nbt != null) {
block.queue.setTile(block.x, block.y, block.z, nbt);
}
return result;
return block.world.setBlock(block.x, block.y, block.z, state);
} catch (WorldEditException e) {
throw new RuntimeException(e);
}
}
public CompoundTag getNbtData() {
return nbt;
return state.getNbtData();
}
public void setNbtData(CompoundTag nbt) {
this.nbt = nbt;
state = this.state.toBaseBlock(nbt);
}
@Override
public byte getRawData() {
return (byte) (combinedId >> BlockTypes.BIT_OFFSET);
return (byte) (state.getInternalId() >> BlockTypes.BIT_OFFSET);
}
@Override
public void setRawData(byte data) {
this.combinedId = getTypeId() + (data << BlockTypes.BIT_OFFSET);
this.blockData = BukkitAdapter.getBlockData(this.combinedId);
int combinedId = getTypeId() + (data << BlockTypes.BIT_OFFSET);
state = com.sk89q.worldedit.world.block.BlockState.getFromInternalId(combinedId).toBaseBlock(state.getNbtData());
this.blockData = BukkitAdapter.adapt(state);
}
@Override

View File

@ -1,8 +1,6 @@
package com.boydti.fawe.bukkit.wrapper;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.TaskManager;
@ -21,11 +19,9 @@ public class AsyncChunk implements Chunk {
private final AsyncWorld world;
private final int z;
private final int x;
private final FaweQueue queue;
public AsyncChunk(World world, FaweQueue queue, int x, int z) {
public AsyncChunk(World world, int x, int z) {
this.world = world instanceof AsyncWorld ? (AsyncWorld) world : new AsyncWorld(world, true);
this.queue = queue;
this.x = x;
this.z = z;
}
@ -61,7 +57,7 @@ public class AsyncChunk implements Chunk {
@Override
public AsyncBlock getBlock(int x, int y, int z) {
return new AsyncBlock(world, queue, (this.x << 4) + x, y, (this.z << 4) + z);
return new AsyncBlock(world, (this.x << 4) + x, y, (this.z << 4) + z);
}
@Override
@ -87,8 +83,7 @@ public class AsyncChunk implements Chunk {
task.run();
return task.value;
}
if (queue instanceof BukkitQueue_0) {
BukkitQueue_0 bq = (BukkitQueue_0) queue;
if (world.isWorld()) {
if (world.isChunkLoaded(x, z)) {
if (world.isChunkLoaded(x, z)) {
task.run();

View File

@ -1,32 +1,36 @@
package com.boydti.fawe.bukkit.wrapper;
import com.bekvon.bukkit.residence.commands.material;
import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.HasFaweQueue;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.object.queue.DelegateFaweQueue;
import com.boydti.fawe.util.SetQueue;
import com.boydti.fawe.util.StringMan;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.bukkit.BukkitWorld;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.PassthroughExtent;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.world.biome.BiomeType;
import java.io.File;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
import java.util.function.Supplier;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import org.bukkit.*;
import com.sk89q.worldedit.world.block.BlockState;
import org.bukkit.BlockChangeDelegate;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.ChunkSnapshot;
import org.bukkit.Difficulty;
import org.bukkit.Effect;
import org.bukkit.FluidCollisionMode;
import org.bukkit.GameRule;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.StructureType;
import org.bukkit.TreeType;
import org.bukkit.World;
import org.bukkit.WorldBorder;
import org.bukkit.WorldCreator;
import org.bukkit.WorldType;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
@ -50,6 +54,17 @@ import org.bukkit.util.Consumer;
import org.bukkit.util.RayTraceResult;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* Modify the world from an async thread<br>
@ -60,10 +75,9 @@ import org.jetbrains.annotations.NotNull;
* @see #wrap(World)
* @see #create(WorldCreator)
*/
public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue {
public class AsyncWorld extends PassthroughExtent implements World {
private World parent;
private FaweQueue queue;
private BukkitImplAdapter adapter;
@Override
@ -78,7 +92,7 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
*/
@Deprecated
public AsyncWorld(World parent, boolean autoQueue) {
this(parent, FaweAPI.createQueue(parent.getName(), autoQueue));
this(parent, FaweAPI.createQueue(new BukkitWorld(parent), autoQueue));
}
public AsyncWorld(String world, boolean autoQueue) {
@ -91,19 +105,10 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
* @param queue
*/
@Deprecated
public AsyncWorld(World parent, FaweQueue queue) {
super(queue);
public AsyncWorld(World parent, Extent extent) {
super(extent);
this.parent = parent;
this.queue = queue;
if (queue instanceof BukkitQueue_0) {
this.adapter = BukkitQueue_0.getAdapter();
} else {
try {
this.adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
} catch (Throwable e) {
e.printStackTrace();
}
}
this.adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
}
/**
@ -118,32 +123,15 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
return new AsyncWorld(world, false);
}
public void changeWorld(World world, FaweQueue queue) {
this.parent = world;
if (queue != this.queue) {
if (this.queue != null) {
final FaweQueue oldQueue = this.queue;
TaskManager.IMP.async(oldQueue::flush);
}
this.queue = queue;
}
setParent(queue);
}
@Override
public String toString() {
return super.toString() + ":" + queue.toString();
return getName();
}
public World getBukkitWorld() {
return parent;
}
@Override
public FaweQueue getQueue() {
return queue;
}
/**
* Create a world async (untested)
* - Only optimized for 1.10
@ -151,8 +139,8 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
* @return
*/
public synchronized static AsyncWorld create(final WorldCreator creator) {
BukkitQueue_0 queue = (BukkitQueue_0) SetQueue.IMP.getNewQueue(creator.name(), true, false);
World world = queue.createWorld(creator);
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
@Nullable World world = adapter.createWorld(creator);
return wrap(world);
}
@ -163,9 +151,7 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
}
public void flush() {
if (queue != null) {
queue.flush();
}
getExtent().commit();
}
@Override
@ -240,7 +226,7 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
@Override
public AsyncBlock getBlockAt(final int x, final int y, final int z) {
return new AsyncBlock(this, queue, x, y, z);
return new AsyncBlock(this, x, y, z);
}
@Override
@ -251,9 +237,8 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
@Override
public int getHighestBlockYAt(int x, int z) {
for (int y = getMaxHeight() - 1; y >= 0; y--) {
int stateId = queue.getCachedCombinedId4Data(x, y, z, BlockTypes.AIR.getInternalId());
BlockType type = BlockTypes.getFromStateId(stateId);
if (!type.getMaterial().isAir()) return y;
BlockState state = this.getBlock(x, y, z);
if (!state.getMaterial().isAir()) return y;
}
return 0;
}
@ -276,7 +261,7 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
@Override
public AsyncChunk getChunkAt(int x, int z) {
return new AsyncChunk(this, queue, x, z);
return new AsyncChunk(this, x, z);
}
@Override
@ -422,8 +407,7 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
@Override
@Deprecated
public boolean refreshChunk(int x, int z) {
queue.sendChunk(queue.getFaweChunk(x, z));
return true;
return parent.refreshChunk(x, z);
}
@Override
@ -825,13 +809,13 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
@Override
public Biome getBiome(int x, int z) {
return adapter.adapt(queue.getBiomeType(x, z));
return adapter.adapt(getExtent().getBiomeType(x, z));
}
@Override
public void setBiome(int x, int z, Biome bio) {
BiomeType biome = adapter.adapt(bio);
queue.setBiome(x, z, biome);
getExtent().setBiome(x, 0, z, biome);
}
@Override
@ -1114,6 +1098,11 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
return parent.locateNearestStructure(arg0, arg1, arg2, arg3);
}
@Override
public int getViewDistance() {
return parent.getViewDistance();
}
@Override
public RayTraceResult rayTrace(Location arg0, Vector arg1, double arg2, FluidCollisionMode arg3, boolean arg4,
double arg5, Predicate<Entity> arg6) {

View File

@ -54,7 +54,7 @@ public final class AsyncDataContainer implements PersistentDataContainer {
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)));
get().put(key.toString(), FaweCache.IMP.asTag(type.toPrimitive(value, null)));
}
public <T, Z> boolean has(NamespacedKey key, PersistentDataType<T, Z> type) {

View File

@ -10,6 +10,8 @@ import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.serializer.gson.GsonComponentSerializer;
import com.sk89q.worldedit.util.formatting.text.serializer.legacy.LegacyComponentSerializer;
import java.util.Map;
import com.sk89q.worldedit.world.block.BaseBlock;
import org.bukkit.DyeColor;
import org.bukkit.block.Sign;
import org.bukkit.persistence.PersistentDataContainer;
@ -17,8 +19,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class AsyncSign extends AsyncBlockState implements Sign {
public AsyncSign(AsyncBlock block, int combined) {
super(block, combined);
public AsyncSign(AsyncBlock block, BaseBlock state) {
super(block, state);
}
private boolean isEditable = false;

View File

@ -330,10 +330,6 @@ public enum BukkitAdapter {
return getAdapter().adapt(block);
}
public static BlockData getBlockData(int combinedId) {
return getAdapter().getBlockData(combinedId);
}
/**
* Create a WorldEdit BlockState from a Bukkit ItemStack
*

View File

@ -21,6 +21,10 @@ package com.sk89q.worldedit.bukkit;
import static com.google.common.base.Preconditions.checkNotNull;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.bukkit.beta.BukkitGetBlocks;
import com.boydti.fawe.config.Settings;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
@ -494,9 +498,19 @@ public class BukkitWorld extends AbstractWorld {
return BukkitAdapter.adapt(getWorld().getBiome(position.getBlockX(), position.getBlockZ()));
}
@Override
public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
return false;
}
@Override
public boolean setBiome(BlockVector2 position, BiomeType biome) {
getWorld().setBiome(position.getBlockX(), position.getBlockZ(), BukkitAdapter.adapt(biome));
return true;
}
@Override
public IChunkGet get(int chunkX, int chunkZ) {
return new BukkitGetBlocks(getWorldChecked(), chunkX, chunkZ, Settings.IMP.QUEUE.POOL);
}
}

View File

@ -41,18 +41,18 @@ import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.util.command.CommandMapping;
import com.sk89q.worldedit.internal.command.CommandUtil;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockCategory;
import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.item.ItemCategory;
import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.registry.LegacyMapper;
import io.papermc.lib.PaperLib;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.block.Biome;
import org.bukkit.command.BlockCommandSender;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;

View File

@ -19,6 +19,8 @@
package com.sk89q.worldedit.bukkit.adapter;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.bukkit.FaweBukkit;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.entity.BaseEntity;
@ -33,6 +35,8 @@ import com.sk89q.worldedit.world.registry.BlockMaterial;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
@ -149,4 +153,8 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
* @param player The player
*/
void sendFakeOP(Player player);
default @org.jetbrains.annotations.Nullable World createWorld(WorldCreator creator) {
return ((FaweBukkit) Fawe.imp()).createWorldUnloaded(creator::createWorld);
}
}

View File

@ -303,10 +303,6 @@ public interface IBukkitAdapter {
*/
BlockData adapt(BlockStateHolder block);
default BlockData getBlockData(int combinedId) {
return adapt(BlockState.getFromInternalId(combinedId));
}
/**
* Create a WorldEdit BlockStateHolder from a Bukkit ItemStack
*

View File

@ -4,6 +4,7 @@ import com.boydti.fawe.beta.Trimable;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.collection.BitArray4096;
import com.boydti.fawe.object.collection.IterableThreadLocal;
import com.boydti.fawe.util.IOUtil;
import com.boydti.fawe.util.MathMan;
import com.sk89q.jnbt.ByteArrayTag;
import com.sk89q.jnbt.ByteTag;
@ -29,92 +30,182 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
public final class FaweCache implements Trimable {
public final static int BLOCKS_PER_LAYER = 4096;
public final static int CHUNK_LAYERS = 16;
public final static int WORLD_HEIGHT = CHUNK_LAYERS << 4;
public final static int WORLD_MAX_Y = WORLD_HEIGHT - 1;
import static com.google.common.base.Preconditions.checkNotNull;
public enum FaweCache implements Trimable {
IMP
; // singleton
public static final char[] EMPTY_CHAR_4096 = new char[4096];
public final int BLOCKS_PER_LAYER = 4096;
public final int CHUNK_LAYERS = 16;
public final int WORLD_HEIGHT = CHUNK_LAYERS << 4;
public final int WORLD_MAX_Y = WORLD_HEIGHT - 1;
public final char[] EMPTY_CHAR_4096 = new char[4096];
private final IdentityHashMap<Class, IterableThreadLocal> REGISTERED_SINGLETONS = new IdentityHashMap<>();
private final IdentityHashMap<Class, Pool> REGISTERED_POOLS = new IdentityHashMap<>();
public interface Pool<T> {
T poll();
default boolean offer(T recycle) {
return false;
}
default void clear() {}
}
public class QueuePool<T> extends ConcurrentLinkedQueue<T> implements Pool<T> {
private final Supplier<T> supplier;
public QueuePool(Supplier<T> supplier) {
this.supplier = supplier;
}
@Override
public boolean offer(T t) {
return super.offer(t);
}
@Override
public T poll() {
T result = super.poll();
if (result == null) {
return supplier.get();
}
return result;
}
@Override
public void clear() {
if (!isEmpty()) super.clear();
}
}
/*
Palette buffers / cache
*/
@Override
public boolean trim(boolean aggressive) {
public synchronized 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();
INDEX_STORE.clean();
MUTABLE_VECTOR3.clean();
MUTABLE_BLOCKVECTOR3.clean();
SECTION_BITS_TO_CHAR.clean();
for (Map.Entry<Class, IterableThreadLocal> entry : REGISTERED_SINGLETONS.entrySet()) {
entry.getValue().clean();
}
for (Map.Entry<Class, Pool> entry : REGISTERED_POOLS.entrySet()) {
Pool pool = entry.getValue();
pool.clear();
}
return false;
}
public static final IterableThreadLocal<int[]> BLOCK_TO_PALETTE = new IterableThreadLocal<int[]>() {
@Override
public int[] init() {
int[] result = new int[BlockTypes.states.length];
Arrays.fill(result, Integer.MAX_VALUE);
return result;
public final <T> Pool<T> getPool(Class<T> clazz) {
Pool<T> pool = REGISTERED_POOLS.get(clazz);
if (pool == null) {
synchronized (this) {
pool = REGISTERED_POOLS.get(clazz);
if (pool == null) {
Fawe.debug("Not registered " + clazz);
Supplier<T> supplier = IOUtil.supplier(clazz::newInstance);
pool = supplier::get;
REGISTERED_POOLS.put(clazz, pool);
}
}
}
};
return pool;
}
public static final IterableThreadLocal<char[]> SECTION_BITS_TO_CHAR = new IterableThreadLocal<char[]>() {
@Override
public char[] init() {
char[] result = new char[4096];
return result;
}
};
public final <T> T getFromPool(Class<T> clazz) {
Pool<T> pool = getPool(clazz);
return pool.poll();
}
public static final IterableThreadLocal<int[]> PALETTE_TO_BLOCK = new IterableThreadLocal<int[]>() {
@Override
public int[] init() {
return new int[Character.MAX_VALUE + 1];
public final <T> T getSingleton(Class<T> clazz) {
IterableThreadLocal<T> cache = REGISTERED_SINGLETONS.get(clazz);
if (cache == null) {
synchronized (this) {
cache = REGISTERED_SINGLETONS.get(clazz);
if (cache == null) {
Fawe.debug("Not registered " + clazz);
cache = new IterableThreadLocal<>(IOUtil.supplier(clazz::newInstance));
REGISTERED_SINGLETONS.put(clazz, cache);
}
}
}
};
return cache.get();
}
public static final IterableThreadLocal<char[]> PALETTE_TO_BLOCK_CHAR = new IterableThreadLocal<char[]>() {
@Override
public char[] init() {
char[] result = new char[Character.MAX_VALUE + 1];
Arrays.fill(result, Character.MAX_VALUE);
return result;
public synchronized <T> IterableThreadLocal<T> registerSingleton(Class<T> clazz, Supplier<T> cache) {
checkNotNull(cache);
IterableThreadLocal<T> local = new IterableThreadLocal<>(cache);
IterableThreadLocal previous = REGISTERED_SINGLETONS.putIfAbsent(clazz, local);
if (previous != null) {
throw new IllegalStateException("Previous key");
}
};
return local;
}
public static final IterableThreadLocal<long[]> BLOCK_STATES = new IterableThreadLocal<long[]>() {
@Override
public long[] init() {
return new long[2048];
public synchronized <T> Pool<T> registerPool(Class<T> clazz, Supplier<T> cache, boolean buffer) {
checkNotNull(cache);
Pool<T> pool;
if (buffer) {
pool = new QueuePool<>(cache);
} else {
pool = cache::get;
}
};
Pool previous = REGISTERED_POOLS.putIfAbsent(clazz, pool);
if (previous != null) {
throw new IllegalStateException("Previous key");
}
return pool;
}
public static final IterableThreadLocal<int[]> SECTION_BLOCKS = new IterableThreadLocal<int[]>() {
@Override
public int[] init() {
return new int[4096];
public final IterableThreadLocal<int[]> BLOCK_TO_PALETTE = new IterableThreadLocal<>(() -> {
int[] result = new int[BlockTypes.states.length];
Arrays.fill(result, Integer.MAX_VALUE);
return result;
});
public final IterableThreadLocal<char[]> SECTION_BITS_TO_CHAR = new IterableThreadLocal<>(() -> new char[4096]);
public final IterableThreadLocal<int[]> PALETTE_TO_BLOCK = new IterableThreadLocal<>(() -> new int[Character.MAX_VALUE + 1]);
public final IterableThreadLocal<char[]> PALETTE_TO_BLOCK_CHAR = new IterableThreadLocal<>(
() -> new char[Character.MAX_VALUE + 1], a -> {
Arrays.fill(a, Character.MAX_VALUE);
}
};
);
public final IterableThreadLocal<long[]> BLOCK_STATES = new IterableThreadLocal<>(() -> new long[2048]);
public final IterableThreadLocal<int[]> SECTION_BLOCKS = new IterableThreadLocal<>(() -> new int[4096]);
public final IterableThreadLocal<int[]> INDEX_STORE = new IterableThreadLocal<>(() -> new int[256]);
/**
* Holds data for a palette used in a chunk section
*/
public static final class Palette {
public final class Palette {
public int paletteToBlockLength;
/**
* Reusable buffer array, MUST check paletteToBlockLength for actual length
@ -128,12 +219,7 @@ public final class FaweCache implements Trimable {
public long[] blockStates;
}
private static final IterableThreadLocal<Palette> PALETTE_CACHE = new IterableThreadLocal<Palette>() {
@Override
public Palette init() {
return new Palette();
}
};
private final IterableThreadLocal<Palette> PALETTE_CACHE = new IterableThreadLocal<>(Palette::new);
/**
* Convert raw char array to palette
@ -141,7 +227,7 @@ public final class FaweCache implements Trimable {
* @param blocks
* @return palette
*/
public static Palette toPalette(int layerOffset, char[] blocks) {
public Palette toPalette(int layerOffset, char[] blocks) {
return toPalette(layerOffset, null, blocks);
}
@ -151,11 +237,11 @@ public final class FaweCache implements Trimable {
* @param blocks
* @return palette
*/
public static Palette toPalette(int layerOffset, int[] blocks) {
public Palette toPalette(int layerOffset, int[] blocks) {
return toPalette(layerOffset, blocks, null);
}
private static Palette toPalette(int layerOffset, int[] blocksInts, char[] blocksChars) {
private 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();
@ -229,14 +315,9 @@ public final class FaweCache implements Trimable {
* Vector cache
*/
public static IterableThreadLocal<MutableBlockVector3> MUTABLE_BLOCKVECTOR3 = new IterableThreadLocal<MutableBlockVector3>() {
@Override
public MutableBlockVector3 init() {
return new MutableBlockVector3();
}
};
public IterableThreadLocal<MutableBlockVector3> MUTABLE_BLOCKVECTOR3 = new IterableThreadLocal<>(MutableBlockVector3::new);
public static IterableThreadLocal<MutableVector3> MUTABLE_VECTOR3 = new IterableThreadLocal<MutableVector3>() {
public IterableThreadLocal<MutableVector3> MUTABLE_VECTOR3 = new IterableThreadLocal<MutableVector3>(MutableVector3::new) {
@Override
public MutableVector3 init() {
return new MutableVector3();
@ -246,7 +327,7 @@ public final class FaweCache implements Trimable {
/*
Conversion methods between JNBT tags and raw values
*/
public static Map<String, Object> asMap(Object... pairs) {
public Map<String, Object> asMap(Object... pairs) {
HashMap<String, Object> map = new HashMap<>(pairs.length >> 1);
for (int i = 0; i < pairs.length; i += 2) {
String key = (String) pairs[i];
@ -256,47 +337,47 @@ public final class FaweCache implements Trimable {
return map;
}
public static ShortTag asTag(short value) {
public ShortTag asTag(short value) {
return new ShortTag(value);
}
public static IntTag asTag(int value) {
public IntTag asTag(int value) {
return new IntTag(value);
}
public static DoubleTag asTag(double value) {
public DoubleTag asTag(double value) {
return new DoubleTag(value);
}
public static ByteTag asTag(byte value) {
public ByteTag asTag(byte value) {
return new ByteTag(value);
}
public static FloatTag asTag(float value) {
public FloatTag asTag(float value) {
return new FloatTag(value);
}
public static LongTag asTag(long value) {
public LongTag asTag(long value) {
return new LongTag(value);
}
public static ByteArrayTag asTag(byte[] value) {
public ByteArrayTag asTag(byte[] value) {
return new ByteArrayTag(value);
}
public static IntArrayTag asTag(int[] value) {
public IntArrayTag asTag(int[] value) {
return new IntArrayTag(value);
}
public static LongArrayTag asTag(long[] value) {
public LongArrayTag asTag(long[] value) {
return new LongArrayTag(value);
}
public static StringTag asTag(String value) {
public StringTag asTag(String value) {
return new StringTag(value);
}
public static CompoundTag asTag(Map<String, Object> value) {
public CompoundTag asTag(Map<String, Object> value) {
HashMap<String, Tag> map = new HashMap<>();
for (Map.Entry<String, Object> entry : value.entrySet()) {
Object child = entry.getValue();
@ -306,7 +387,7 @@ public final class FaweCache implements Trimable {
return new CompoundTag(map);
}
public static Tag asTag(Object value) {
public Tag asTag(Object value) {
if (value instanceof Integer) {
return asTag((int) value);
} else if (value instanceof Short) {
@ -359,7 +440,7 @@ public final class FaweCache implements Trimable {
}
}
public static ListTag asTag(Object... values) {
public ListTag asTag(Object... values) {
Class<? extends Tag> clazz = null;
List<Tag> list = new ArrayList<>(values.length);
for (Object value : values) {
@ -373,7 +454,7 @@ public final class FaweCache implements Trimable {
return new ListTag(clazz, list);
}
public static ListTag asTag(Collection values) {
public ListTag asTag(Collection values) {
Class<? extends Tag> clazz = null;
List<Tag> list = new ArrayList<>(values.size());
for (Object value : values) {
@ -390,7 +471,7 @@ public final class FaweCache implements Trimable {
/*
Thread stuff
*/
public static ThreadPoolExecutor newBlockingExecutor() {
public ThreadPoolExecutor newBlockingExecutor() {
int nThreads = Settings.IMP.QUEUE.PARALLEL_THREADS;
ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(nThreads);
return new ThreadPoolExecutor(nThreads, nThreads,

View File

@ -106,6 +106,8 @@ public interface IChunk<T extends Future<T>> extends Trimable, Callable<T>, IChu
/* set - queues a change */
boolean setBiome(int x, int y, int z, BiomeType biome);
boolean setTile(int x, int y, int z, CompoundTag tag);
boolean setBlock(int x, int y, int z, BlockStateHolder block);
@Override
@ -126,7 +128,7 @@ public interface IChunk<T extends Future<T>> extends Trimable, Callable<T>, IChu
*/
@Override
default IBlocks reset() {
init(getQueue(), getX(), getZ());
init(null, getX(), getZ());
return this;
}
}

View File

@ -6,6 +6,8 @@ import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import java.util.concurrent.Future;
/**
* An interface for getting blocks.
*/
@ -28,4 +30,8 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent {
default void optimize() {
}
<T extends Future<T>> T call(IChunkSet set, Runnable finalize);
char[] load(int layer);
}

View File

@ -28,6 +28,10 @@ public interface IDelegateChunk<U extends IChunk> extends IChunk {
return root;
}
@Override
default <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
return getParent().call(set, finalize);
}
@Override
default IQueueExtent getQueue() {
@ -49,6 +53,11 @@ public interface IDelegateChunk<U extends IChunk> extends IChunk {
getParent().flood(flood, mask, block);
}
@Override
default boolean setTile(int x, int y, int z, CompoundTag tag) {
return getParent().setTile(x, y, z, tag);
}
@Override
default boolean setBiome(int x, int y, int z, BiomeType biome) {
return getParent().setBiome(x, y, z, biome);
@ -74,6 +83,11 @@ public interface IDelegateChunk<U extends IChunk> extends IChunk {
return getParent().getFullBlock(x, y, z);
}
@Override
default char[] load(int layer) {
return getParent().load(layer);
}
@Override
default void init(IQueueExtent extent, int chunkX, int chunkZ) {
getParent().init(extent, chunkX, chunkZ);

View File

@ -1,6 +1,35 @@
package com.boydti.fawe.beta;
import com.boydti.fawe.beta.implementation.WorldChunkCache;
import com.boydti.fawe.beta.implementation.IChunkCache;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.function.generator.GenBase;
import com.sk89q.worldedit.function.generator.Resource;
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.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;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Future;
/**
@ -11,8 +40,43 @@ public interface IDelegateQueueExtent extends IQueueExtent {
IQueueExtent getParent();
@Override
default void init(WorldChunkCache cache) {
getParent().init(cache);
default boolean isQueueEnabled() {
return getParent().isQueueEnabled();
}
@Override
default void clearBlockUpdates(Player... players) {
getParent().clearBlockUpdates(players);
}
@Override
default void sendBlockUpdates(Player... players) {
getParent().sendBlockUpdates(players);
}
@Override
default void enableQueue() {
getParent().enableQueue();
}
@Override
default void disableQueue() {
getParent().disableQueue();
}
@Override
default void init(Extent extent, IChunkCache<IChunkGet> get, IChunkCache<IChunkSet> set) {
getParent().init(extent, get, set);
}
@Override
default IChunkGet getCachedGet(int x, int z) {
return getParent().getCachedGet(x, z);
}
@Override
default IChunkSet getCachedSet(int x, int z) {
return getParent().getCachedSet(x, z);
}
@Override
@ -21,10 +85,50 @@ public interface IDelegateQueueExtent extends IQueueExtent {
}
@Override
default Future<?> submit(IChunk chunk) {
default <T extends Future<T>> T submit(IChunk<T> chunk) {
return getParent().submit(chunk);
}
@Override
default boolean setBlock(int x, int y, int z, BlockStateHolder state) {
return getParent().setBlock(x, y, z, state);
}
@Override
default boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
return getParent().setTile(x, y, z, tile);
}
@Override
default boolean setBiome(int x, int y, int z, BiomeType biome) {
return getParent().setBiome(x, y, z, biome);
}
@Override
default BlockState getBlock(int x, int y, int z) {
return getParent().getBlock(x, y, z);
}
@Override
default BaseBlock getFullBlock(int x, int y, int z) {
return getParent().getFullBlock(x, y, z);
}
@Override
default BiomeType getBiome(int x, int z) {
return getParent().getBiome(x, z);
}
@Override
default BlockVector3 getMinimumPoint() {
return getParent().getMinimumPoint();
}
@Override
default BlockVector3 getMaximumPoint() {
return getParent().getMaximumPoint();
}
@Override
default IChunk create(boolean isFull) {
return getParent().create(isFull);
@ -40,8 +144,247 @@ public interface IDelegateQueueExtent extends IQueueExtent {
getParent().flush();
}
@Override
default ChunkFilterBlock initFilterBlock() {
return getParent().initFilterBlock();
}
@Override
default int size() {
return getParent().size();
}
@Override
default boolean isEmpty() {
return getParent().isEmpty();
}
@Override
default void sendChunk(int chunkX, int chunkZ, int bitMask) {
getParent().sendChunk(chunkX, chunkZ, bitMask);
}
@Override
default boolean trim(boolean aggressive) {
return getParent().trim(aggressive);
}
@Override
default void recycle() {
getParent().recycle();
}
@Override
default List<? extends Entity> getEntities(Region region) {
return getParent().getEntities(region);
}
@Override
default List<? extends Entity> getEntities() {
return getParent().getEntities();
}
@Override
@Nullable
default Entity createEntity(Location location, BaseEntity entity) {
return getParent().createEntity(location, entity);
}
@Override
@Nullable
default void removeEntity(int x, int y, int z, UUID uuid) {
getParent().removeEntity(x, y, z, uuid);
}
@Override
default boolean isWorld() {
return getParent().isWorld();
}
@Override
default boolean regenerateChunk(int x, int z, @Nullable BiomeType type, @Nullable Long seed) {
return getParent().regenerateChunk(x, z, type, seed);
}
@Override
default int getHighestTerrainBlock(int x, int z, int minY, int maxY) {
return getParent().getHighestTerrainBlock(x, z, minY, maxY);
}
@Override
default int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) {
return getParent().getHighestTerrainBlock(x, z, minY, maxY, filter);
}
@Override
default int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) {
return getParent().getNearestSurfaceLayer(x, z, y, minY, maxY);
}
@Override
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) {
return getParent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir);
}
@Override
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) {
return getParent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY);
}
@Override
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) {
return getParent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax);
}
@Override
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) {
return getParent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask);
}
@Override
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, boolean ignoreAir) {
return getParent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir);
}
@Override
default void addCaves(Region region) throws WorldEditException {
getParent().addCaves(region);
}
@Override
default void generate(Region region, GenBase gen) throws WorldEditException {
getParent().generate(region, gen);
}
@Override
default void addSchems(Region region, Mask mask, List<ClipboardHolder> clipboards, int rarity, boolean rotate) throws WorldEditException {
getParent().addSchems(region, mask, clipboards, rarity, rotate);
}
@Override
default void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException {
getParent().spawnResource(region, gen, rarity, frequency);
}
@Override
default boolean contains(BlockVector3 pt) {
return getParent().contains(pt);
}
@Override
default void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException {
getParent().addOre(region, mask, material, size, frequency, rarity, minY, maxY);
}
@Override
default void addOres(Region region, Mask mask) throws WorldEditException {
getParent().addOres(region, mask);
}
@Override
default List<Countable<BlockType>> getBlockDistribution(Region region) {
return getParent().getBlockDistribution(region);
}
@Override
default List<Countable<BlockState>> getBlockDistributionWithData(Region region) {
return getParent().getBlockDistributionWithData(region);
}
@Override
@Nullable
default Operation commit() {
return getParent().commit();
}
@Override
default boolean cancel() {
return getParent().cancel();
}
@Override
default int getMaxY() {
return getParent().getMaxY();
}
@Override
default BlockArrayClipboard lazyCopy(Region region) {
return getParent().lazyCopy(region);
}
@Override
default int countBlocks(Region region, Set<BaseBlock> searchBlocks) {
return getParent().countBlocks(region, searchBlocks);
}
@Override
default int countBlocks(Region region, Mask searchMask) {
return getParent().countBlocks(region, searchMask);
}
@Override
default <B extends BlockStateHolder<B>> int setBlocks(Region region, B block) throws MaxChangedBlocksException {
return getParent().setBlocks(region, block);
}
@Override
default int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException {
return getParent().setBlocks(region, pattern);
}
@Override
default <B extends BlockStateHolder<B>> int replaceBlocks(Region region, Set<BaseBlock> filter, B replacement) throws MaxChangedBlocksException {
return getParent().replaceBlocks(region, filter, replacement);
}
@Override
default int replaceBlocks(Region region, Set<BaseBlock> filter, Pattern pattern) throws MaxChangedBlocksException {
return getParent().replaceBlocks(region, filter, pattern);
}
@Override
default int replaceBlocks(Region region, Mask mask, Pattern pattern) throws MaxChangedBlocksException {
return getParent().replaceBlocks(region, mask, pattern);
}
@Override
default int center(Region region, Pattern pattern) throws MaxChangedBlocksException {
return getParent().center(region, pattern);
}
@Override
default int setBlocks(Set<BlockVector3> vset, Pattern pattern) {
return getParent().setBlocks(vset, pattern);
}
@Override
default BlockState getBlock(BlockVector3 position) {
return getParent().getBlock(position);
}
@Override
default BaseBlock getFullBlock(BlockVector3 position) {
return getParent().getFullBlock(position);
}
@Override
default BiomeType getBiome(BlockVector2 position) {
return getParent().getBiome(position);
}
@Override
default BiomeType getBiomeType(int x, int z) {
return getParent().getBiomeType(x, z);
}
@Override
@Deprecated
default <T extends BlockStateHolder<T>> 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);
}
}

View File

@ -1,24 +1,24 @@
package com.boydti.fawe.beta;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.implementation.WorldChunkCache;
import com.boydti.fawe.beta.implementation.IChunkCache;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.registry.Keyed;
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;
import java.util.function.Supplier;
/**
* TODO: implement Extent (need to refactor Extent first) Interface for a queue based extent which
* uses chunks
*/
public interface IQueueExtent extends Flushable, Trimable, Extent, Keyed {
public interface IQueueExtent extends Flushable, Trimable, Extent {
@Override
default boolean isQueueEnabled() {
@ -54,7 +54,7 @@ public interface IQueueExtent extends Flushable, Trimable, Extent, Keyed {
void disableQueue();
void init(WorldChunkCache world); // TODO NOT IMPLEMENTED replace with supplier
void init(Extent extent, IChunkCache<IChunkGet> get, IChunkCache<IChunkSet> set);
/**
* Get the cached get object
@ -64,7 +64,7 @@ public interface IQueueExtent extends Flushable, Trimable, Extent, Keyed {
* @param supplier
* @return
*/
IChunkGet getCachedGet(int x, int z, Supplier<IChunkGet> supplier);
IChunkGet getCachedGet(int x, int z);
/**
* Get the cached chunk set object
@ -73,7 +73,7 @@ public interface IQueueExtent extends Flushable, Trimable, Extent, Keyed {
* @param supplier
* @return
*/
IChunkSet getCachedSet(int x, int z, Supplier<IChunkSet> supplier);
IChunkSet getCachedSet(int x, int z);
/**
* Get the IChunk at a position (and cache it if it's not already)
@ -100,6 +100,12 @@ public interface IQueueExtent extends Flushable, Trimable, Extent, Keyed {
return chunk.setBlock(x & 15, y, z & 15, state);
}
@Override
default boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
final IChunk chunk = getCachedChunk(x >> 4, z >> 4);
return chunk.setTile(x & 15, y, z & 15, tile);
}
@Override
default boolean setBiome(int x, int y, int z, BiomeType biome) {
final IChunk chunk = getCachedChunk(x >> 4, z >> 4);
@ -130,7 +136,7 @@ public interface IQueueExtent extends Flushable, Trimable, Extent, Keyed {
@Override
default BlockVector3 getMaximumPoint() {
return BlockVector3.at(30000000, FaweCache.WORLD_MAX_Y, 30000000);
return BlockVector3.at(30000000, FaweCache.IMP.WORLD_MAX_Y, 30000000);
}
/**

View File

@ -14,4 +14,6 @@ public interface Trimable {
* @return if this object is empty at the end of the trim, and can therefore be deleted
*/
boolean trim(boolean aggressive);
default void recycle() {}
}

View File

@ -0,0 +1,77 @@
package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.Trimable;
import com.boydti.fawe.util.MathMan;
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;
public class ChunkCache<T extends Trimable> implements IChunkCache<T> {
protected final Long2ObjectLinkedOpenHashMap<WeakReference<T>> getCache;
private final IChunkCache<T> delegate;
protected ChunkCache(IChunkCache<T> delegate) {
this.getCache = new Long2ObjectLinkedOpenHashMap<>();
this.delegate = delegate;
}
/**
* 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
*/
@Override
public synchronized T get(int x, int z) {
long pair = MathMan.pairInt(x, z);
final WeakReference<T> ref = getCache.get(pair);
if (ref != null) {
final T blocks = ref.get();
if (blocks != null) {
return blocks;
}
}
final T blocks = newChunk(x, z);
getCache.put(pair, new WeakReference<>(blocks));
return blocks;
}
public T newChunk(int chunkX, int chunkZ) {
return delegate.get(chunkX, chunkZ);
}
@Override
public synchronized boolean trim(boolean aggressive) {
if (getCache.size() == 0) {
return true;
}
boolean result = true;
if (!getCache.isEmpty()) {
final ObjectIterator<Long2ObjectMap.Entry<WeakReference<T>>> iter = getCache
.long2ObjectEntrySet().fastIterator();
while (iter.hasNext()) {
final Long2ObjectMap.Entry<WeakReference<T>> entry = iter.next();
final WeakReference<T> value = entry.getValue();
final T igb = value.get();
if (igb == null) {
iter.remove();
} else {
result = false;
if (!aggressive) {
return false;
}
synchronized (igb) {
igb.trim(true);
}
}
}
}
return result;
}
}

View File

@ -0,0 +1,135 @@
package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IBlocks;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.util.MathMan;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Future;
public class FallbackChunkGet implements IChunkGet {
private final int bx, bz;
private final Extent extent;
public FallbackChunkGet(Extent extent, int chunkX, int chunkZ) {
this.extent = extent;
this.bx = chunkX << 4;
this.bz = chunkZ << 4;
}
@Override
public BaseBlock getFullBlock(int x, int y, int z) {
return extent.getFullBlock(bx + x, y, bz + z);
}
@Override
public BiomeType getBiomeType(int x, int z) {
return extent.getBiomeType(bx + x, bz + z);
}
@Override
public BlockState getBlock(int x, int y, int z) {
return extent.getBlock(bx + x, y, bz + z);
}
@Override
public CompoundTag getTag(int x, int y, int z) {
return extent.getFullBlock(bx + x, y, bz + z).getNbtData();
}
@Override
public boolean trim(boolean aggressive) {
return true;
}
@Override
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
for (int layer = 0; layer < 16; layer++) {
if (set.hasSection(layer)) {
char[] arr = set.getArray(layer);
int by = layer << 4;
for (int y = 0, i = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++, i++) {
char ordinal = arr[i];
if (ordinal != 0) {
BlockState block = BlockState.getFromOrdinal(ordinal);
extent.setBlock(bx + x, by + y, bz + z, block);
}
}
}
}
}
}
Map<Short, CompoundTag> tiles = set.getTiles();
if (!tiles.isEmpty()) {
for (Map.Entry<Short, CompoundTag> entry : tiles.entrySet()) {
short blockHash = entry.getKey();
final int x = (blockHash >> 12 & 0xF) + bx;
final int y = (blockHash & 0xFF);
final int z = (blockHash >> 8 & 0xF) + bz;
extent.setTile(bx + x, y, bz + z, entry.getValue());
}
}
Set<CompoundTag> spawns = set.getEntities();
if (!spawns.isEmpty()) {
for (CompoundTag spawn : spawns) {
BaseEntity ent = new BaseEntity(spawn);
extent.createEntity(ent.getLocation(extent), ent);
}
}
Set<UUID> kills = set.getEntityRemoves();
if (!kills.isEmpty()) {
for (UUID kill : kills) {
extent.removeEntity(0, 0, 0, kill);
}
}
BiomeType[] biomes = set.getBiomes();
if (biomes != null) {
for (int z = 0, i = 0; z < 16; z++) {
for (int x = 0; x < 16; x++, i++) {
BiomeType biome = biomes[i];
if (biome != null) {
extent.setBiome(bx + x, 0, bz + z, biome);
}
}
}
}
return null;
}
@Override
public char[] load(int layer) {
char[] arr = FaweCache.IMP.SECTION_BITS_TO_CHAR.get();
int by = layer << 4;
for (int y = 0, i = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++, i++) {
arr[i] = getBlock(bx + x, by + y, bz + z).getOrdinalChar();
}
}
}
return arr;
}
@Override
public boolean hasSection(int layer) {
return true;
}
@Override
public IBlocks reset() {
return null;
}
}

View File

@ -0,0 +1,16 @@
package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.beta.Trimable;
/**
* 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 interface IChunkCache<T> extends Trimable {
T get(int chunkX, int chunkZ);
@Override
default boolean trim(boolean aggressive) {
return false;
}
}

View File

@ -0,0 +1,63 @@
package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IBlocks;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.concurrent.Future;
public enum NullChunkGet implements IChunkGet {
INSTANCE
;
@Override
public BaseBlock getFullBlock(int x, int y, int z) {
return BlockTypes.AIR.getDefaultState().toBaseBlock();
}
@Override
public BiomeType getBiomeType(int x, int z) {
return BiomeTypes.FOREST;
}
@Override
public BlockState getBlock(int x, int y, int z) {
return BlockTypes.AIR.getDefaultState();
}
@Override
public CompoundTag getTag(int x, int y, int z) {
return null;
}
@Override
public boolean trim(boolean aggressive) {
return true;
}
@Override
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
return null;
}
@Override
public char[] load(int layer) {
return FaweCache.IMP.EMPTY_CHAR_4096;
}
@Override
public boolean hasSection(int layer) {
return false;
}
@Override
public IBlocks reset() {
return null;
}
}

View File

@ -3,6 +3,8 @@ package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
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.Trimable;
import com.boydti.fawe.config.Settings;
@ -11,6 +13,7 @@ import com.boydti.fawe.util.MemUtil;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.wrappers.WorldWrapper;
import com.google.common.util.concurrent.Futures;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.world.World;
import java.lang.ref.WeakReference;
import java.util.HashMap;
@ -33,16 +36,11 @@ public abstract class QueueHandler implements Trimable, Runnable {
private ForkJoinPool forkJoinPoolPrimary = new ForkJoinPool();
private ForkJoinPool forkJoinPoolSecondary = new ForkJoinPool();
private ThreadPoolExecutor blockingExecutor = FaweCache.newBlockingExecutor();
private ThreadPoolExecutor blockingExecutor = FaweCache.IMP.newBlockingExecutor();
private ConcurrentLinkedQueue<FutureTask> syncTasks = new ConcurrentLinkedQueue<>();
private Map<World, WeakReference<WorldChunkCache>> chunkCache = new HashMap<>();
private IterableThreadLocal<IQueueExtent> queuePool = new IterableThreadLocal<IQueueExtent>() {
@Override
public IQueueExtent init() {
return create();
}
};
private Map<World, WeakReference<IChunkCache<IChunkGet>>> chunkCache = new HashMap<>();
private IterableThreadLocal<IQueueExtent> queuePool = new IterableThreadLocal<>(QueueHandler.this::create);
/**
* Used to calculate elapsed time in milliseconds and ensure block placement doesn't lag the
* server
@ -50,6 +48,7 @@ public abstract class QueueHandler implements Trimable, Runnable {
private long last;
private long allocate = 50;
private double targetTPS = 18;
public QueueHandler() {
TaskManager.IMP.repeat(this, 1);
}
@ -197,18 +196,18 @@ public abstract class QueueHandler implements Trimable, Runnable {
* @param world
* @return
*/
public WorldChunkCache getOrCreate(World world) {
public IChunkCache<IChunkGet> getOrCreateWorldCache(World world) {
world = WorldWrapper.unwrap(world);
synchronized (chunkCache) {
final WeakReference<WorldChunkCache> ref = chunkCache.get(world);
final WeakReference<IChunkCache<IChunkGet>> ref = chunkCache.get(world);
if (ref != null) {
final WorldChunkCache cached = ref.get();
final IChunkCache<IChunkGet> cached = ref.get();
if (cached != null) {
return cached;
}
}
final WorldChunkCache created = new WorldChunkCache(world);
final IChunkCache<IChunkGet> created = new ChunkCache<>(world);
chunkCache.put(world, new WeakReference<>(created));
return created;
}
@ -222,7 +221,9 @@ public abstract class QueueHandler implements Trimable, Runnable {
public IQueueExtent getQueue(World world) {
final IQueueExtent queue = queuePool.get();
queue.init(getOrCreate(world));
IChunkCache<IChunkGet> cacheGet = getOrCreateWorldCache(world);
IChunkCache<IChunkSet> set = null; // TODO cache?
queue.init(world, cacheGet, set);
return queue;
}
@ -230,13 +231,13 @@ public abstract class QueueHandler implements Trimable, Runnable {
public boolean trim(boolean aggressive) {
boolean result = true;
synchronized (chunkCache) {
final Iterator<Map.Entry<World, WeakReference<WorldChunkCache>>> iter = chunkCache
final Iterator<Map.Entry<World, WeakReference<IChunkCache<IChunkGet>>>> iter = chunkCache
.entrySet().iterator();
while (iter.hasNext()) {
final Map.Entry<World, WeakReference<WorldChunkCache>> entry = iter.next();
final WeakReference<WorldChunkCache> value = entry.getValue();
final WorldChunkCache cache = value.get();
if (cache == null || cache.size() == 0 || cache.trim(aggressive)) {
final Map.Entry<World, WeakReference<IChunkCache<IChunkGet>>> entry = iter.next();
final WeakReference<IChunkCache<IChunkGet>> value = entry.getValue();
final IChunkCache<IChunkGet> cache = value.get();
if (cache.trim(aggressive)) {
iter.remove();
continue;
}

View File

@ -1,41 +1,49 @@
package com.boydti.fawe.beta.implementation;
import static com.google.common.base.Preconditions.checkNotNull;
import com.boydti.fawe.Fawe;
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.blocks.CharSetBlocks;
import com.boydti.fawe.beta.implementation.holder.ChunkHolder;
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 com.sk89q.worldedit.extent.Extent;
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.function.Supplier;
/**
* Single threaded implementation for IQueueExtent (still abstract) - Does not implement creation of
* chunks (that has to implemented by the platform e.g. Bukkit)
* <p>
* This queue is reusable {@link #init(WorldChunkCache)}
* This queue is reusable {@link #init(IChunkCache)}
*/
public abstract class SingleThreadQueueExtent implements IQueueExtent {
// Pool discarded chunks for reuse (can safely be cleared by another thread)
private static final ConcurrentLinkedQueue<IChunk> CHUNK_POOL = new ConcurrentLinkedQueue<>();
// // Pool discarded chunks for reuse (can safely be cleared by another thread)
// private static final ConcurrentLinkedQueue<IChunk> CHUNK_POOL = new ConcurrentLinkedQueue<>();
// Chunks currently being queued / worked on
private final Long2ObjectLinkedOpenHashMap<IChunk> chunks = new Long2ObjectLinkedOpenHashMap<>();
private WorldChunkCache cache;
private IChunkCache<IChunkGet> cacheGet;
private IChunkCache<IChunkSet> cacheSet;
private boolean initialized;
private Thread currentThread;
private ConcurrentLinkedQueue<Future> submissions = new ConcurrentLinkedQueue<>();
// Last access pointers
private IChunk lastChunk;
private long lastPair = Long.MAX_VALUE;
private boolean enabledQueue = true;
/**
* Safety check to ensure that the thread being used matches the one being initialized on. - Can
* be removed later
@ -48,23 +56,42 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
}
@Override
public IChunkGet getCachedGet(int x, int z, Supplier<IChunkGet> supplier) {
return cache.get(MathMan.pairInt(x, z), supplier);
public void enableQueue() {
enabledQueue = true;
}
@Override
public void disableQueue() {
enabledQueue = false;
}
@Override
public IChunkGet getCachedGet(int x, int z) {
return cacheGet.get(x, z);
}
@Override
public IChunkSet getCachedSet(int x, int z) {
return cacheSet.get(x, z);
}
/**
* Resets the queue.
*/
protected synchronized void reset() {
if (!initialized) return;
checkThread();
cache = null;
if (!chunks.isEmpty()) {
CHUNK_POOL.addAll(chunks.values());
for (IChunk chunk : chunks.values()) {
chunk.recycle();
}
chunks.clear();
}
enabledQueue = true;
lastChunk = null;
lastPair = Long.MAX_VALUE;
currentThread = null;
initialized = false;
}
/**
@ -73,17 +100,18 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
* @param cache
*/
@Override
public synchronized void init(WorldChunkCache cache) {
if (this.cache != null) {
reset();
}
public synchronized void init(Extent extent, IChunkCache<IChunkGet> get, IChunkCache<IChunkSet> set) {
reset();
currentThread = Thread.currentThread();
checkNotNull(cache);
this.cache = cache;
}
public void returnToPool(IChunk chunk) {
CHUNK_POOL.add(chunk);
if (get == null) {
get = (x, z) -> { throw new UnsupportedOperationException(); };
}
if (set == null) {
set = (x, z) -> CharSetBlocks.newInstance();
}
this.cacheGet = get;
this.cacheSet = set;
initialized = true;
}
@Override
@ -116,8 +144,9 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
*/
private <T extends Future<T>> T submitUnchecked(IChunk<T> chunk) {
if (chunk.isEmpty()) {
CHUNK_POOL.add(chunk);
return (T) (Future) Futures.immediateFuture(null);
chunk.recycle();
Future result = Futures.immediateFuture(null);
return (T) result;
}
if (Fawe.isMainThread()) {
@ -130,7 +159,8 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
@Override
public synchronized boolean trim(boolean aggressive) {
// TODO trim individial chunk sections
CHUNK_POOL.clear();
cacheGet.trim(aggressive);
cacheSet.trim(aggressive);
if (Thread.currentThread() == currentThread) {
lastChunk = null;
lastPair = Long.MAX_VALUE;
@ -157,10 +187,7 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
* @return IChunk
*/
private IChunk poolOrCreate(int X, int Z) {
IChunk next = CHUNK_POOL.poll();
if (next == null) {
next = create(false);
}
IChunk next = create(false);
next.init(this, X, Z);
return next;
}
@ -187,7 +214,7 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
checkThread();
final int size = chunks.size();
final boolean lowMem = MemUtil.isMemoryLimited();
if (lowMem || size > Settings.IMP.QUEUE.TARGET_SIZE) {
if (enabledQueue && (lowMem || size > Settings.IMP.QUEUE.TARGET_SIZE)) {
chunk = chunks.removeFirst();
final Future future = submitUnchecked(chunk);
if (future != null && !future.isDone()) {
@ -211,6 +238,11 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
return chunk;
}
@Override
public IChunk create(boolean isFull) {
return ChunkHolder.newInstance();
}
private void pollSubmissions(int targetSize, boolean aggressive) {
final int overflow = submissions.size() - targetSize;
if (aggressive) {

View File

@ -63,7 +63,7 @@ public class BitSetBlocks implements IChunkSet {
@Override
public char[] getArray(int layer) {
char[] arr = FaweCache.SECTION_BITS_TO_CHAR.get();
char[] arr = FaweCache.IMP.SECTION_BITS_TO_CHAR.get();
MemBlockSet.IRow nullRowY = row.getRow(layer);
if (nullRowY instanceof MemBlockSet.RowY) {
char value = blockState.getOrdinalChar();

View File

@ -6,6 +6,8 @@ import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.concurrent.Future;
public abstract class CharGetBlocks extends CharBlocks implements IChunkGet {
@Override

View File

@ -1,6 +1,8 @@
package com.boydti.fawe.beta.implementation.blocks;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.util.MathMan;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.world.biome.BiomeType;
@ -14,21 +16,21 @@ import java.util.Set;
import java.util.UUID;
public class CharSetBlocks extends CharBlocks implements IChunkSet {
private static FaweCache.Pool<CharSetBlocks> POOL = FaweCache.IMP.registerPool(CharSetBlocks.class, CharSetBlocks::new, Settings.IMP.QUEUE.POOL);
public static CharSetBlocks newInstance() {
return POOL.poll();
}
public BiomeType[] biomes;
public HashMap<Short, CompoundTag> tiles;
public HashSet<CompoundTag> entities;
public HashSet<UUID> entityRemoves;
public CharSetBlocks(CharBlocks other) {
super(other);
if (other instanceof CharSetBlocks) {
}
}
public CharSetBlocks() {
private CharSetBlocks() {}
@Override
public void recycle() {
POOL.offer(this);
}
@Override

View File

@ -1,5 +1,6 @@
package com.boydti.fawe.beta.implementation.holder;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.ChunkFilterBlock;
import com.boydti.fawe.beta.Filter;
import com.boydti.fawe.beta.FilterBlockMask;
@ -10,19 +11,67 @@ 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.blocks.CharSetBlocks;
import com.boydti.fawe.config.Settings;
import com.sk89q.jnbt.CompoundTag;
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 java.util.concurrent.Future;
import java.util.function.Supplier;
import javax.annotation.Nullable;
/**
* An abstract {@link IChunk} class that implements basic get/set blocks
*/
public abstract class ChunkHolder implements IChunk {
public class ChunkHolder<T extends Future<T>> implements IChunk {
private static FaweCache.Pool<ChunkHolder> POOL = FaweCache.IMP.registerPool(ChunkHolder.class, ChunkHolder::new, Settings.IMP.QUEUE.POOL);
public static ChunkHolder newInstance() {
return POOL.poll();
}
private IChunkGet get;
private IChunkSet set;
private IBlockDelegate delegate;
private IQueueExtent extent;
private int chunkX;
private int chunkZ;
public ChunkHolder() {
this.delegate = NULL;
}
public void init(IBlockDelegate delegate) {
this.delegate = delegate;
}
@Override
public void recycle() {
delegate = NULL;
}
public IBlockDelegate getDelegate() {
return delegate;
}
@Override
public IQueueExtent getQueue() {
return extent;
}
@Override
public boolean setTile(int x, int y, int z, CompoundTag tag) {
return false;
}
@Override
public char[] load(int layer) {
return getOrCreateGet().load(layer);
}
public static final IBlockDelegate BOTH = new IBlockDelegate() {
@Override
@ -160,20 +209,6 @@ public abstract class ChunkHolder implements IChunk {
return chunk.getFullBlock(x, y, z);
}
};
private IChunkGet get;
private IChunkSet set;
private IBlockDelegate delegate;
private IQueueExtent extent;
private int chunkX;
private int chunkZ;
public ChunkHolder() {
this.delegate = NULL;
}
public ChunkHolder(IBlockDelegate delegate) {
this.delegate = delegate;
}
@Override
public void flood(Flood flood, FilterBlockMask mask, ChunkFilterBlock block) {
@ -264,14 +299,6 @@ public abstract class ChunkHolder implements IChunk {
return set;
}
/**
* Create the settable part of this chunk (defaults to a char array)
* @return
*/
public IChunkSet createSet() {
return new CharSetBlocks();
}
/**
* Create a wrapped set object
* - The purpose of wrapping is to allow different extents to intercept / alter behavior
@ -279,13 +306,7 @@ public abstract class ChunkHolder implements IChunk {
* @return
*/
private IChunkSet newWrappedSet() {
if (extent instanceof SingleThreadQueueExtent) {
IChunkSet newSet = extent.getCachedSet(chunkX, chunkZ, this::createSet);
if (newSet != null) {
return newSet;
}
}
return createSet();
return extent.getCachedSet(chunkX, chunkZ);
}
/**
@ -295,17 +316,9 @@ public abstract class ChunkHolder implements IChunk {
* @return
*/
private IChunkGet newWrappedGet() {
if (extent instanceof SingleThreadQueueExtent) {
IChunkGet newGet = extent.getCachedGet(chunkX, chunkZ, this::get);
if (newGet != null) {
return newGet;
}
}
return get();
return extent.getCachedGet(chunkX, chunkZ);
}
public abstract IChunkGet get();
@Override
public void init(IQueueExtent extent, int chunkX, int chunkZ) {
this.extent = extent;
@ -320,6 +333,22 @@ public abstract class ChunkHolder implements IChunk {
get = null;
}
@Override
public synchronized T call() {
if (get != null && set != null) {
return getOrCreateGet().call(getOrCreateSet(), this::recycle);
}
return null;
}
@Override
public T call(IChunkSet set, Runnable finalize) {
if (get != null && set != null) {
return getOrCreateGet().call(set, finalize);
}
return null;
}
public IQueueExtent getExtent() {
return extent;
}

View File

@ -1,27 +1,29 @@
package com.boydti.fawe.beta.implementation.holder;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.IDelegateChunk;
import com.sk89q.jnbt.CompoundTag;
import java.util.concurrent.Future;
/**
* Implementation of IDelegateChunk
*
* @param <T>
*/
public class DelegateChunk<T extends IChunk> implements IDelegateChunk {
public class DelegateChunk<U extends IChunk> implements IDelegateChunk<U> {
private T parent;
private U parent;
public DelegateChunk(T parent) {
public DelegateChunk(U parent) {
this.parent = parent;
}
@Override
public final T getParent() {
public final U getParent() {
return parent;
}
public final void setParent(T parent) {
public final void setParent(U parent) {
this.parent = parent;
}
}

View File

@ -475,7 +475,7 @@ public class AnvilCommands {
// });
// if (useData) {
// for (long[] c : map) {
// BaseBlock block = FaweCache.CACHE_BLOCK[(int) c[0]];
// BaseBlock block = FaweCache.IMP.CACHE_BLOCK[(int) c[0]];
// String name = BlockType.fromID(block.getId()).getName();
// String str = String.format("%-7s (%.3f%%) %s #%d:%d",
// String.valueOf(c[1]),

View File

@ -293,7 +293,13 @@ public class Settings extends Config {
" - Low values may result in FAWE waiting on requests to the main thread",
" - Higher values use more memory and isn't noticeably faster",
})
public int PRELOAD_CHUNKS = 32;
public int PRELOAD_CHUNKS = 100000;
@Comment({
"If pooling is enabled (reduces GC, higher memory usage)",
" - Enable to improve performance at the expense of memory",
})
public boolean POOL = true;
@Comment({
"Discard edits which have been idle for a certain amount of time (ms)",

View File

@ -58,10 +58,10 @@ public class LoggingChangeSet extends AbstractDelegateChangeSet {
// loc.x = x;
// loc.y = y;
// loc.z = z;
// oldBlock.id = FaweCache.getId(combinedId4DataFrom);
// oldBlock.data = FaweCache.getData(combinedId4DataFrom);
// newBlock.id = FaweCache.getId(combinedId4DataTo);
// newBlock.data = FaweCache.getData(combinedId4DataTo);
// oldBlock.id = FaweCache.IMP.getId(combinedId4DataFrom);
// oldBlock.data = FaweCache.IMP.getData(combinedId4DataFrom);
// newBlock.id = FaweCache.IMP.getId(combinedId4DataTo);
// newBlock.data = FaweCache.IMP.getData(combinedId4DataTo);
// // Log to BlocksHub and parent
// api.logBlock(loc, player, world, oldBlock, newBlock);
parent.add(x, y, z, combinedId4DataFrom, combinedId4DataTo);

View File

@ -1,7 +1,12 @@
package com.boydti.fawe.object.brush.visualization.cfi;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IBlocks;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.IQueueExtent;
import com.boydti.fawe.beta.implementation.FallbackChunkGet;
import com.boydti.fawe.object.FaweInputStream;
import com.boydti.fawe.object.FaweOutputStream;
import com.boydti.fawe.object.FawePlayer;
@ -44,6 +49,7 @@ import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
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.BlockStateHolder;
@ -58,6 +64,7 @@ import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadLocalRandom;
import javax.annotation.Nullable;
@ -65,13 +72,6 @@ import javax.annotation.Nullable;
public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Drawable, VirtualWorld {
private final MutableBlockVector3 mutable = new MutableBlockVector3();
private final ThreadLocal<int[]> indexStore = new ThreadLocal<int[]>() {
@Override
protected int[] initialValue() {
return new int[256];
}
};
private final DifferentialBlockBuffer blocks;
protected final DifferentialArray<byte[]> heights;
protected final DifferentialArray<byte[]> biomes;
@ -1571,7 +1571,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
int[] floor = this.floor.get();
int[] overlay = this.overlay != null ? this.overlay.get() : null;
try {
int[] indexes = indexStore.get();
int[] indexes = FaweCache.IMP.INDEX_STORE.get();
int index;
int maxY = 0;
@ -1902,12 +1902,6 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
}));
}
@Override
protected void finalize() throws Throwable {
IterableThreadLocal.clean(indexStore);
super.finalize();
}
@Override
public int getMaxY() {
return 255;
@ -1973,4 +1967,10 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
// TODO Auto-generated method stub
return null;
}
@Override
public IChunkGet get(int x, int z) {
Fawe.debug("Should not be using buffering with HMMG");
return new FallbackChunkGet(this, x, z);
}
}

View File

@ -79,10 +79,10 @@ public class WritableMCAChunk {
}
public void write(NBTOutputStream nbtOut) throws IOException {
int[] blockToPalette = FaweCache.BLOCK_TO_PALETTE.get();
int[] paletteToBlock = FaweCache.PALETTE_TO_BLOCK.get();
long[] blockstates = FaweCache.BLOCK_STATES.get();
int[] blocksCopy = FaweCache.SECTION_BLOCKS.get();
int[] blockToPalette = FaweCache.IMP.BLOCK_TO_PALETTE.get();
int[] paletteToBlock = FaweCache.IMP.PALETTE_TO_BLOCK.get();
long[] blockstates = FaweCache.IMP.BLOCK_STATES.get();
int[] blocksCopy = FaweCache.IMP.SECTION_BLOCKS.get();
nbtOut.writeNamedTagName("", NBTConstants.TYPE_COMPOUND);
nbtOut.writeNamedTag("DataVersion", 1631);

View File

@ -52,7 +52,7 @@ public abstract class FaweChangeSet implements ChangeSet {
public FaweChangeSet(String world) {
this.worldName = world;
this.mainThread = Fawe.get() == null || Fawe.isMainThread();
this.layers = FaweCache.CHUNK_LAYERS;
this.layers = FaweCache.IMP.CHUNK_LAYERS;
}
public FaweChangeSet(World world) {

View File

@ -223,7 +223,7 @@ public class ClipboardRemapper {
// String name = entry.getKey();
// int id = value.get("id").getAsInt();
// int data = value.get("data").getAsInt();
// int combined = FaweCache.getCombined(id, data);
// int combined = FaweCache.IMP.getCombined(id, data);
// map.putIfAbsent(name, new ArrayList<>());
// map.get(name).add(combined);
// }
@ -496,7 +496,7 @@ public class ClipboardRemapper {
// int combined = block.getCombined();
// if (remap[combined]) {
// char value = remapCombined[combined];
// BaseBlock newBlock = FaweCache.CACHE_BLOCK[value];
// BaseBlock newBlock = FaweCache.IMP.CACHE_BLOCK[value];
// newBlock.setNbtData(block.getNbtData());
// return newBlock;
// }

View File

@ -1,5 +1,6 @@
package com.boydti.fawe.object.collection;
import com.boydti.fawe.util.IOUtil;
import com.boydti.fawe.util.MainUtil;
import java.lang.ref.Reference;
import java.lang.reflect.Array;
@ -8,12 +9,27 @@ import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Supplier;
public abstract class IterableThreadLocal<T> extends ThreadLocal<T> implements Iterable<T> {
public class IterableThreadLocal<T> extends ThreadLocal<T> implements Iterable<T> {
private final ConcurrentLinkedDeque<T> allValues = new ConcurrentLinkedDeque<>();
private final Supplier<T> supplier;
public IterableThreadLocal() {
public IterableThreadLocal(Supplier<T> supplier) {
this.supplier = supplier;
}
public IterableThreadLocal(Supplier<T> supplier, Function<T, T> modifier) {
this.supplier = supplier;
}
public IterableThreadLocal(Supplier<T> supplier, Consumer<T> modifier) {
this.supplier = supplier;
}
@Override
@ -33,7 +49,7 @@ public abstract class IterableThreadLocal<T> extends ThreadLocal<T> implements I
}
public T init() {
return null;
return supplier.get();
}
public void clean() {

View File

@ -20,7 +20,7 @@ import org.jetbrains.annotations.NotNull;
*/
public final class MemBlockSet extends BlockSet {
public final static int BITS_PER_WORD = 6;
public final static int WORDS = FaweCache.BLOCKS_PER_LAYER >> BITS_PER_WORD;
public final static int WORDS = FaweCache.IMP.BLOCKS_PER_LAYER >> BITS_PER_WORD;
public final static IRow NULL_ROW_X = new NullRowX();
public final static IRow NULL_ROW_Z = new NullRowZ();
public final static IRow NULL_ROW_Y = new NullRowY();
@ -354,7 +354,7 @@ public final class MemBlockSet extends BlockSet {
maxy = y + 1;
}
by = (Y << 4) + y;
if (by == FaweCache.WORLD_MAX_Y) return FaweCache.WORLD_MAX_Y;
if (by == FaweCache.IMP.WORLD_MAX_Y) return FaweCache.IMP.WORLD_MAX_Y;
break outer;
}
}
@ -823,7 +823,7 @@ public final class MemBlockSet extends BlockSet {
private final IRow[] rows;
public RowZ() {
this.rows = new IRow[FaweCache.CHUNK_LAYERS];
this.rows = new IRow[FaweCache.IMP.CHUNK_LAYERS];
reset();
}
@ -866,7 +866,7 @@ public final class MemBlockSet extends BlockSet {
}
public void reset() {
for (int i = 0; i < FaweCache.CHUNK_LAYERS; i++) rows[i] = NULL_ROW_Y;
for (int i = 0; i < FaweCache.IMP.CHUNK_LAYERS; i++) rows[i] = NULL_ROW_Y;
}
}

View File

@ -31,10 +31,10 @@ public abstract class FaweBlockMatcher {
// public boolean apply(BaseBlock oldBlock) {
// int currentId = oldBlock.getId();
// oldBlock.setId(id);
// if (FaweCache.hasData(currentId)) {
// if (FaweCache.IMP.hasData(currentId)) {
// oldBlock.setData(0);
// }
// if (FaweCache.hasNBT(currentId)) {
// if (FaweCache.IMP.hasNBT(currentId)) {
// oldBlock.setNbtData(null);
// }
// return true;
@ -47,7 +47,7 @@ public abstract class FaweBlockMatcher {
// int currentId = oldBlock.getId();
// oldBlock.setId(id);
// oldBlock.setData(data);
// if (FaweCache.hasNBT(currentId)) {
// if (FaweCache.IMP.hasNBT(currentId)) {
// oldBlock.setNbtData(null);
// }
// return true;
@ -67,10 +67,10 @@ public abstract class FaweBlockMatcher {
// BaseBlock replace = array[random.random(size)];
// int currentId = block.getId();
// block.setId(replace.getId());
// if (FaweCache.hasNBT(currentId)) {
// if (FaweCache.IMP.hasNBT(currentId)) {
// block.setNbtData(null);
// }
// if (FaweCache.hasData(currentId) || replace.getData() != 0) {
// if (FaweCache.IMP.hasData(currentId) || replace.getData() != 0) {
// block.setData(replace.getData());
// }
// return true;
@ -82,7 +82,7 @@ public abstract class FaweBlockMatcher {
public static FaweBlockMatcher fromBlock(BaseBlock block, boolean checkData) {
// final int id = block.getId();
// final int data = block.getData();
// if (checkData && FaweCache.hasData(id)) {
// if (checkData && FaweCache.IMP.hasData(id)) {
// return new FaweBlockMatcher() {
// @Override
// public boolean apply(BaseBlock block) {
@ -104,13 +104,13 @@ public abstract class FaweBlockMatcher {
// if (searchBlocks.size() == 1) {
// return fromBlock(searchBlocks.iterator().next(), checkData);
// }
// final boolean[] allowedId = new boolean[FaweCache.getId(Character.MAX_VALUE)];
// final boolean[] allowedId = new boolean[FaweCache.IMP.getId(Character.MAX_VALUE)];
// for (BaseBlock block : searchBlocks) {
// allowedId[block.getId()] = true;
// }
// final boolean[] allowed = new boolean[Character.MAX_VALUE];
// for (BaseBlock block : searchBlocks) {
// allowed[FaweCache.getCombined(block)] = true;
// allowed[FaweCache.IMP.getCombined(block)] = true;
// }
// if (checkData) {
// return new FaweBlockMatcher() {
@ -118,7 +118,7 @@ public abstract class FaweBlockMatcher {
// public boolean apply(BaseBlock block) {
// int id = block.getId();
// if (allowedId[id]) {
// if (FaweCache.hasData(id)) {
// if (FaweCache.IMP.hasData(id)) {
// return allowed[(id << 4) + block.getData()];
// }
// return true;

View File

@ -36,7 +36,7 @@ public class FuzzyRegionSelector extends PassthroughExtent implements RegionSele
.player(FawePlayer.wrap(player))
.changeSetNull()
.checkMemory(false)
.autoQueue(true)
.autoQueue(false)
.build());
this.player = player;
this.region = new FuzzyRegion(world, getExtent(), mask);

View File

@ -161,7 +161,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter {
if (width > WARN_SIZE || height > WARN_SIZE || length > WARN_SIZE) {
Fawe.debug("A structure longer than 32 is unsupported by minecraft (but probably still works)");
}
Map<String, Object> structure = FaweCache.asMap("version", 1, "author", owner);
Map<String, Object> structure = FaweCache.IMP.asMap("version", 1, "author", owner);
// ignored: version / owner
MutableBlockVector3 mutable = new MutableBlockVector3(0, 0, 0);
Int2ObjectArrayMap<Integer> indexes = new Int2ObjectArrayMap<>();
@ -211,10 +211,10 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter {
List<Integer> pos = Arrays.asList(point.getX() - min.getX(),
point.getY() - min.getY(), point.getZ() - min.getZ());
if (!block.hasNbtData()) {
blocks.add(FaweCache.asMap("state", index, "pos", pos));
blocks.add(FaweCache.IMP.asMap("state", index, "pos", pos));
} else {
blocks.add(
FaweCache.asMap("state", index, "pos", pos, "nbt", block.getNbtData()));
FaweCache.IMP.asMap("state", index, "pos", pos, "nbt", block.getNbtData()));
}
}
}
@ -234,14 +234,14 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter {
// Replace rotation data
nbtMap.put("Rotation", writeRotation(entity.getLocation()));
nbtMap.put("id", new StringTag(state.getType().getId()));
Map<String, Object> entityMap = FaweCache.asMap("pos", pos, "blockPos", blockPos, "nbt", nbt);
Map<String, Object> entityMap = FaweCache.IMP.asMap("pos", pos, "blockPos", blockPos, "nbt", nbt);
entities.add(entityMap);
}
}
if (!entities.isEmpty()) {
structure.put("entities", entities);
}
out.writeNamedTag("", FaweCache.asTag(structure));
out.writeNamedTag("", FaweCache.IMP.asTag(structure));
close();
}

View File

@ -25,10 +25,11 @@ public class FaweLocalBlockQueue extends LocalBlockQueue {
public final IQueueExtent IMP;
private final LegacyMapper legacyMapper;
private final World world;
public FaweLocalBlockQueue(String worldName) {
super(worldName);
World world = FaweAPI.getWorld(worldName);
this.world = FaweAPI.getWorld(worldName);
IMP = Fawe.get().getQueueHandler().getQueue(world);
legacyMapper = LegacyMapper.getInstance();
}
@ -104,7 +105,7 @@ public class FaweLocalBlockQueue extends LocalBlockQueue {
@Override
public String getWorld() {
return IMP.getId();
return world.getId();
}
@Override
@ -134,7 +135,7 @@ public class FaweLocalBlockQueue extends LocalBlockQueue {
@Override
public boolean setTile(int x, int y, int z, CompoundTag tag) {
IMP.setTile(x, y, z, (com.sk89q.jnbt.CompoundTag) FaweCache.asTag(tag));
IMP.setTile(x, y, z, (com.sk89q.jnbt.CompoundTag) FaweCache.IMP.asTag(tag));
return true;
}
}

View File

@ -116,7 +116,7 @@ public class FaweSchematicHandler extends SchematicHandler {
public void run(OutputStream output) {
try {
try (PGZIPOutputStream gzip = new PGZIPOutputStream(output)) {
CompoundTag weTag = (CompoundTag) FaweCache.asTag(tag);
CompoundTag weTag = (CompoundTag) FaweCache.IMP.asTag(tag);
try (NBTOutputStream nos = new NBTOutputStream(gzip)) {
Map<String, Tag> map = weTag.getValue();
nos.writeNamedTag("Schematic", map.getOrDefault("Schematic", weTag));

View File

@ -93,7 +93,7 @@ public final class BrushCache {
} else {
displayMap = ReflectionUtils.getMap(display.getValue());
}
displayMap.put("Lore", FaweCache.asTag(json.split("\\r?\\n")));
displayMap.put("Lore", FaweCache.IMP.asTag(json.split("\\r?\\n")));
String primary = (String) tool.getPrimary().getSettings().get(BrushSettings.SettingType.BRUSH);
String secondary = (String) tool.getSecondary().getSettings().get(BrushSettings.SettingType.BRUSH);
if (primary == null) primary = secondary;

View File

@ -5,6 +5,11 @@ import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Supplier;
public final class IOUtil {
@ -79,4 +84,30 @@ public final class IOUtil {
out.write(buf, 0, r);
}
}
public static <T> Supplier<T> supplier(IntFunction<T> funx, int size) {
return () -> funx.apply(size);
}
public static <T> Supplier<T> supplier(Supplier<T> supplier, Function<T, T> modifier) {
return () -> modifier.apply(supplier.get());
}
public static <T> Supplier<T> supplier(Supplier<T> supplier, Consumer<T> modifier) {
return () -> {
T instance = supplier.get();
modifier.accept(instance);
return instance;
};
}
public static <T> Supplier<T> supplier(Callable<T> callable) {
return () -> {
try {
return callable.call();
} catch (Exception e) {
throw new RuntimeException(e);
}
};
}
}

View File

@ -1,6 +1,8 @@
package com.boydti.fawe.wrappers;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.util.ExtentTraverser;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.jnbt.CompoundTag;
@ -12,6 +14,8 @@ import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.math.BlockVector2;
@ -57,6 +61,18 @@ public class WorldWrapper extends AbstractWorld {
return world;
}
public static World unwrap(Extent extent) {
if (extent.isWorld()) {
if (extent instanceof World) {
return unwrap((World) extent);
}
if (extent instanceof AbstractDelegateExtent) {
return unwrap(new ExtentTraverser<>(extent).find(World.class).get());
}
}
return null;
}
private WorldWrapper(World parent) {
this.parent = parent;
}
@ -267,4 +283,9 @@ public class WorldWrapper extends AbstractWorld {
public BlockVector3 getSpawnPosition() {
return parent.getSpawnPosition();
}
@Override
public IChunkGet get(int x, int z) {
return parent.get(x, z);
}
}

View File

@ -164,7 +164,7 @@ import org.slf4j.LoggerFactory;
* using the {@link ChangeSetExtent}.</p>
*/
@SuppressWarnings({"FieldCanBeLocal"})
public class EditSession extends PassthroughExtent implements SimpleWorld, AutoCloseable {
public class EditSession extends PassthroughExtent implements AutoCloseable {
private static final Logger log = LoggerFactory.getLogger(EditSession.class);
@ -3023,33 +3023,10 @@ public class EditSession extends PassthroughExtent implements SimpleWorld, AutoC
Direction.DOWN.toBlockVector(),
};
@Override
public String getName() {
return worldName;
}
@Override public @org.jetbrains.annotations.Nullable Path getStoragePath() {
return null;
}
@Override
public boolean clearContainerBlockContents(BlockVector3 pos) {
BaseBlock block = getFullBlock(pos);
CompoundTag nbt = block.getNbtData();
if (nbt != null) {
if (nbt.containsKey("items")) {
return setBlock(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(), block.toBlockState().toBaseBlock());
}
}
return false;
}
public boolean regenerate(final Region region) {
return regenerate(region, this);
}
@Override
public boolean regenerate(final Region region, final EditSession session) {
return session.regenerate(region, null, null);
}
@ -3164,69 +3141,4 @@ public class EditSession extends PassthroughExtent implements SimpleWorld, AutoC
}
return false;
}
@Override
public void simulateBlockMine(BlockVector3 position) {
TaskManager.IMP.sync((Supplier<Object>) () -> {
world.simulateBlockMine(position);
return null;
});
}
public boolean generateTree(TreeGenerator.TreeType type, BlockVector3 position) {
return generateTree(type, this, position);
}
@Override
public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 position) {
if (getWorld() != null) {
try {
return getWorld().generateTree(type, editSession, position);
} catch (MaxChangedBlocksException e) {
throw new RuntimeException(e);
}
}
return false;
}
@Override
public WeatherType getWeather() {
return world.getWeather();
}
@Override
public long getRemainingWeatherDuration() {
return world.getRemainingWeatherDuration();
}
@Override
public void setWeather(WeatherType weatherType) {
world.setWeather(weatherType);
}
@Override
public void setWeather(WeatherType weatherType, long duration) {
world.setWeather(weatherType, duration);
}
@Override
public void dropItem(Vector3 position, BaseItemStack item) {
world.dropItem(position, item);
}
@Override
public boolean playEffect(Vector3 position, int type, int data) {
return world.playEffect(position, type, data);
}
@Override
public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException {
return world.notifyAndLightBlock(position, previousType);
}
@Override
public BlockVector3 getSpawnPosition() {
return world.getSpawnPosition();
}
}

View File

@ -618,7 +618,7 @@ public class SelectionCommands {
maskOpt = new IdMask(world);
}
//TODO Make FuzzyRegionSelector accept actors
newSelector = new FuzzyRegionSelector((Player) actor, editSession, maskOpt);
newSelector = new FuzzyRegionSelector((Player) actor, world, maskOpt);
actor.print(BBC.SEL_FUZZY.s());
actor.print(BBC.SEL_LIST.s());
break;

View File

@ -22,8 +22,12 @@ package com.sk89q.worldedit.entity;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.NbtValued;
import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.entity.EntityTypes;
import javax.annotation.Nullable;
@ -56,6 +60,10 @@ public class BaseEntity implements NbtValued {
setNbtData(nbtData);
}
public BaseEntity(CompoundTag tag) {
this(EntityTypes.parse(tag.getString("Id")), tag);
}
/**
* Create a new base entity with no NBT data.
*
@ -76,6 +84,17 @@ public class BaseEntity implements NbtValued {
setNbtData(other.getNbtData());
}
public Location getLocation(Extent extent) {
ListTag posTag = nbtData.getListTag("Pos");
ListTag rotTag = nbtData.getListTag("Rotation");
double x = posTag.getDouble(0);
double y = posTag.getDouble(1);
double z = posTag.getDouble(2);
float yaw = rotTag.getFloat(0);
float pitch = rotTag.getFloat(1);
return new Location(extent, x, y, z, yaw, pitch);
}
@Override
public boolean hasNbtData() {
return true;

View File

@ -13,7 +13,7 @@ public class MutableBlockVector3 extends BlockVector3 {
}
public static MutableBlockVector3 get(int x, int y, int z) {
return FaweCache.MUTABLE_BLOCKVECTOR3.get().setComponents(x, y, z);
return FaweCache.IMP.MUTABLE_BLOCKVECTOR3.get().setComponents(x, y, z);
}
public MutableBlockVector3() {}

View File

@ -10,11 +10,11 @@ public class MutableVector3 extends Vector3 {
}
public static MutableVector3 get(int x, int y, int z) {
return FaweCache.MUTABLE_VECTOR3.get().setComponents(x, y, z);
return FaweCache.IMP.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);
return FaweCache.IMP.MUTABLE_VECTOR3.get().setComponents(x, y, z);
}
public MutableVector3(double x, double y, double z) {

View File

@ -43,12 +43,10 @@ public class LinkedFuture<T extends Future<T>> implements Future<T> {
@Override
public synchronized T get(long timeout, @NotNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
if (task != null) {
T result = task.get(timeout, unit);
if (task != null || !task.isDone()) {
task = task.get(timeout, unit);
if (task != null) {
return (T) this;
}
task = null;
}
return null;
}

View File

@ -19,6 +19,8 @@
package com.sk89q.worldedit.world;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.implementation.NullChunkGet;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
@ -132,6 +134,11 @@ public class NullWorld extends AbstractWorld {
return BlockVector3.ZERO;
}
@Override
public IChunkGet get(int x, int z) {
return NullChunkGet.INSTANCE;
}
@Override
public BlockState getBlock(int x, int y, int z) {
return BlockTypes.AIR.getDefaultState();

View File

@ -19,6 +19,8 @@
package com.sk89q.worldedit.world;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.implementation.IChunkCache;
import com.boydti.fawe.object.extent.LightingExtent;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
@ -47,7 +49,7 @@ import java.util.Locale;
/**
* Represents a world (dimension).
*/
public interface World extends Extent, Keyed {
public interface World extends Extent, Keyed, IChunkCache<IChunkGet> {
/**
* Get the name of the world.
@ -290,4 +292,7 @@ public interface World extends Extent, Keyed {
default String getId() {
return getName().replace(" ", "_").toLowerCase(Locale.ROOT);
}
@Override
IChunkGet get(int x, int z);
}