implement block get

This commit is contained in:
Jesse Boyd 2019-05-01 02:19:10 +10:00
parent 6692a2eb92
commit 33e119ccb6
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
39 changed files with 1234 additions and 198 deletions

View File

@ -10,7 +10,7 @@ repositories {
dependencies { dependencies {
compile project(':worldedit-core') compile project(':worldedit-core')
compile 'org.bukkit:craftbukkit-1.14:pre5' // compile 'org.bukkit:craftbukkit-1.14:pre5'
compile 'net.milkbowl.vault:VaultAPI:1.7' compile 'net.milkbowl.vault:VaultAPI:1.7'
compile 'com.sk89q:dummypermscompat:1.10' compile 'com.sk89q:dummypermscompat:1.10'
compile 'com.destroystokyo.paper:paper-api:1.13.2-R0.1-SNAPSHOT' compile 'com.destroystokyo.paper:paper-api:1.13.2-R0.1-SNAPSHOT'

View File

@ -2,6 +2,9 @@ package com.boydti.fawe.bukkit;
import com.boydti.fawe.Fawe; import com.boydti.fawe.Fawe;
import com.boydti.fawe.IFawe; import com.boydti.fawe.IFawe;
import com.boydti.fawe.beta.implementation.QueueHandler;
import com.boydti.fawe.bukkit.beta.BukkitQueue;
import com.boydti.fawe.bukkit.beta.BukkitQueueHandler;
import com.boydti.fawe.bukkit.chat.BukkitChatManager; import com.boydti.fawe.bukkit.chat.BukkitChatManager;
import com.boydti.fawe.bukkit.listener.AsyncTabCompleteListener; import com.boydti.fawe.bukkit.listener.AsyncTabCompleteListener;
import com.boydti.fawe.bukkit.listener.BrushListener; import com.boydti.fawe.bukkit.listener.BrushListener;
@ -144,6 +147,11 @@ public class FaweBukkit implements IFawe, Listener {
}); });
} }
@Override
public QueueHandler getQueueHandler() {
return new BukkitQueueHandler();
}
@Override @Override
public CUI getCUI(FawePlayer player) { public CUI getCUI(FawePlayer player) {
if (Settings.IMP.EXPERIMENTAL.VANILLA_CUI) { if (Settings.IMP.EXPERIMENTAL.VANILLA_CUI) {

View File

@ -92,16 +92,16 @@ public final class Spigot_v1_13_R2 extends CachedBukkitAdapter implements Bukkit
nbtCreateTagMethod.setAccessible(true); nbtCreateTagMethod.setAccessible(true);
} }
public int[] idbToStateOrdinal; public char[] idbToStateOrdinal;
private boolean init() { private boolean init() {
if (idbToStateOrdinal != null) return false; if (idbToStateOrdinal != null) return false;
idbToStateOrdinal = new int[Block.REGISTRY_ID.a()]; // size idbToStateOrdinal = new char[Block.REGISTRY_ID.a()]; // size
for (int i = 0; i < idbToStateOrdinal.length; i++) { for (int i = 0; i < idbToStateOrdinal.length; i++) {
BlockState state = BlockTypes.states[i]; BlockState state = BlockTypes.states[i];
BlockMaterial_1_13 material = (BlockMaterial_1_13) state.getMaterial(); BlockMaterial_1_13 material = (BlockMaterial_1_13) state.getMaterial();
int id = Block.REGISTRY_ID.getId(material.getState()); int id = Block.REGISTRY_ID.getId(material.getState());
idbToStateOrdinal[id] = state.getOrdinal(); idbToStateOrdinal[id] = state.getOrdinalChar();
} }
return true; return true;
} }
@ -532,6 +532,16 @@ public final class Spigot_v1_13_R2 extends CachedBukkitAdapter implements Bukkit
} }
} }
public char adaptToChar(IBlockData ibd) {
try {
int id = Block.REGISTRY_ID.getId(ibd);
return idbToStateOrdinal[id];
} catch (NullPointerException e) {
if (init()) return adaptToChar(ibd);
throw e;
}
}
@Override @Override
public BlockData adapt(BlockStateHolder state) { public BlockData adapt(BlockStateHolder state) {
BlockMaterial_1_13 material = (BlockMaterial_1_13) state.getMaterial(); BlockMaterial_1_13 material = (BlockMaterial_1_13) state.getMaterial();

View File

@ -2,23 +2,24 @@ package com.boydti.fawe.bukkit.beta;
import com.boydti.fawe.beta.Filter; import com.boydti.fawe.beta.Filter;
import com.boydti.fawe.beta.IGetBlocks; import com.boydti.fawe.beta.IGetBlocks;
import com.boydti.fawe.beta.IQueueExtent;
import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks; import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks;
import com.boydti.fawe.beta.implementation.holder.ChunkHolder; import com.boydti.fawe.beta.implementation.holder.ChunkHolder;
public class BukkitChunkHolder extends ChunkHolder<Boolean, BukkitQueue> { public class BukkitChunkHolder extends ChunkHolder<Boolean> {
@Override @Override
public void init(final BukkitQueue extent, final int X, final int Z) { public void init(final IQueueExtent extent, final int X, final int Z) {
super.init(extent, X, Z); super.init(extent, X, Z);
} }
@Override @Override
public IGetBlocks get() { public IGetBlocks get() {
BukkitQueue extent = getExtent(); BukkitQueue extent = (BukkitQueue) getExtent();
return null; return new BukkitGetBlocks(extent.getNmsWorld(), getX(), getZ());
} }
@Override @Override
public Boolean apply() { public boolean applyAsync() {
BukkitGetBlocks get = (BukkitGetBlocks) cachedGet(); BukkitGetBlocks get = (BukkitGetBlocks) cachedGet();
CharSetBlocks set = (CharSetBlocks) cachedSet(); CharSetBlocks set = (CharSetBlocks) cachedSet();
// - getBlocks // - getBlocks
@ -37,6 +38,11 @@ public class BukkitChunkHolder extends ChunkHolder<Boolean, BukkitQueue> {
// return true; // return true;
} }
@Override
public boolean applySync() {
return true;
}
@Override @Override
public void set(final Filter filter) { public void set(final Filter filter) {
// for each block // for each block

View File

@ -16,8 +16,13 @@ public class BukkitFullChunk extends ChunkHolder {
} }
@Override @Override
public Object apply() { public boolean applyAsync() {
return null; return false;
}
@Override
public boolean applySync() {
return false;
} }
@Override @Override

View File

@ -1,8 +1,175 @@
package com.boydti.fawe.bukkit.beta; package com.boydti.fawe.bukkit.beta;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
import com.boydti.fawe.bukkit.adapter.v1_13_1.Spigot_v1_13_R2;
import com.boydti.fawe.bukkit.v1_13.BukkitQueue_1_13;
import com.boydti.fawe.jnbt.anvil.BitArray4096;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockTypes;
import net.minecraft.server.v1_13_R2.Chunk;
import net.minecraft.server.v1_13_R2.ChunkCoordIntPair;
import net.minecraft.server.v1_13_R2.ChunkProviderServer;
import net.minecraft.server.v1_13_R2.ChunkSection; import net.minecraft.server.v1_13_R2.ChunkSection;
import net.minecraft.server.v1_13_R2.DataBits;
import net.minecraft.server.v1_13_R2.DataPalette;
import net.minecraft.server.v1_13_R2.DataPaletteBlock;
import net.minecraft.server.v1_13_R2.DataPaletteHash;
import net.minecraft.server.v1_13_R2.DataPaletteLinear;
import net.minecraft.server.v1_13_R2.IBlockData;
import net.minecraft.server.v1_13_R2.World;
import static com.boydti.fawe.bukkit.v0.BukkitQueue_0.getAdapter;
public class BukkitGetBlocks extends CharGetBlocks { public class BukkitGetBlocks extends CharGetBlocks {
private ChunkSection[] sections; private ChunkSection[] sections;
private Chunk nmsChunk;
private World nmsWorld;
private int X, Z;
public BukkitGetBlocks(World nmsWorld, int X, int Z) {/*d*/
this.nmsWorld = nmsWorld;
this.X = X;
this.Z = Z;
}
@Override
public BiomeType getBiome(int x, int z) {
// TODO
return null;
}
@Override
public CompoundTag getTag(int x, int y, int z) {
// TODO
return null;
}
@Override
protected char[] load(int layer) {
return load(layer, null);
}
@Override
protected char[] load(int layer, char[] data) {
ChunkSection section = getSections()[layer];
// Section is null, return empty array
if (section == null) {
return FaweCache.EMPTY_CHAR_4096;
}
if (data == null || data == FaweCache.EMPTY_CHAR_4096) {
data = new char[4096];
}
// Efficiently convert ChunkSection to raw data
try {
final DataPaletteBlock<IBlockData> blocks = section.getBlocks();
final DataBits bits = (DataBits) BukkitQueue_1_13.fieldBits.get(blocks);
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitQueue_1_13.fieldPalette.get(blocks);
final int bitsPerEntry = bits.c();
final long[] blockStates = bits.a();
new BitArray4096(blockStates, bitsPerEntry).toRaw(data);
int num_palette;
if (palette instanceof DataPaletteLinear) {
num_palette = ((DataPaletteLinear<IBlockData>) palette).b();
} else if (palette instanceof DataPaletteHash) {
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();
try {
for (int i = 0; i < 4096; i++) {
char paletteVal = data[i];
char ordinal = paletteToBlockChars[paletteVal];
if (ordinal == Character.MAX_VALUE) {
paletteToBlockInts[num_palette++] = paletteVal;
IBlockData ibd = palette.a(data[i]);
if (ibd == null) {
ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar();
} else {
ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToChar(ibd);
}
paletteToBlockChars[paletteVal] = ordinal;
}
data[i] = ordinal;
}
} finally {
for (int i = 0; i < num_palette; i++) {
int paletteVal = paletteToBlockInts[i];
paletteToBlockChars[paletteVal] = Character.MAX_VALUE;
}
}
return data;
}
char[] paletteToBlockChars = FaweCache.PALETTE_TO_BLOCK_CHAR.get();
try {
for (int i = 0; i < num_palette; i++) {
IBlockData ibd = palette.a(i);
char ordinal;
if (ibd == null) {
ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar();
System.out.println("Invalid palette");
} else {
ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToChar(ibd);
}
paletteToBlockChars[i] = ordinal;
}
for (int i = 0; i < 4096; i++) {
char paletteVal = data[i];
data[i] = paletteToBlockChars[paletteVal];
}
} finally {
for (int i = 0; i < num_palette; i++) {
paletteToBlockChars[i] = Character.MAX_VALUE;
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return data;
}
private ChunkSection[] getSections() {
ChunkSection[] tmp = sections;
if (tmp == null) {
Chunk chunk = getChunk();
sections = tmp = chunk.getSections();
}
return tmp;
}
private Chunk getChunk() {
Chunk tmp = nmsChunk;
if (tmp == null) {
ChunkProviderServer provider = (ChunkProviderServer) nmsWorld.getChunkProvider();
nmsChunk = tmp = provider.chunks.get(ChunkCoordIntPair.a(X, Z));
if (tmp == null) {
System.out.println("SYNC");
// TOOD load with paper
nmsChunk = tmp = TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(X, Z));
}
}
return tmp;
}
@Override
public boolean hasSection(int layer) {
return getSections()[layer] != null;
}
@Override
public boolean trim(boolean aggressive) {
if (aggressive) {
sections = null;
nmsChunk = null;
}
return super.trim(aggressive);
}
} }

View File

@ -1,19 +1,50 @@
package com.boydti.fawe.bukkit.beta; package com.boydti.fawe.bukkit.beta;
import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.implementation.SimpleCharQueueExtent;
import com.boydti.fawe.beta.implementation.SingleThreadQueueExtent; import com.boydti.fawe.beta.implementation.SingleThreadQueueExtent;
import com.boydti.fawe.beta.implementation.WorldChunkCache; import com.boydti.fawe.beta.implementation.WorldChunkCache;
import com.boydti.fawe.object.collection.IterableThreadLocal; import com.boydti.fawe.object.collection.IterableThreadLocal;
import com.sk89q.worldedit.bukkit.BukkitWorld;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import net.minecraft.server.v1_13_R2.WorldServer;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_13_R2.CraftWorld;
public class BukkitQueue extends SingleThreadQueueExtent { import static com.google.common.base.Preconditions.checkNotNull;
public class BukkitQueue extends SimpleCharQueueExtent {
private org.bukkit.World bukkitWorld;
private WorldServer nmsWorld;
@Override @Override
public synchronized void init(WorldChunkCache cache) { public synchronized void init(WorldChunkCache cache) {
World world = cache.getWorld(); World world = cache.getWorld();
if (world instanceof BukkitWorld) {
this.bukkitWorld = ((BukkitWorld) world).getWorld();
} else {
this.bukkitWorld = Bukkit.getWorld(world.getName());
}
checkNotNull(this.bukkitWorld);
CraftWorld craftWorld = ((CraftWorld) bukkitWorld);
this.nmsWorld = craftWorld.getHandle();
super.init(cache); super.init(cache);
} }
public WorldServer getNmsWorld() {
return nmsWorld;
}
public org.bukkit.World getBukkitWorld() {
return bukkitWorld;
}
@Override
protected synchronized void reset() {
super.reset();
}
private static final IterableThreadLocal<BukkitFullChunk> FULL_CHUNKS = new IterableThreadLocal<BukkitFullChunk>() { private static final IterableThreadLocal<BukkitFullChunk> FULL_CHUNKS = new IterableThreadLocal<BukkitFullChunk>() {
@Override @Override
public BukkitFullChunk init() { public BukkitFullChunk init() {
@ -24,9 +55,9 @@ public class BukkitQueue extends SingleThreadQueueExtent {
@Override @Override
public IChunk create(boolean full) { public IChunk create(boolean full) {
if (full) { if (full) {
return FULL_CHUNKS.get(); // TODO implement
} else { // return FULL_CHUNKS.get();
}
return new BukkitChunkHolder(); return new BukkitChunkHolder();
} }
} }
}

View File

@ -0,0 +1,11 @@
package com.boydti.fawe.bukkit.beta;
import com.boydti.fawe.beta.IQueueExtent;
import com.boydti.fawe.beta.implementation.QueueHandler;
public class BukkitQueueHandler extends QueueHandler {
@Override
public IQueueExtent create() {
return new BukkitQueue();
}
}

View File

@ -68,8 +68,9 @@ import java.util.function.Supplier;
public class BukkitQueue_1_13 extends BukkitQueue_0<net.minecraft.server.v1_13_R2.Chunk, ChunkSection[], ChunkSection> { public class BukkitQueue_1_13 extends BukkitQueue_0<net.minecraft.server.v1_13_R2.Chunk, ChunkSection[], ChunkSection> {
protected final static Field fieldBits; public final static Field fieldBits;
protected final static Field fieldPalette; public final static Field fieldPalette;
protected final static Field fieldSize; protected final static Field fieldSize;
protected final static Field fieldHashBlocks; protected final static Field fieldHashBlocks;

View File

@ -1,5 +1,6 @@
package com.boydti.fawe; package com.boydti.fawe;
import com.boydti.fawe.beta.implementation.QueueHandler;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Commands; import com.boydti.fawe.config.Commands;
import com.boydti.fawe.config.Settings; import com.boydti.fawe.config.Settings;
@ -82,6 +83,8 @@ public class Fawe {
private DefaultTransformParser transformParser; private DefaultTransformParser transformParser;
private ChatManager chatManager = new PlainChatManager(); private ChatManager chatManager = new PlainChatManager();
private QueueHandler queueHandler;
/** /**
* Get the implementation specific class * Get the implementation specific class
* *
@ -199,6 +202,17 @@ public class Fawe {
public void onDisable() { public void onDisable() {
} }
public QueueHandler getQueueHandler() {
if (queueHandler == null) {
synchronized (this) {
if (queueHandler == null) {
queueHandler = IMP.getQueueHandler();
}
}
}
return queueHandler;
}
public CUI getCUI(Actor actor) { public CUI getCUI(Actor actor) {
FawePlayer<Object> fp = FawePlayer.wrap(actor); FawePlayer<Object> fp = FawePlayer.wrap(actor);
CUI cui = fp.getMeta("CUI"); CUI cui = fp.getMeta("CUI");

View File

@ -13,6 +13,7 @@ import java.lang.reflect.Field;
import java.util.*; import java.util.*;
public class FaweCache implements Trimable { public class FaweCache implements Trimable {
public static final char[] EMPTY_CHAR_4096 = new char[4096];
/* /*
Palette buffers / cache Palette buffers / cache
@ -40,7 +41,16 @@ public class FaweCache implements Trimable {
public static final IterableThreadLocal<int[]> PALETTE_TO_BLOCK = new IterableThreadLocal<int[]>() { public static final IterableThreadLocal<int[]> PALETTE_TO_BLOCK = new IterableThreadLocal<int[]>() {
@Override @Override
public int[] init() { public int[] init() {
return new int[Character.MAX_VALUE]; return new int[Character.MAX_VALUE + 1];
}
};
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;
} }
}; };
@ -58,17 +68,10 @@ public class FaweCache implements Trimable {
} }
}; };
public static Map<String, Object> asMap(Object... pairs) { /**
HashMap<String, Object> map = new HashMap<>(pairs.length >> 1); * Holds data for a palette used in a chunk section
for (int i = 0; i < pairs.length; i += 2) { */
String key = (String) pairs[i]; public static final class Palette {
Object value = pairs[i + 1];
map.put(key, value);
}
return map;
}
private static final class Palette {
public int paletteToBlockLength; public int paletteToBlockLength;
/** /**
* Reusable buffer array, MUST check paletteToBlockLength for actual length * Reusable buffer array, MUST check paletteToBlockLength for actual length
@ -91,31 +94,31 @@ public class FaweCache implements Trimable {
/** /**
* Convert raw char array to palette * Convert raw char array to palette
* @param layer * @param layerOffset
* @param blocks * @param blocks
* @return palette * @return palette
*/ */
public static Palette toPalette(int layer, char[] blocks) { public static Palette toPalette(int layerOffset, char[] blocks) {
return toPalette(layer, null, blocks); return toPalette(layerOffset, null, blocks);
} }
/** /**
* Convert raw int array to palette * Convert raw int array to palette
* @param layer * @param layerOffset
* @param blocks * @param blocks
* @return palette * @return palette
*/ */
public static Palette toPalette(int layer, int[] blocks) { public static Palette toPalette(int layerOffset, int[] blocks) {
return toPalette(layer, blocks, null); return toPalette(layerOffset, blocks, null);
} }
private static Palette toPalette(int layer, int[] blocksInts, char[] blocksChars) { private static Palette toPalette(int layerOffset, int[] blocksInts, char[] blocksChars) {
int[] blockToPalette = BLOCK_TO_PALETTE.get(); int[] blockToPalette = BLOCK_TO_PALETTE.get();
int[] paletteToBlock = PALETTE_TO_BLOCK.get(); int[] paletteToBlock = PALETTE_TO_BLOCK.get();
long[] blockstates = BLOCK_STATES.get(); long[] blockstates = BLOCK_STATES.get();
int[] blocksCopy = SECTION_BLOCKS.get(); int[] blocksCopy = SECTION_BLOCKS.get();
int blockIndexStart = layer << 12; int blockIndexStart = layerOffset << 12;
int blockIndexEnd = blockIndexStart + 4096; int blockIndexEnd = blockIndexStart + 4096;
int num_palette = 0; int num_palette = 0;
try { try {
@ -124,7 +127,7 @@ public class FaweCache implements Trimable {
int ordinal = blocksChars[i]; int ordinal = blocksChars[i];
int palette = blockToPalette[ordinal]; int palette = blockToPalette[ordinal];
if (palette == Integer.MAX_VALUE) { if (palette == Integer.MAX_VALUE) {
BlockState state = BlockTypes.states[ordinal]; // BlockState state = BlockTypes.states[ordinal];
blockToPalette[ordinal] = palette = num_palette; blockToPalette[ordinal] = palette = num_palette;
paletteToBlock[num_palette] = ordinal; paletteToBlock[num_palette] = ordinal;
num_palette++; num_palette++;
@ -183,6 +186,16 @@ public class FaweCache implements Trimable {
Conversion methods between JNBT tags and raw values Conversion methods between JNBT tags and raw values
*/ */
public static 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];
Object value = pairs[i + 1];
map.put(key, value);
}
return map;
}
public static ShortTag asTag(short value) { public static ShortTag asTag(short value) {
return new ShortTag(value); return new ShortTag(value);
} }

View File

@ -1,5 +1,6 @@
package com.boydti.fawe; package com.boydti.fawe;
import com.boydti.fawe.beta.implementation.QueueHandler;
import com.boydti.fawe.object.FaweCommand; import com.boydti.fawe.object.FaweCommand;
import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.FaweQueue;
@ -62,4 +63,6 @@ public interface IFawe {
return ""; return "";
} }
QueueHandler getQueueHandler();
} }

View File

@ -0,0 +1,249 @@
package com.boydti.fawe.beta;
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.registry.BlockMaterial;
import static com.sk89q.worldedit.world.block.BlockTypes.states;
public class CharFilterBlock implements FilterBlock {
private IQueueExtent queue;
private CharGetBlocks chunk;
private char[] section;
@Override
public void init(IQueueExtent queue) {
this.queue = queue;
}
@Override
public void init(int X, int Z, IGetBlocks chunk) {
this.chunk = (CharGetBlocks) chunk;
this.X = X;
this.Z = Z;
this.xx = X << 4;
this.zz = Z << 4;
}
public void init(char[] section, int layer) {
this.section = section;
this.layer = layer;
this.yy = layer << 4;
}
// local
public int layer, index, x, y, z, xx, yy, zz, X, Z;
@Override
public int getX() {
return xx + x;
}
@Override
public int getY() {
return yy + y;
}
@Override
public int getZ() {
return zz + z;
}
@Override
public int getLocalX() {
return x;
}
@Override
public int getLocalY() {
return y;
}
@Override
public int getLocalZ() {
return z;
}
@Override
public int getChunkX() {
return X;
}
@Override
public int getChunkZ() {
return Z;
}
@Override
public int getOrdinal() {
return section[index];
}
@Override
public BlockState getState() {
int ordinal = section[index];
return BlockTypes.states[ordinal];
}
@Override
public BaseBlock getBaseBlock() {
BlockState state = getState();
BlockMaterial material = state.getMaterial();
if (material.hasContainer()) {
CompoundTag tag = chunk.getTag(x, y + (layer << 4), z);
return state.toBaseBlock(tag);
}
return state.toBaseBlock();
}
@Override
public CompoundTag getTag() {
return null;
}
public BlockState getOrdinalBelow() {
if (y > 0) {
return states[section[index - 256]];
}
if (layer > 0) {
final int newLayer = layer - 1;
final CharGetBlocks chunk = this.chunk;
return states[chunk.sections[newLayer].get(chunk, newLayer, index + 3840)];
}
return BlockTypes.__RESERVED__.getDefaultState();
}
public BlockState getStateAbove() {
if (y < 16) {
return states[section[index + 256]];
}
if (layer < 16) {
final int newLayer = layer + 1;
final CharGetBlocks chunk = this.chunk;
return states[chunk.sections[newLayer].get(chunk, newLayer, index - 3840)];
}
return BlockTypes.__RESERVED__.getDefaultState();
}
public BlockState getStateRelativeY(int y) {
int newY = this.y + y;
int layerAdd = newY >> 4;
switch (layerAdd) {
case 0:
return states[section[this.index + (y << 8)]];
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15: {
int newLayer = layer + layerAdd;
if (newLayer < 16) {
int index = this.index + ((y & 15) << 8);
return states[chunk.sections[newLayer].get(chunk, newLayer, index)];
}
break;
}
case -1:
case -2:
case -3:
case -4:
case -5:
case -6:
case -7:
case -8:
case -9:
case -10:
case -11:
case -12:
case -13:
case -14:
case -15: {
int newLayer = layer + layerAdd;
if (newLayer >= 0) {
int index = this.index + ((y & 15) << 8);
return states[chunk.sections[newLayer].get(chunk, newLayer, index)];
}
break;
}
}
return BlockTypes.__RESERVED__.getDefaultState();
}
public BlockState getStateRelative(final int x, final int y, final int z) {
int newX = this.x + x;
if (newX >> 4 == 0) {
int newZ = this.z + z;
if (newZ >> 4 == 0) {
int newY = this.y + y;
int layerAdd = newY >> 4;
switch (layerAdd) {
case 0:
return states[section[this.index + ((y << 8) | (z << 4) | x)]];
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15: {
int newLayer = layer + layerAdd;
if (newLayer < 16) {
int index = this.index + (((y & 15) << 8) | (z << 4) | x);
return states[chunk.sections[newLayer].get(chunk, newLayer, index)];
}
break;
}
case -1:
case -2:
case -3:
case -4:
case -5:
case -6:
case -7:
case -8:
case -9:
case -10:
case -11:
case -12:
case -13:
case -14:
case -15: {
int newLayer = layer + layerAdd;
if (newLayer >= 0) {
int index = this.index + (((y & 15) << 8) | (z << 4) | x);
return states[chunk.sections[newLayer].get(chunk, newLayer, index)];
}
break;
}
}
return BlockTypes.__RESERVED__.getDefaultState();
}
}
// queue.get
// TODO return normal get block
int newY = this.y + y + yy;
if (newY >= 0 && newY <= 256) {
return queue.getBlock(xx + newX, newY, this.zz + this.z + z);
}
return BlockTypes.__RESERVED__.getDefaultState();
}
}

View File

@ -0,0 +1,60 @@
package com.boydti.fawe.beta;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class ChunkFuture implements Future<Void> {
private final IChunk chunk;
private volatile boolean cancelled;
private volatile boolean done;
public ChunkFuture(IChunk chunk) {
this.chunk = chunk;
}
public IChunk getChunk() {
return chunk;
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
cancelled = true;
if (done) return false;
return true;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public boolean isDone() {
return done;
}
@Override
public Void get() throws InterruptedException, ExecutionException {
synchronized (chunk) {
if (!done) {
this.wait();
}
}
return null;
}
@Override
public Void get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
synchronized (chunk) {
if (!done) {
this.wait(unit.toMillis(timeout));
if (!done) {
throw new TimeoutException();
}
}
}
return null;
}
}

View File

@ -34,12 +34,9 @@ public interface Filter {
* - e.g. block.setId(...)<br> * - e.g. block.setId(...)<br>
* - Note: Performance is critical here<br> * - Note: Performance is critical here<br>
* *
* @param x
* @param y
* @param z
* @param block * @param block
*/ */
default void applyBlock(final int x, final int y, final int z, final BaseBlock block) { default void applyBlock(final FilterBlock block) {
} }
/** /**
@ -59,4 +56,8 @@ public interface Filter {
default Filter fork() { default Filter fork() {
return this; return this;
} }
default void join(Filter parent) {
}
} }

View File

@ -0,0 +1,60 @@
package com.boydti.fawe.beta;
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
public interface FilterBlock {
void init(IQueueExtent queue);
void init(int X, int Z, IGetBlocks chunk);
int getOrdinal();
BlockState getState();
BaseBlock getBaseBlock();
CompoundTag getTag();
default BlockState getOrdinalBelow() {
return getStateRelative(0, -1, 0);
}
default BlockState getStateAbove() {
return getStateRelative(0, 1, 0);
}
default BlockState getStateRelativeY(int y) {
return getStateRelative(0, y, 0);
}
int getX();
int getY();
int getZ();
default int getLocalX() {
return getX() & 15;
}
default int getLocalY() {
return getY() & 15;
}
default int getLocalZ() {
return getZ() & 15;
}
default int getChunkX() {
return getX() >> 4;
}
default int getChunkZ() {
return getZ() >> 4;
}
BlockState getStateRelative(final int x, final int y, final int z);
}

View File

@ -3,6 +3,8 @@ package com.boydti.fawe.beta;
/** /**
* Shared interface for IGetBlocks and ISetBlocks * Shared interface for IGetBlocks and ISetBlocks
*/ */
public interface IBlocks { public interface IBlocks extends Trimable {
boolean hasSection(int layer);
void reset();
} }

View File

@ -8,17 +8,15 @@ import com.sk89q.worldedit.world.block.BlockStateHolder;
/** /**
* Represents a chunk in the queue {@link IQueueExtent} * Represents a chunk in the queue {@link IQueueExtent}
* Used for getting and setting blocks / biomes / entities * Used for getting and setting blocks / biomes / entities
* @param <T> The result type (typically returns true when the chunk is applied)
* @param <V> The IQueue class
*/ */
public interface IChunk<T, V extends IQueueExtent> extends Trimable { public interface IChunk extends Trimable {
/** /**
* Initialize at the location * Initialize at the location
* @param extent * @param extent
* @param X * @param X
* @param Z * @param Z
*/ */
void init(V extent, int X, int Z); void init(IQueueExtent extent, int X, int Z);
int getX(); int getX();
@ -38,10 +36,16 @@ public interface IChunk<T, V extends IQueueExtent> extends Trimable {
boolean isEmpty(); boolean isEmpty();
/** /**
* Apply the queued changes to the world * Apply the queued async changes to the world
* @return * @return false if applySync needs to run
*/ */
T apply(); boolean applyAsync();
/**
* Apply the queued sync changes to the world
* @return true
*/
boolean applySync();
/* set - queues a change */ /* set - queues a change */
boolean setBiome(int x, int y, int z, BiomeType biome); boolean setBiome(int x, int y, int z, BiomeType biome);
@ -60,4 +64,6 @@ public interface IChunk<T, V extends IQueueExtent> extends Trimable {
BlockState getBlock(int x, int y, int z); BlockState getBlock(int x, int y, int z);
BaseBlock getFullBlock(int x, int y, int z); BaseBlock getFullBlock(int x, int y, int z);
void filter(Filter filter, FilterBlock mutable);
} }

View File

@ -7,11 +7,9 @@ import com.sk89q.worldedit.world.block.BlockStateHolder;
/** /**
* Delegate for IChunk * Delegate for IChunk
* @param <T> The result type (typically returns true when the chunk is applied)
* @param <V> The IQueue class
* @param <U> parent class * @param <U> parent class
*/ */
public interface IDelegateChunk<T, V extends IQueueExtent, U extends IChunk<T, V>> extends IChunk<T, V> { public interface IDelegateChunk<U extends IChunk> extends IChunk {
U getParent(); U getParent();
default IChunk getRoot() { default IChunk getRoot() {
@ -48,7 +46,7 @@ public interface IDelegateChunk<T, V extends IQueueExtent, U extends IChunk<T, V
} }
@Override @Override
default void init(final V extent, final int X, final int Z) { default void init(final IQueueExtent extent, final int X, final int Z) {
getParent().init(extent, X, Z); getParent().init(extent, X, Z);
} }
@ -68,13 +66,19 @@ public interface IDelegateChunk<T, V extends IQueueExtent, U extends IChunk<T, V
return getParent().trim(aggressive); return getParent().trim(aggressive);
} }
/**
* Apply this chunk to the world
* @return result T (typically a boolean)
*/
@Override @Override
default T apply() { default boolean applySync() {
return getParent().apply(); return getParent().applySync();
}
@Override
default boolean applyAsync() {
return getParent().applyAsync();
}
@Override
default void filter(Filter filter, FilterBlock mutable) {
getParent().filter(filter, mutable);
} }
@Override @Override

View File

@ -21,7 +21,7 @@ public interface IDelegateQueueExtent extends IQueueExtent {
} }
@Override @Override
default <T> Future<T> submit(IChunk<T, ?> chunk) { default Future<?> submit(IChunk chunk) {
return getParent().submit(chunk); return getParent().submit(chunk);
} }

View File

@ -1,5 +1,6 @@
package com.boydti.fawe.beta; package com.boydti.fawe.beta;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
@ -14,6 +15,10 @@ public interface IGetBlocks extends IBlocks, Trimable {
BlockState getBlock(int x, int y, int z); BlockState getBlock(int x, int y, int z);
CompoundTag getTag(int x, int y, int z);
@Override @Override
boolean trim(boolean aggressive); boolean trim(boolean aggressive);
void filter(Filter filter, FilterBlock block);
} }

View File

@ -15,6 +15,12 @@ import java.util.concurrent.Future;
public interface IQueueExtent extends Flushable, Trimable { public interface IQueueExtent extends Flushable, Trimable {
void init(WorldChunkCache world); void init(WorldChunkCache world);
/**
* Get the {@link WorldChunkCache}
* @return
*/
WorldChunkCache getCache();
/** /**
* Get the IChunk at a position (and cache it if it's not already) * Get the IChunk at a position (and cache it if it's not already)
* @param X * @param X
@ -26,10 +32,9 @@ public interface IQueueExtent extends Flushable, Trimable {
/** /**
* Submit the chunk so that it's changes are applied to the world * Submit the chunk so that it's changes are applied to the world
* @param chunk * @param chunk
* @param <T> result type
* @return result * @return result
*/ */
<T> Future<T> submit(IChunk<T, ?> chunk); Future<?> submit(IChunk chunk);
default boolean setBlock(final int x, final int y, final int z, final BlockStateHolder state) { default boolean setBlock(final int x, final int y, final int z, final BlockStateHolder state) {
final IChunk chunk = getCachedChunk(x >> 4, z >> 4); final IChunk chunk = getCachedChunk(x >> 4, z >> 4);
@ -75,4 +80,6 @@ public interface IQueueExtent extends Flushable, Trimable {
*/ */
@Override @Override
void flush(); void flush();
FilterBlock initFilterBlock();
} }

View File

@ -1,10 +1,17 @@
package com.boydti.fawe.beta.implementation; package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.beta.Filter; import com.boydti.fawe.beta.Filter;
import com.boydti.fawe.beta.FilterBlock;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IQueueExtent; import com.boydti.fawe.beta.IQueueExtent;
import com.boydti.fawe.beta.Trimable; import com.boydti.fawe.beta.Trimable;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.collection.IterableThreadLocal; import com.boydti.fawe.object.collection.IterableThreadLocal;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.wrappers.WorldWrapper; import com.boydti.fawe.wrappers.WorldWrapper;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
@ -12,6 +19,10 @@ import java.lang.ref.WeakReference;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.Future;
/** /**
* Class which handles all the queues {@link IQueueExtent} * Class which handles all the queues {@link IQueueExtent}
@ -26,6 +37,17 @@ public abstract class QueueHandler implements Trimable {
} }
}; };
public Future<?> submit(IChunk chunk) {
if (Fawe.isMainThread()) {
if (!chunk.applyAsync()) {
chunk.applySync();
}
return null;
}
// TODO return future
return null;
}
/** /**
* Get or create the WorldChunkCache for a world * Get or create the WorldChunkCache for a world
* @param world * @param world
@ -50,6 +72,12 @@ public abstract class QueueHandler implements Trimable {
public abstract IQueueExtent create(); public abstract IQueueExtent create();
public IQueueExtent getQueue(World world) {
IQueueExtent queue = pool.get();
queue.init(getOrCreate(world));
return queue;
}
@Override @Override
public boolean trim(final boolean aggressive) { public boolean trim(final boolean aggressive) {
boolean result = true; boolean result = true;
@ -69,67 +97,68 @@ public abstract class QueueHandler implements Trimable {
return result; return result;
} }
public static void apply(final Region region, final Filter filter) { // TODO not MCAFilter, but another similar class public void apply(final World world, final Region region, final Filter filter) {
// // The chunks positions to iterate over // The chunks positions to iterate over
// final Set<BlockVector2> chunks = region.getChunks(); final Set<BlockVector2> chunks = region.getChunks();
// final Iterator<BlockVector2> chunksIter = chunks.iterator(); final Iterator<BlockVector2> chunksIter = chunks.iterator();
//
// // Get a pool, to operate on the chunks in parallel // Get a pool, to operate on the chunks in parallel
// final ForkJoinPool pool = TaskManager.IMP.getPublicForkJoinPool(); final ForkJoinPool pool = TaskManager.IMP.getPublicForkJoinPool();
// final int size = Math.min(chunks.size(), Settings.IMP.QUEUE.PARALLEL_THREADS); final int size = Math.min(chunks.size(), Settings.IMP.QUEUE.PARALLEL_THREADS);
// final ForkJoinTask[] tasks = new ForkJoinTask[size]; final ForkJoinTask[] tasks = new ForkJoinTask[size];
//
// for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
// tasks[i] = pool.submit(new Runnable() { tasks[i] = pool.submit(new Runnable() {
// @Override @Override
// public void run() { public void run() {
// // Create a chunk that we will reuse/reset for each operation Filter newFilter = filter.fork();
// IChunk chunk = create(true); // Create a chunk that we will reuse/reset for each operation
// IQueueExtent queue = getQueue(world);
// while (true) { FilterBlock block = null;
// // Get the next chunk pos
// final BlockVector2 pos; while (true) {
// synchronized (chunksIter) { // Get the next chunk pos
// if (!chunksIter.hasNext()) return; final BlockVector2 pos;
// pos = chunksIter.next(); synchronized (chunksIter) {
// } if (!chunksIter.hasNext()) return;
// final int X = pos.getX(); pos = chunksIter.next();
// final int Z = pos.getZ(); }
// final long pair = MathMan.pairInt(X, Z); final int X = pos.getX();
// final int Z = pos.getZ();
// // Initialize // TODO create full
// chunk.init(SingleThreadQueueExtent.this, X, Z); IChunk chunk = queue.getCachedChunk(X, Z);
// // Initialize
// { // Start set chunk.init(queue, X, Z);
// lastPair = pair; try {
// lastChunk = chunk; if (!newFilter.appliesChunk(X, Z)) {
// } continue;
// try { }
// if (!filter.appliesChunk(X, Z)) { chunk = newFilter.applyChunk(chunk);
// continue;
// } if (chunk == null) continue;
// chunk = filter.applyChunk(chunk);
// if (block == null) block = queue.initFilterBlock();
// if (chunk == null) continue; chunk.filter(newFilter, block);
//
// chunk.filter(filter); newFilter.finishChunk(chunk);
//
// filter.finishChunk(chunk); queue.submit(chunk);
// } finally
// chunk.apply(); {
// } finally if (filter != newFilter) {
// { // End set synchronized (filter) {
// lastPair = Long.MAX_VALUE; newFilter.join(filter);
// lastChunk = null; }
// } }
// } }
// } }
// }); }
// } });
// }
// // Join the tasks
// for (final ForkJoinTask task : tasks) { // Join the tasks
// task.join(); for (final ForkJoinTask task : tasks) {
// } task.join();
}
} }
} }

View File

@ -0,0 +1,13 @@
package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.beta.CharFilterBlock;
import com.boydti.fawe.beta.FilterBlock;
public abstract class SimpleCharQueueExtent extends SingleThreadQueueExtent {
@Override
public FilterBlock initFilterBlock() {
CharFilterBlock filter = new CharFilterBlock();
filter.init(this);
return filter;
}
}

View File

@ -1,5 +1,6 @@
package com.boydti.fawe.beta.implementation; package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IQueueExtent; import com.boydti.fawe.beta.IQueueExtent;
import com.boydti.fawe.beta.implementation.holder.ReferenceChunk; import com.boydti.fawe.beta.implementation.holder.ReferenceChunk;
@ -12,8 +13,10 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask; import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.Future;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
@ -37,10 +40,7 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
} }
} }
/** @Override
* Get the {@link WorldChunkCache}
* @return
*/
public WorldChunkCache getCache() { public WorldChunkCache getCache() {
return cache; return cache;
} }
@ -52,12 +52,7 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
checkThread(); checkThread();
cache = null; cache = null;
if (!chunks.isEmpty()) { if (!chunks.isEmpty()) {
for (IChunk chunk : chunks.values()) { CHUNK_POOL.addAll(chunks.values());
chunk = chunk.getRoot();
if (chunk != null) {
CHUNK_POOL.add(chunk);
}
}
chunks.clear(); chunks.clear();
} }
lastChunk = null; lastChunk = null;
@ -88,27 +83,19 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
private static final ConcurrentLinkedQueue<IChunk> CHUNK_POOL = new ConcurrentLinkedQueue<>(); private static final ConcurrentLinkedQueue<IChunk> CHUNK_POOL = new ConcurrentLinkedQueue<>();
@Override @Override
public <T> ForkJoinTask<T> submit(final IChunk<T, ?> chunk) { public Future<?> submit(final IChunk chunk) {
if (chunk.isEmpty()) { if (chunk.isEmpty()) {
CHUNK_POOL.add(chunk); CHUNK_POOL.add(chunk);
return null; return null;
} }
// TODO use SetQueue to run in parallel if (Fawe.isMainThread()) {
final ForkJoinPool pool = TaskManager.IMP.getPublicForkJoinPool(); if (!chunk.applyAsync()) {
return pool.submit(new Callable<T>() { chunk.applySync();
@Override
public T call() {
IChunk<T, ?> tmp = chunk;
T result = tmp.apply();
tmp = tmp.getRoot();
if (tmp != null) {
CHUNK_POOL.add(tmp);
} }
return result; return null;
} }
}); QueueHandler handler = Fawe.get().getQueueHandler();
return handler.submit(chunk);
} }
@Override @Override
@ -141,7 +128,7 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
@Override @Override
public final IChunk getCachedChunk(final int X, final int Z) { public final IChunk getCachedChunk(final int X, final int Z) {
final long pair = MathMan.pairInt(X, Z); final long pair = (((long) X) << 32) | (Z & 0xffffffffL);
if (pair == lastPair) { if (pair == lastPair) {
return lastChunk; return lastChunk;
} }
@ -178,14 +165,21 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
public synchronized void flush() { public synchronized void flush() {
checkThread(); checkThread();
if (!chunks.isEmpty()) { if (!chunks.isEmpty()) {
final ForkJoinTask[] tasks = new ForkJoinTask[chunks.size()]; final Future[] tasks = new ForkJoinTask[chunks.size()];
int i = 0; int i = 0;
for (final IChunk chunk : chunks.values()) { for (final IChunk chunk : chunks.values()) {
tasks[i++] = submit(chunk); tasks[i++] = submit(chunk);
} }
chunks.clear(); chunks.clear();
for (final ForkJoinTask task : tasks) { for (final Future task : tasks) {
if (task != null) task.join(); if (task != null) {
try {
task.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
} }
} }
reset(); reset();

View File

@ -3,5 +3,93 @@ package com.boydti.fawe.beta.implementation.blocks;
import com.boydti.fawe.beta.IBlocks; import com.boydti.fawe.beta.IBlocks;
public class CharBlocks implements IBlocks { public class CharBlocks implements IBlocks {
protected char[][] blocks; public final char[][] blocks;
public final Section[] sections;
public CharBlocks() {
blocks = new char[16][];
sections = new Section[16];
for (int i = 0; i < 16; i++) sections[i] = NULL;
}
@Override
public boolean trim(boolean aggressive) {
boolean result = true;
for (int i = 0; i < 16; i++) {
if (sections[i] == NULL) {
blocks[i] = null;
} else {
result = false;
}
}
return result;
}
@Override
public void reset() {
for (int i = 0; i < 16; i++) sections[i] = NULL;
}
protected char[] load(int layer) {
return new char[4096];
}
protected char[] load(int layer, char[] data) {
for (int i = 0; i < 4096; i++) data[i] = 0;
return data;
}
@Override
public boolean hasSection(int layer) {
return sections[layer] == FULL;
}
public char get(int x, int y, int z) {
int layer = y >> 4;
int index = ((y & 15) << 8) | (z << 4) | (x & 15);
return sections[layer].get(this, layer, index);
}
public char set(int x, int y, int z, char value) {
int layer = y >> 4;
int index = ((y & 15) << 8) | (z << 4) | (x & 15);
return sections[layer].set(this, layer, index, value);
}
/*
Section
*/
public static abstract class Section {
public abstract char[] get(CharBlocks blocks, int layer);
public final char get(CharBlocks blocks, int layer, int index) {
return get(blocks, layer)[index];
}
public final char set(CharBlocks blocks, int layer, int index, char value) {
return get(blocks, layer)[index] = value;
}
}
public static final Section NULL = new Section() {
@Override
public final char[] get(CharBlocks blocks, int layer) {
blocks.sections[layer] = FULL;
char[] arr = blocks.blocks[layer];
if (arr == null) {
arr = blocks.blocks[layer] = blocks.load(layer);
} else {
blocks.blocks[layer] = blocks.load(layer, arr);
}
return arr;
}
};
public static final Section FULL = new Section() {
@Override
public final char[] get(CharBlocks blocks, int layer) {
return blocks.blocks[layer];
}
};
} }

View File

@ -1,23 +1,52 @@
package com.boydti.fawe.beta.implementation.blocks; package com.boydti.fawe.beta.implementation.blocks;
import com.boydti.fawe.beta.CharFilterBlock;
import com.boydti.fawe.beta.Filter;
import com.boydti.fawe.beta.FilterBlock;
import com.boydti.fawe.beta.IGetBlocks; import com.boydti.fawe.beta.IGetBlocks;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
public class CharGetBlocks extends CharBlocks implements IGetBlocks { public abstract class CharGetBlocks extends CharBlocks implements IGetBlocks {
@Override @Override
public BaseBlock getFullBlock(final int x, final int y, final int z) { public BaseBlock getFullBlock(final int x, final int y, final int z) {
return null; return BlockTypes.states[get(x, y, z)].toBaseBlock();
}
@Override
public BiomeType getBiome(final int x, final int z) {
} }
@Override @Override
public BlockState getBlock(final int x, final int y, final int z) { public BlockState getBlock(final int x, final int y, final int z) {
return null; return BlockTypes.states[get(x, y, z)];
}
@Override
public void filter(Filter filter, FilterBlock block) {
CharFilterBlock b = (CharFilterBlock) block;
for (int layer = 0; layer < 16; layer++) {
if (!hasSection(layer)) continue;
char[] arr = sections[layer].get(this, layer);
b.init(arr, layer);
for (b.y = 0, b.index = 0; b.y < 16; b.y++) {
for (b.z = 0; b.z < 16; b.z++) {
for (b.x = 0; b.x < 16; b.x++, b.index++) {
filter.applyBlock(b);
}
}
}
}
}
@Override
public boolean trim(boolean aggressive) {
for (int i = 0; i < 16; i++) {
sections[i] = NULL;
blocks[i] = null;
}
return true;
}
@Override
public void reset() {
super.reset();
} }
} }

View File

@ -2,14 +2,48 @@ package com.boydti.fawe.beta.implementation.blocks;
import com.boydti.fawe.beta.ISetBlocks; import com.boydti.fawe.beta.ISetBlocks;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.UUID; import java.util.UUID;
public class CharSetBlocks extends CharBlocks implements ISetBlocks { public class CharSetBlocks extends CharBlocks implements ISetBlocks {
private byte[] biomes; private BiomeType[] biomes;
private HashMap<Short, CompoundTag> tiles; private HashMap<Short, CompoundTag> tiles;
private HashSet<CompoundTag> entities; private HashSet<CompoundTag> entities;
private HashSet<UUID> entityRemoves; private HashSet<UUID> entityRemoves;
@Override
public boolean setBiome(int x, int y, int z, BiomeType biome) {
if (biomes == null) {
biomes = new BiomeType[256];
}
biomes[x + (z << 4)] = biome;
return true;
}
@Override
public boolean setBlock(int x, int y, int z, BlockStateHolder holder) {
set(x, y, z, holder.getOrdinalChar());
return true;
}
@Override
public boolean isEmpty() {
if (biomes != null) return false;
for (int i = 0; i < 16; i++) {
if (hasSection(i)) {
return false;
}
}
return true;
}
@Override
public void reset() {
biomes = null;
super.reset();
}
} }

View File

@ -2,7 +2,23 @@ package com.boydti.fawe.beta.implementation.blocks;
import com.boydti.fawe.beta.IBlocks; import com.boydti.fawe.beta.IBlocks;
// TODO implement
public class FullCharBlocks implements IBlocks { public class FullCharBlocks implements IBlocks {
public final boolean[] hasSections = new boolean[16]; public final boolean[] hasSections = new boolean[16];
public final char[] blocks = new char[65536]; public final char[] blocks = new char[65536];
@Override
public boolean hasSection(int layer) {
return false;
}
@Override
public void reset() {
}
@Override
public boolean trim(boolean aggressive) {
return false;
}
} }

View File

@ -1,5 +1,9 @@
package com.boydti.fawe.beta.implementation.holder; package com.boydti.fawe.beta.implementation.holder;
import com.boydti.fawe.beta.CharFilterBlock;
import com.boydti.fawe.beta.Filter;
import com.boydti.fawe.beta.FilterBlock;
import com.boydti.fawe.beta.IQueueExtent;
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks; import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks;
import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.IChunk;
@ -18,11 +22,11 @@ import java.util.function.Supplier;
/** /**
* Abstract IChunk class that implements basic get/set blocks * Abstract IChunk class that implements basic get/set blocks
*/ */
public abstract class ChunkHolder<T, V extends SingleThreadQueueExtent> implements IChunk<T, V>, Supplier<IGetBlocks> { public abstract class ChunkHolder<T> implements IChunk, Supplier<IGetBlocks> {
private IGetBlocks get; private IGetBlocks get;
private ISetBlocks set; private ISetBlocks set;
private IBlockDelegate delegate; private IBlockDelegate delegate;
private SingleThreadQueueExtent extent; private IQueueExtent extent;
private int X,Z; private int X,Z;
public ChunkHolder() { public ChunkHolder() {
@ -33,6 +37,37 @@ public abstract class ChunkHolder<T, V extends SingleThreadQueueExtent> implemen
this.delegate = delegate; this.delegate = delegate;
} }
@Override
public void filter(Filter filter, FilterBlock block) {
block.init(X, Z, get);
IGetBlocks get = cachedGet();
get.filter(filter, block);
}
@Override
public boolean trim(boolean aggressive) {
if (set != null) {
boolean result = set.trim(aggressive);
if (result) {
delegate = NULL;
get = null;
set = null;
return true;
}
}
if (aggressive) {
get = null;
if (delegate == BOTH) {
delegate = SET;
} else if (delegate == GET) {
delegate = NULL;
}
} else {
get.trim(false);
}
return false;
}
@Override @Override
public boolean isEmpty() { public boolean isEmpty() {
return set == null || set.isEmpty(); return set == null || set.isEmpty();
@ -53,25 +88,29 @@ public abstract class ChunkHolder<T, V extends SingleThreadQueueExtent> implemen
} }
private IGetBlocks newGet() { private IGetBlocks newGet() {
WorldChunkCache cache = extent.getCache(); if (extent instanceof SingleThreadQueueExtent) {
cache.get(MathMan.pairInt(X, Z), this); WorldChunkCache cache = ((SingleThreadQueueExtent) extent).getCache();
return new CharGetBlocks(); return cache.get(MathMan.pairInt(X, Z), this);
}
return get();
} }
public void init(final SingleThreadQueueExtent extent, final int X, final int Z) { @Override
public void init(IQueueExtent extent, final int X, final int Z) {
this.extent = extent; this.extent = extent;
this.X = X; this.X = X;
this.Z = Z; this.Z = Z;
set = null; if (set != null) {
if (delegate == BOTH) { set.reset();
delegate = GET; delegate = SET;
} else if (delegate == SET) { } else {
delegate = NULL; delegate = NULL;
} }
get = null;
} }
public V getExtent() { public IQueueExtent getExtent() {
return (V) extent; return extent;
} }
@Override @Override

View File

@ -22,7 +22,8 @@ public class FinalizedChunk extends DelegateChunk {
@Override @Override
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
if (getParent() != null) { if (getParent() != null) {
apply(); // TODO apply safely
// apply();
setParent(null); setParent(null);
} }
super.finalize(); super.finalize();

View File

@ -0,0 +1,58 @@
package com.boydti.fawe.beta.test;
import com.boydti.fawe.beta.Filter;
import com.boydti.fawe.beta.FilterBlock;
import com.boydti.fawe.config.BBC;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CountFilter implements Filter {
private int[] counter = new int[BlockTypes.states.length];
@Override
public void applyBlock(FilterBlock block) {
counter[block.getOrdinal()]++;
}
public List<Countable<BlockState>> getDistribution() {
List<Countable<BlockState>> distribution = new ArrayList<>();
for (int i = 0; i < counter.length; i++) {
int count = counter[i];
if (count != 0) {
distribution.add(new Countable<>(BlockTypes.states[i], count));
}
}
Collections.sort(distribution);
return distribution;
}
public void print(Actor actor, long size) {
for (Countable c : getDistribution()) {
String name = c.getID().toString();
String str = String.format("%-7s (%.3f%%) %s",
String.valueOf(c.getAmount()),
c.getAmount() / (double) size * 100,
name);
actor.print(BBC.getPrefix() + str);
}
}
@Override
public Filter fork() {
return new CountFilter();
}
@Override
public void join(Filter parent) {
CountFilter other = (CountFilter) parent;
for (int i = 0; i < counter.length; i++) {
other.counter[i] += this.counter[i];
}
}
}

View File

@ -159,4 +159,38 @@ public final class BitArray4096 {
} }
return buffer; return buffer;
} }
public final char[] toRaw(char[] buffer) {
final long[] data = this.data;
final int dataLength = longLen;
final int bitsPerEntry = this.bitsPerEntry;
final int maxEntryValue = this.maxEntryValue;
final int maxSeqLocIndex = this.maxSeqLocIndex;
int localStart = 0;
char lastVal;
int arrI = 0;
long l;
for (int i = 0; i < dataLength; i++) {
l = data[i];
for (; localStart <= maxSeqLocIndex; localStart += bitsPerEntry) {
lastVal = (char) (l >>> localStart & maxEntryValue);
buffer[arrI++] = lastVal;
}
if (localStart < 64) {
if (i != dataLength - 1) {
lastVal = (char) (l >>> localStart);
localStart -= maxSeqLocIndex;
l = data[i + 1];
int localShift = bitsPerEntry - localStart;
lastVal |= l << localShift;
lastVal &= maxEntryValue;
buffer[arrI++] = lastVal;
}
} else {
localStart = 0;
}
}
return buffer;
}
} }

View File

@ -19,7 +19,12 @@
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweAPI; import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.beta.IQueueExtent;
import com.boydti.fawe.beta.implementation.QueueHandler;
import com.boydti.fawe.beta.implementation.WorldChunkCache;
import com.boydti.fawe.beta.test.CountFilter;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
import com.boydti.fawe.example.NMSMappedFaweQueue; import com.boydti.fawe.example.NMSMappedFaweQueue;
import com.boydti.fawe.object.FaweLimit; import com.boydti.fawe.object.FaweLimit;
@ -61,20 +66,25 @@ import com.sk89q.worldedit.math.convolution.HeightMap;
import com.sk89q.worldedit.math.convolution.HeightMapFilter; import com.sk89q.worldedit.math.convolution.HeightMapFilter;
import com.sk89q.worldedit.math.noise.RandomNoise; import com.sk89q.worldedit.math.noise.RandomNoise;
import com.sk89q.worldedit.regions.*; import com.sk89q.worldedit.regions.*;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.util.TreeGenerator.TreeType;
import com.sk89q.worldedit.util.command.binding.Range; import com.sk89q.worldedit.util.command.binding.Range;
import com.sk89q.worldedit.util.command.binding.Switch; import com.sk89q.worldedit.util.command.binding.Switch;
import com.sk89q.worldedit.util.command.binding.Text; import com.sk89q.worldedit.util.command.binding.Text;
import com.sk89q.worldedit.util.command.parametric.Optional; import com.sk89q.worldedit.util.command.parametric.Optional;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.biome.Biomes; import com.sk89q.worldedit.world.biome.Biomes;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.registry.BiomeRegistry; import com.sk89q.worldedit.world.registry.BiomeRegistry;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -261,6 +271,19 @@ public class RegionCommands extends MethodCommands {
BBC.VISITOR_BLOCK.send(player, blocksChanged); BBC.VISITOR_BLOCK.send(player, blocksChanged);
} }
@Command(
aliases = {"debugtest"},
usage = "",
desc = "debugtest",
help = "debugtest"
)
public void debugtest(Player player, @Selection Region region) throws WorldEditException {
QueueHandler queueHandler = Fawe.get().getQueueHandler();
World world = player.getWorld();
CountFilter filter = new CountFilter();
queueHandler.apply(world, region, filter);
}
@Command( @Command(
aliases = {"/curve", "/spline"}, aliases = {"/curve", "/spline"},
usage = "<pattern> [thickness]", usage = "<pattern> [thickness]",

View File

@ -710,7 +710,7 @@ public class SelectionCommands {
distributionData = (List) editSession.getBlockDistributionWithData(region); distributionData = (List) editSession.getBlockDistributionWithData(region);
else else
distributionData = (List) editSession.getBlockDistribution(region); distributionData = (List) editSession.getBlockDistribution(region);
size = session.getSelection(player.getWorld()).getArea(); size = region.getArea();
if (distributionData.size() <= 0) { if (distributionData.size() <= 0) {
player.printError(BBC.getPrefix() + "No blocks counted."); player.printError(BBC.getPrefix() + "No blocks counted.");

View File

@ -21,6 +21,8 @@ package com.sk89q.worldedit.command;
import com.boydti.fawe.Fawe; import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweAPI; import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.beta.implementation.QueueHandler;
import com.boydti.fawe.beta.implementation.WorldChunkCache;
import com.boydti.fawe.command.FaweParser; import com.boydti.fawe.command.FaweParser;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Commands; import com.boydti.fawe.config.Commands;
@ -70,6 +72,7 @@ import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.visitor.EntityVisitor; import com.sk89q.worldedit.function.visitor.EntityVisitor;
import com.sk89q.worldedit.internal.annotation.Direction; import com.sk89q.worldedit.internal.annotation.Direction;
import com.sk89q.worldedit.internal.annotation.Selection;
import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;

View File

@ -19,25 +19,23 @@
package com.sk89q.worldedit.world.block; package com.sk89q.worldedit.world.block;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag; import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.world.registry.BlockMaterial;
import com.sk89q.worldedit.world.registry.LegacyMapper;
import com.sk89q.worldedit.blocks.TileEntityBlock;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.registry.state.PropertyKey; import com.sk89q.worldedit.registry.state.PropertyKey;
import com.sk89q.worldedit.world.registry.BlockMaterial;
import com.sk89q.worldedit.world.registry.LegacyMapper;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import static com.google.common.base.Preconditions.checkNotNull;
/** /**
* Represents a "snapshot" of a block with NBT Data. * Represents a "snapshot" of a block with NBT Data.
* *
@ -84,7 +82,6 @@ public class BaseBlock implements BlockStateHolder<BaseBlock> {
*/ */
public BaseBlock(BlockState blockState) { public BaseBlock(BlockState blockState) {
// this(blockState, blockState.getNbtData());
this.blockState = blockState; this.blockState = blockState;
} }
@ -210,7 +207,12 @@ public class BaseBlock implements BlockStateHolder<BaseBlock> {
} }
@Override @Override
public BaseBlock toBaseBlock() { public final char getOrdinalChar() {
return blockState.getOrdinalChar();
}
@Override
public final BaseBlock toBaseBlock() {
return this; return this;
} }

View File

@ -52,6 +52,7 @@ import java.util.stream.Stream;
public class BlockState implements BlockStateHolder<BlockState>, FawePattern { public class BlockState implements BlockStateHolder<BlockState>, FawePattern {
private final int internalId; private final int internalId;
private final int ordinal; private final int ordinal;
private final char ordinalChar;
private final BlockType blockType; private final BlockType blockType;
private BlockMaterial material; private BlockMaterial material;
private BaseBlock emptyBaseBlock; private BaseBlock emptyBaseBlock;
@ -60,6 +61,7 @@ public class BlockState implements BlockStateHolder<BlockState>, FawePattern {
this.blockType = blockType; this.blockType = blockType;
this.internalId = internalId; this.internalId = internalId;
this.ordinal = ordinal; this.ordinal = ordinal;
this.ordinalChar = (char) ordinal;
this.emptyBaseBlock = new BaseBlock(this); this.emptyBaseBlock = new BaseBlock(this);
} }
@ -285,7 +287,7 @@ public class BlockState implements BlockStateHolder<BlockState>, FawePattern {
} }
@Override @Override
public BaseBlock toBaseBlock() { public final BaseBlock toBaseBlock() {
return this.emptyBaseBlock; return this.emptyBaseBlock;
} }
@ -335,6 +337,11 @@ public class BlockState implements BlockStateHolder<BlockState>, FawePattern {
return this.ordinal; return this.ordinal;
} }
@Override
public final char getOrdinalChar() {
return this.ordinalChar;
}
@Override @Override
public String toString() { public String toString() {
return getAsString(); return getAsString();

View File

@ -63,6 +63,9 @@ public interface BlockStateHolder<B extends BlockStateHolder<B>> extends FawePat
@Deprecated @Deprecated
int getOrdinal(); int getOrdinal();
@Deprecated
char getOrdinalChar();
BlockMaterial getMaterial(); BlockMaterial getMaterial();
/** /**
* Get type id (legacy uses) * Get type id (legacy uses)