WIP filter patterns

This commit is contained in:
Jesse Boyd
2019-05-12 23:32:04 +10:00
parent 459629a2f2
commit c797dcb194
61 changed files with 2075 additions and 793 deletions

View File

@ -0,0 +1,88 @@
package com.boydti.fawe.beta;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.awt.image.BufferedImage;
import java.util.concurrent.ThreadLocalRandom;
public class ArrayFilterBlock extends SimpleFilterBlock {
private final char[] blocks;
private final byte[] heights;
private final int yOffset;
private int x, z, index;
private char ordinal;
private final int width, length;
public ArrayFilterBlock(Extent extent, char[] blocks, byte[] heights, int width, int length, int yOffset) {
super(extent);
this.blocks = blocks;
this.width = width;
this.length = length;
this.heights = heights;
this.yOffset = yOffset;
}
public void filter2D(Filter filter) {
for (z = 0; z < length; z++) {
for (x = 0; x < width; x++, index++) {
ordinal = blocks[ordinal];
filter.applyBlock(this);
}
}
}
@Override
public void setOrdinal(int ordinal) {
blocks[index] = (char) ordinal;
}
@Override
public void setState(BlockState state) {
blocks[index] = state.getOrdinalChar();
}
@Override
public void setFullBlock(BaseBlock block) {
blocks[index] = block.getOrdinalChar();
}
@Override
public int getOrdinal() {
return ordinal;
}
@Override
public BlockState getState() {
return BlockTypes.states[ordinal];
}
@Override
public BaseBlock getBaseBlock() {
return getState().toBaseBlock();
}
@Override
public CompoundTag getTag() {
return null;
}
@Override
public int getX() {
return x;
}
@Override
public int getY() {
return (heights[index] & 0xFF) + yOffset;
}
@Override
public int getZ() {
return z;
}
}

View File

@ -4,6 +4,7 @@ import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
@ -12,11 +13,10 @@ import com.sk89q.worldedit.world.registry.BlockMaterial;
import javax.annotation.Nullable;
import static com.sk89q.worldedit.world.block.BlockTypes.states;
public class CharFilterBlock implements FilterBlock {
private IQueueExtent queue;
public class CharFilterBlock extends ChunkFilterBlock {
private CharGetBlocks get;
private ISetBlocks set;
private IChunkSet set;
private char[] getArr;
private @Nullable char[] setArr;
@ -25,14 +25,12 @@ public class CharFilterBlock implements FilterBlock {
// local
private int layer, index, x, y, z, xx, yy, zz, X, Z;
@Override
public final FilterBlock init(final IQueueExtent queue) {
this.queue = queue;
return this;
public CharFilterBlock(IQueueExtent queueExtent) {
super(queueExtent);
}
@Override
public final FilterBlock init(final int X, final int Z, final IGetBlocks chunk) {
public final ChunkFilterBlock init(final int X, final int Z, final IChunkGet chunk) {
this.get = (CharGetBlocks) chunk;
this.X = X;
this.Z = Z;
@ -41,11 +39,32 @@ public class CharFilterBlock implements FilterBlock {
return this;
}
@Override
public final void filter(final IGetBlocks iget, final ISetBlocks iset, final int layer, final Filter filter, final @Nullable Region region, BlockVector3 min, BlockVector3 max) {
public void flood(final IChunkGet iget, final IChunkSet iset, final int layer, Flood flood, FilterBlockMask mask) {
final int maxDepth = flood.getMaxDepth();
final boolean checkDepth = maxDepth < Character.MAX_VALUE;
if (init(iget, iset, layer)) {
while ((index = flood.poll()) != -1) {
x = index & 15;
z = (index >> 4) & 15;
y = (index >> 8) & 15;
if (mask.applyBlock(this)) {
int depth = index >> 12;
if (checkDepth && depth > maxDepth) {
continue;
}
flood.apply(x, y, z, depth);
}
}
}
}
private final boolean init(final IChunkGet iget, final IChunkSet iset, final int layer) {
this.layer = layer;
final CharGetBlocks get = (CharGetBlocks) iget;
if (!get.hasSection(layer)) return;
if (!get.hasSection(layer)) return false;
this.set = iset;
getArr = get.sections[layer].get(get, layer);
if (set.hasSection(layer)) {
@ -56,17 +75,24 @@ public class CharFilterBlock implements FilterBlock {
setArr = null;
}
this.yy = layer << 4;
if (region == null) {
if (min != null && max != null) {
iterate(min, max, layer, filter);
return true;
}
@Override
public final void filter(final IChunkGet iget, final IChunkSet iset, final int layer, final Filter filter, final @Nullable Region region, BlockVector3 min, BlockVector3 max) {
if (init(iget, iset, layer)) {
if (region == null) {
if (min != null && max != null) {
iterate(min, max, layer, filter);
} else {
iterate(filter);
}
} else {
iterate(filter);
}
} else {
if (min != null && max != null) {
iterate(region, min, max, layer, filter);
} else {
iterate(region, filter);
if (min != null && max != null) {
iterate(region, min, max, layer, filter);
} else {
iterate(region, filter);
}
}
}
}
@ -227,7 +253,7 @@ public class CharFilterBlock implements FilterBlock {
@Override
public final CompoundTag getTag() {
return null;
return get.getTag(x, y + (layer << 4), z);
}
public final BlockState getOrdinalBelow() {
@ -310,71 +336,135 @@ public class CharFilterBlock implements FilterBlock {
public final BlockState getStateRelative(final int x, final int y, final int z) {
final int newX = this.x + x;
if (newX >> 4 == 0) {
final int newZ = this.z + z;
if (newZ >> 4 == 0) {
final int newY = this.y + y;
final int layerAdd = newY >> 4;
switch (layerAdd) {
case 0:
return states[getArr[this.index + ((y << 8) + (z << 4) + x)]];
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15: {
final int newLayer = layer + layerAdd;
if (newLayer < 16) {
final int index = ((newY & 15) << 8) + (newZ << 4) + newX;
return states[get.sections[newLayer].get(get, newLayer, index)];
}
break;
}
case -1:
case -2:
case -3:
case -4:
case -5:
case -6:
case -7:
case -8:
case -9:
case -10:
case -11:
case -12:
case -13:
case -14:
case -15: {
final int newLayer = layer + layerAdd;
if (newLayer >= 0) {
final int index = ((newY & 15) << 8) + (newZ << 4) + newX;
return states[get.sections[newLayer].get(get, newLayer, index)];
}
break;
final int newZ = this.z + z;
if (newX >> 4 == 0 && newZ >> 4 == 0) {
final int newY = this.y + y;
final int layerAdd = newY >> 4;
switch (layerAdd) {
case 0:
return states[getArr[this.index + ((y << 8) + (z << 4) + x)]];
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15: {
final int newLayer = layer + layerAdd;
if (newLayer < 16) {
final int index = ((newY & 15) << 8) + (newZ << 4) + newX;
return states[get.sections[newLayer].get(get, newLayer, index)];
}
break;
}
case -1:
case -2:
case -3:
case -4:
case -5:
case -6:
case -7:
case -8:
case -9:
case -10:
case -11:
case -12:
case -13:
case -14:
case -15: {
final int newLayer = layer + layerAdd;
if (newLayer >= 0) {
final int index = ((newY & 15) << 8) + (newZ << 4) + newX;
return states[get.sections[newLayer].get(get, newLayer, index)];
}
break;
}
return BlockTypes.__RESERVED__.getDefaultState();
}
return BlockTypes.__RESERVED__.getDefaultState();
}
// queue.get
// TODO return normal get block
final int newY = this.y + y + yy;
if (newY >= 0 && newY <= 256) {
return queue.getBlock(xx + newX, newY, this.zz + this.z + z);
return getExtent().getBlock(xx + newX, newY, this.zz + newZ);
}
return BlockTypes.__RESERVED__.getDefaultState();
}
public final BaseBlock getFullBlockRelative(final int x, final int y, final int z) {
final int newX = this.x + x;
final int newZ = this.z + z;
if (newX >> 4 == 0 && newZ >> 4 == 0) {
final int newY = this.y + y;
final int layerAdd = newY >> 4;
BlockState state = BlockTypes.__RESERVED__.getDefaultState();
switch (layerAdd) {
case 0:
state = states[getArr[this.index + ((y << 8) + (z << 4) + x)]];
break;
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15: {
final int newLayer = layer + layerAdd;
if (newLayer < 16) {
final int index = ((newY & 15) << 8) + (newZ << 4) + newX;
state = states[get.sections[newLayer].get(get, newLayer, index)];
}
break;
}
case -1:
case -2:
case -3:
case -4:
case -5:
case -6:
case -7:
case -8:
case -9:
case -10:
case -11:
case -12:
case -13:
case -14:
case -15: {
final int newLayer = layer + layerAdd;
if (newLayer >= 0) {
final int index = ((newY & 15) << 8) + (newZ << 4) + newX;
state = states[get.sections[newLayer].get(get, newLayer, index)];
}
break;
}
}
if (state.getMaterial().hasContainer()) {
final CompoundTag tag = get.getTag(x, y + (layer << 4), z);
return state.toBaseBlock(tag);
}
}
final int newY = this.y + y + yy;
if (newY >= 0 && newY <= 256) {
return getExtent().getFullBlock(xx + newX, newY, this.zz + newZ);
}
return BlockTypes.__RESERVED__.getDefaultState().toBaseBlock();
}
/*
Set delegate
*/
@ -383,6 +473,22 @@ public class CharFilterBlock implements FilterBlock {
return delegate = FULL;
}
@Override
public BiomeType getBiome(int x, int z) {
if ((x >> 4) == X && (z >> 4) == Z) {
return get.getBiome(x & 15, z & 15);
}
return getExtent().getBiome(x, z);
}
@Override
public boolean setBiome(int x, int y, int z, BiomeType biome) {
if ((x >> 4) == X && (z >> 4) == Z) {
return set.setBiome(x & 15, z & 15, biome);
}
return getExtent().setBiome(x, y, z, biome);
}
private interface SetDelegate {
void set(CharFilterBlock block, char value);
}

View File

@ -0,0 +1,19 @@
package com.boydti.fawe.beta;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import javax.annotation.Nullable;
public abstract class ChunkFilterBlock extends FilterBlock {
public ChunkFilterBlock(Extent extent) {
super(extent);
}
public abstract ChunkFilterBlock init(int X, int Z, IChunkGet chunk);
public abstract void flood(final IChunkGet iget, final IChunkSet iset, final int layer, Flood flood, FilterBlockMask mask);
public abstract void filter(IChunkGet get, IChunkSet set, int layer, Filter filter, @Nullable Region region, BlockVector3 min, BlockVector3 max);
}

View File

@ -10,7 +10,4 @@ public abstract class DelegateFilter implements IDelegateFilter {
public Filter getParent() {
return parent;
}
@Override
public abstract Filter fork();
}

View File

@ -0,0 +1,5 @@
package com.boydti.fawe.beta;
public interface DirectionMask {
boolean apply(int fromX, int fromY, int fromZ, int toX, int toY, int toZ);
}

View File

@ -1,6 +1,7 @@
package com.boydti.fawe.beta;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.block.BaseBlock;
@ -8,64 +9,97 @@ import com.sk89q.worldedit.world.block.BlockState;
import javax.annotation.Nullable;
public interface FilterBlock {
FilterBlock init(IQueueExtent queue);
public abstract class FilterBlock extends BlockVector3 implements Extent {
private final Extent extent;
FilterBlock init(int X, int Z, IGetBlocks chunk);
public FilterBlock(Extent extent) {
this.extent = extent;
}
void filter(IGetBlocks get, ISetBlocks set, int layer, Filter filter, @Nullable Region region, BlockVector3 min, BlockVector3 max);
public final Extent getExtent() {
return extent;
}
void setOrdinal(int ordinal);
public abstract void setOrdinal(int ordinal);
void setState(BlockState state);
public abstract void setState(BlockState state);
void setFullBlock(BaseBlock block);
public abstract void setFullBlock(BaseBlock block);
int getOrdinal();
public abstract int getOrdinal();
BlockState getState();
public abstract BlockState getState();
BaseBlock getBaseBlock();
public abstract BaseBlock getBaseBlock();
CompoundTag getTag();
public abstract CompoundTag getTag();
default BlockState getOrdinalBelow() {
@Override
public BlockVector3 getMinimumPoint() {
return getExtent().getMinimumPoint();
}
@Override
public BlockVector3 getMaximumPoint() {
return getExtent().getMaximumPoint();
}
@Override
public BlockState getBlock(int x, int y, int z) {
return getStateRelative(x - getX(), y - getY(), z - getZ());
}
@Override
public BaseBlock getFullBlock(int x, int y, int z) {
return getFullBlockRelative(x - getX(), y - getY(), z - getZ());
}
public BlockState getOrdinalBelow() {
return getStateRelative(0, -1, 0);
}
default BlockState getStateAbove() {
public BlockState getStateAbove() {
return getStateRelative(0, 1, 0);
}
default BlockState getStateRelativeY(final int y) {
public BlockState getStateRelativeY(final int y) {
return getStateRelative(0, y, 0);
}
int getX();
public BlockState getStateRelative(final int x, final int y, final int z) {
return getFullBlockRelative(x, y, z).toBlockState();
}
int getY();
public BaseBlock getFullBlockRelative(int x, int y, int z) {
return getExtent().getFullBlock(x + getX(), y + getY(), z + getZ());
}
int getZ();
@Override
public abstract int getX();
default int getLocalX() {
@Override
public abstract int getY();
@Override
public abstract int getZ();
public int getLocalX() {
return getX() & 15;
}
default int getLocalY() {
public int getLocalY() {
return getY() & 15;
}
default int getLocalZ() {
public int getLocalZ() {
return getZ() & 15;
}
default int getChunkX() {
public int getChunkX() {
return getX() >> 4;
}
default int getChunkZ() {
public int getChunkZ() {
return getZ() >> 4;
}
BlockState getStateRelative(final int x, final int y, final int z);
}

View File

@ -0,0 +1,5 @@
package com.boydti.fawe.beta;
public interface FilterBlockMask {
boolean applyBlock(final FilterBlock block);
}

View File

@ -0,0 +1,192 @@
package com.boydti.fawe.beta;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.beta.implementation.QueueHandler;
import com.boydti.fawe.beta.implementation.WorldChunkCache;
import com.boydti.fawe.util.MathMan;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.world.World;
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
public class Flood {
private final int maxBranch;
private final int maxDepth;
private final Direction[] directions;
private int[] queue;
private long[] visit;
private int[][] queues;
private long[][] visits;
private int X, Y, Z;
private ConcurrentLinkedQueue<int[]> queuePool = new ConcurrentLinkedQueue<>();
private final Long2ObjectLinkedOpenHashMap<long[][]> chunkVisits;
private final Long2ObjectLinkedOpenHashMap<int[][]> chunkQueues;
public Flood(int maxBranch, int maxDepth, Direction[] directions) {
this.maxBranch = maxBranch;
this.maxDepth = maxDepth;
this.directions = directions;
this.queues = new int[27][];
this.visits = new long[27][];
this.chunkVisits = new Long2ObjectLinkedOpenHashMap<>();
this.chunkQueues = new Long2ObjectLinkedOpenHashMap<>();
}
public synchronized void run(World world) {
QueueHandler queueHandler = Fawe.get().getQueueHandler();
IQueueExtent fq = queueHandler.getQueue(world);
while (!chunkQueues.isEmpty()) {
long firstKey = chunkQueues.firstLongKey();
int X = MathMan.unpairIntX(firstKey);
int Z = MathMan.unpairIntY(firstKey);
int[][] chunkQueue = chunkQueues.get(firstKey);
// apply
}
}
private void init(int X, int Y, int Z) {
this.X = X;
this.Y = Y;
this.Z = Z;
}
public void start(int x, int y, int z) {
push(x, y, z, 0);
}
private void push(int x, int y, int z, int depth) {
int X = x >> 4;
int Z = z >> 4;
long pair = MathMan.pairInt(X, Z);
int layer = y >> 4;
int[] section = getOrCreateQueue(pair, layer);
int val = (x & 15) + ((z & 15) << 4) + ((y & 15) << 8) + (depth << 12);
push(section, val);
}
private int[] getOrCreateQueue(long pair, int layer) {
int[][] arrs = chunkQueues.get(pair);
if (arrs == null) {
chunkQueues.put(pair, arrs = new int[16][]);
}
int[] section = arrs[layer];
if (section == null) {
arrs[layer] = section = newQueue();
}
return section;
}
private int[] newQueue() {
int[] arr = queuePool.poll();
if (arr != null) {
arr[0] = 2;
arr[1] = 2;
return arr;
}
return new int[4096];
}
public int poll() {
int index = queue[0];
if (index == queue[1]) {
return -1;
}
queue[0] = index + 1;
return queue[index];
}
private void push(int[] queue, int val) {
int indexStart = queue[0];
int indexEnd = queue[1];
push(indexStart, indexEnd, queue, val);
}
private void push(int indexStart, int indexEnd, int[] queue, int val) {
if (indexStart > 2) {
queue[0] = --indexStart;
queue[indexStart] = val;
} else {
queue[indexEnd] = val;
queue[0] = ++indexEnd;
}
}
public Direction[] getDirections() {
return directions;
}
public int getMaxBranch() {
return maxBranch;
}
public int getMaxDepth() {
return maxDepth;
}
public void apply(int x, int y, int z, int depth) {
for (int i = 0, j = 0; i < directions.length && j < maxBranch; i++) {
final Direction dir = directions[i];
final int ty = y + dir.getBlockY();
final int tx = x + dir.getBlockX();
final int tz = z + dir.getBlockZ();
int index;
long[] visit;
int[] queue;
final int or = tx | ty | tz;
if (or > 15 || or < 0) {
visit = this.visit;
queue = this.queue;
index = tx + (tz << 4) + (ty << 8);
} else {
int nextX = tx >> 4;
int nextY = ty >> 4;
int nextZ = tz >> 4;
int sectionIndex = nextX + nextZ * 3 + nextZ * 9 + 13;
visit = visits[sectionIndex];
queue = queues[sectionIndex];
if (visit == null || queue == null) {
long pair = MathMan.pairInt(X + nextX, Z + nextZ);
int layer = Y + nextY;
if (layer < 0 || layer > 15) {
continue;
}
queues[sectionIndex] = queue = getOrCreateQueue(pair, layer);
}
index = (tx & 15) + ((tz & 15) << 4) + ((ty & 15) << 8);
}
if (!getAndSet(visit, index)) {
j++;
push(queue, index + (depth << 12));
}
}
}
public void set(long[] bits, int i) {
bits[i >> 6] |= (1L << (i & 0x3F));
}
public final boolean getAndSet(long[] bits, int i) {
int index = i >> 6;
long offset = (1L << (i & 0x3F));
long val = bits[index];
if ((val & offset) != 0) {
return true;
} else {
bits[index] |= offset;
return false;
}
}
public boolean get(long[] bits, final int i) {
return (bits[i >> 6] & (1L << (i & 0x3F))) != 0;
}
}

View File

@ -11,7 +11,6 @@ import javax.annotation.Nullable;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.function.Supplier;
/**
* Represents a chunk in the queue {@link IQueueExtent}
@ -72,7 +71,9 @@ public interface IChunk<T extends Future<T>> extends Trimable, Callable<T> {
* @param unitialized a mutable block vector (buffer)
* @param unitialized2 a mutable block vector (buffer)
*/
void filter(Filter filter, FilterBlock block, @Nullable Region region, MutableBlockVector3 unitialized, MutableBlockVector3 unitialized2);
void filter(Filter filter, ChunkFilterBlock block, @Nullable Region region, MutableBlockVector3 unitialized, MutableBlockVector3 unitialized2);
void flood(Flood flood, FilterBlockMask mask, ChunkFilterBlock block);
/* set - queues a change */
boolean setBiome(int x, int y, int z, BiomeType biome);

View File

@ -1,6 +1,7 @@
package com.boydti.fawe.beta;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.extent.InputExtent;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
@ -8,11 +9,14 @@ import com.sk89q.worldedit.world.block.BlockState;
/**
* Interface for getting blocks
*/
public interface IGetBlocks extends IBlocks, Trimable {
public interface IChunkGet extends IBlocks, Trimable, InputExtent {
@Override
BaseBlock getFullBlock(int x, int y, int z);
@Override
BiomeType getBiome(int x, int z);
@Override
BlockState getBlock(int x, int y, int z);
CompoundTag getTag(int x, int y, int z);

View File

@ -1,6 +1,7 @@
package com.boydti.fawe.beta;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.extent.OutputExtent;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
@ -14,8 +15,8 @@ import java.util.UUID;
/**
* Interface for setting blocks
*/
public interface ISetBlocks extends IBlocks {
boolean setBiome(int x, int y, int z, BiomeType biome);
public interface IChunkSet extends IBlocks, OutputExtent {
boolean setBiome(int x, int z, BiomeType biome);
boolean setBlock(int x, int y, int z, BlockStateHolder holder);

View File

@ -26,6 +26,11 @@ public interface IDelegateChunk<U extends IChunk> extends IChunk {
return root;
}
@Override
default void flood(Flood flood, FilterBlockMask mask, FilterBlock block) {
getParent().flood(flood, mask, block);
}
@Override
default boolean setBiome(final int x, final int y, final int z, final BiomeType biome) {
return getParent().setBiome(x, y, z, biome);

View File

@ -39,7 +39,11 @@ public interface IDelegateFilter extends Filter {
@Override
default Filter fork() {
return newInstance(getParent().fork());
Filter fork = getParent().fork();
if (fork != getParent()) {
return newInstance(fork);
}
return this;
}
Filter newInstance(Filter other);

View File

@ -1,7 +1,10 @@
package com.boydti.fawe.beta;
import com.boydti.fawe.beta.implementation.WorldChunkCache;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
@ -12,7 +15,7 @@ import java.util.concurrent.Future;
* TODO: implement Extent (need to refactor Extent first)
* Interface for a queue based extent which uses chunks
*/
public interface IQueueExtent extends Flushable, Trimable {
public interface IQueueExtent extends Flushable, Trimable, Extent {
void init(WorldChunkCache world);
/**
@ -51,11 +54,26 @@ public interface IQueueExtent extends Flushable, Trimable {
return chunk.getBlock(x & 15, y, z & 15);
}
@Override
default BaseBlock getFullBlock(int x, int y, int z) {
final IChunk chunk = getCachedChunk(x >> 4, z >> 4);
return chunk.getFullBlock(x & 15, y, z & 15);
}
default BiomeType getBiome(final int x, final int z) {
final IChunk chunk = getCachedChunk(x >> 4, z >> 4);
return chunk.getBiome(x & 15, z & 15);
}
@Override
default BlockVector3 getMinimumPoint() {
return getCache().getWorld().getMinimumPoint();
}
@Override
default BlockVector3 getMaximumPoint() {
return getCache().getWorld().getMaximumPoint();
}
/**
* Create a new root IChunk object<br>
* - Full chunks will be reused, so a more optimized chunk can be returned in that case<br>
@ -81,5 +99,5 @@ public interface IQueueExtent extends Flushable, Trimable {
@Override
void flush();
FilterBlock initFilterBlock();
ChunkFilterBlock initFilterBlock();
}

View File

@ -0,0 +1,70 @@
package com.boydti.fawe.beta;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import javax.annotation.Nullable;
public abstract class SimpleFilterBlock extends FilterBlock {
public SimpleFilterBlock(Extent extent) {
super(extent);
}
private int x, y, z, ordinal;
private CompoundTag nbt;
public void init(int x, int y, int z, int ordinal) {
this.x = x;
this.y = y;
this.z = z;
this.ordinal = ordinal;
}
public void init(int x, int y, int z, int ordinal, CompoundTag nbt) {
this.x = x;
this.y = y;
this.z = z;
this.ordinal = ordinal;
this.nbt = nbt;
}
@Override
public int getOrdinal() {
return ordinal;
}
@Override
public BlockState getState() {
return BlockTypes.states[ordinal];
}
@Override
public BaseBlock getBaseBlock() {
return getState().toBaseBlock(nbt);
}
@Override
public CompoundTag getTag() {
return nbt;
}
@Override
public int getX() {
return x;
}
@Override
public int getY() {
return y;
}
@Override
public int getZ() {
return z;
}
}

View File

@ -0,0 +1,26 @@
package com.boydti.fawe.beta.filters;
import com.boydti.fawe.beta.DelegateFilter;
import com.boydti.fawe.beta.Filter;
import com.boydti.fawe.beta.FilterBlock;
import com.boydti.fawe.beta.FilterBlockMask;
import java.awt.image.BufferedImage;
import java.util.concurrent.ThreadLocalRandom;
public class ArrayImageMask implements FilterBlockMask {
private final ThreadLocalRandom r;
private final boolean white;
private final BufferedImage img;
public ArrayImageMask(BufferedImage img, boolean white) {
this.img = img;
this.white = white;
this.r = ThreadLocalRandom.current();
}
@Override
public boolean applyBlock(FilterBlock block) {
int height = img.getRGB(block.getX(), block.getZ()) & 0xFF;
return ((height == 255 || height > 0 && !white && r.nextInt(256) <= height));
}
}

View File

@ -2,6 +2,7 @@ package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.ChunkFilterBlock;
import com.boydti.fawe.beta.Filter;
import com.boydti.fawe.beta.FilterBlock;
import com.boydti.fawe.beta.IChunk;
@ -163,7 +164,7 @@ public abstract class QueueHandler implements Trimable, Runnable {
// Create a chunk that we will reuse/reset for each operation
final IQueueExtent queue = getQueue(world);
synchronized (queue) {
FilterBlock block = null;
ChunkFilterBlock block = null;
while (true) {
// Get the next chunk posWeakChunk

View File

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

View File

@ -1,6 +1,6 @@
package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.beta.IGetBlocks;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.Trimable;
import com.sk89q.worldedit.world.World;
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
@ -15,7 +15,7 @@ import java.util.function.Supplier;
* - avoids conversion between palette and raw data on every block get
*/
public class WorldChunkCache implements Trimable {
protected final Long2ObjectLinkedOpenHashMap<WeakReference<IGetBlocks>> getCache;
protected final Long2ObjectLinkedOpenHashMap<WeakReference<IChunkGet>> getCache;
private final World world;
protected WorldChunkCache(final World world) {
@ -37,13 +37,13 @@ public class WorldChunkCache implements Trimable {
* @param provider used to create if it isn't already cached
* @return cached IGetBlocks
*/
public synchronized IGetBlocks get(final long index, final Supplier<IGetBlocks> provider) {
final WeakReference<IGetBlocks> ref = getCache.get(index);
public synchronized IChunkGet get(final long index, final Supplier<IChunkGet> provider) {
final WeakReference<IChunkGet> ref = getCache.get(index);
if (ref != null) {
final IGetBlocks blocks = ref.get();
final IChunkGet blocks = ref.get();
if (blocks != null) return blocks;
}
final IGetBlocks blocks = provider.get();
final IChunkGet blocks = provider.get();
getCache.put(index, new WeakReference<>(blocks));
return blocks;
}
@ -52,11 +52,11 @@ public class WorldChunkCache implements Trimable {
public synchronized boolean trim(final boolean aggressive) {
boolean result = true;
if (!getCache.isEmpty()) {
final ObjectIterator<Long2ObjectMap.Entry<WeakReference<IGetBlocks>>> iter = getCache.long2ObjectEntrySet().fastIterator();
final ObjectIterator<Long2ObjectMap.Entry<WeakReference<IChunkGet>>> iter = getCache.long2ObjectEntrySet().fastIterator();
while (iter.hasNext()) {
final Long2ObjectMap.Entry<WeakReference<IGetBlocks>> entry = iter.next();
final WeakReference<IGetBlocks> value = entry.getValue();
final IGetBlocks igb = value.get();
final Long2ObjectMap.Entry<WeakReference<IChunkGet>> entry = iter.next();
final WeakReference<IChunkGet> value = entry.getValue();
final IChunkGet igb = value.get();
if (igb == null) iter.remove();
else {
result = false;

View File

@ -1,11 +1,11 @@
package com.boydti.fawe.beta.implementation.blocks;
import com.boydti.fawe.beta.IGetBlocks;
import com.boydti.fawe.beta.IChunkGet;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
public abstract class CharGetBlocks extends CharBlocks implements IGetBlocks {
public abstract class CharGetBlocks extends CharBlocks implements IChunkGet {
@Override
public BaseBlock getFullBlock(final int x, final int y, final int z) {
return BlockTypes.states[get(x, y, z)].toBaseBlock();

View File

@ -1,6 +1,6 @@
package com.boydti.fawe.beta.implementation.blocks;
import com.boydti.fawe.beta.ISetBlocks;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.util.MathMan;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.world.biome.BiomeType;
@ -14,7 +14,7 @@ import java.util.Map;
import java.util.Set;
import java.util.UUID;
public class CharSetBlocks extends CharBlocks implements ISetBlocks {
public class CharSetBlocks extends CharBlocks implements IChunkSet {
public BiomeType[] biomes;
public HashMap<Short, CompoundTag> tiles;
public HashSet<CompoundTag> entities;

View File

@ -1,12 +1,15 @@
package com.boydti.fawe.beta.implementation.holder;
import com.boydti.fawe.beta.ChunkFilterBlock;
import com.boydti.fawe.beta.Filter;
import com.boydti.fawe.beta.FilterBlock;
import com.boydti.fawe.beta.FilterBlockMask;
import com.boydti.fawe.beta.Flood;
import com.boydti.fawe.beta.IQueueExtent;
import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IGetBlocks;
import com.boydti.fawe.beta.ISetBlocks;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.implementation.SingleThreadQueueExtent;
import com.boydti.fawe.beta.implementation.WorldChunkCache;
import com.boydti.fawe.util.MathMan;
@ -23,9 +26,9 @@ import java.util.function.Supplier;
/**
* Abstract IChunk class that implements basic get/set blocks
*/
public abstract class ChunkHolder implements IChunk, Supplier<IGetBlocks> {
private IGetBlocks get;
private ISetBlocks set;
public abstract class ChunkHolder implements IChunk, Supplier<IChunkGet> {
private IChunkGet get;
private IChunkSet set;
private IBlockDelegate delegate;
private IQueueExtent extent;
private int X,Z;
@ -39,9 +42,14 @@ public abstract class ChunkHolder implements IChunk, Supplier<IGetBlocks> {
}
@Override
public void filter(final Filter filter, FilterBlock block, @Nullable Region region, final MutableBlockVector3 min, final MutableBlockVector3 max) {
final IGetBlocks get = getOrCreateGet();
final ISetBlocks set = getOrCreateSet();
public void flood(Flood flood, FilterBlockMask mask, ChunkFilterBlock block) {
// block.flood(get, set, mask, block, );
}
@Override
public void filter(final Filter filter, ChunkFilterBlock block, @Nullable Region region, @Nullable final MutableBlockVector3 min, @Nullable final MutableBlockVector3 max) {
final IChunkGet get = getOrCreateGet();
final IChunkSet set = getOrCreateSet();
try {
if (region != null) {
switch (region.getChunkBounds(X, Z, min, max)) {
@ -106,21 +114,21 @@ public abstract class ChunkHolder implements IChunk, Supplier<IGetBlocks> {
return set == null || set.isEmpty();
}
public final IGetBlocks getOrCreateGet() {
public final IChunkGet getOrCreateGet() {
if (get == null) get = newGet();
return get;
}
public final ISetBlocks getOrCreateSet() {
public final IChunkSet getOrCreateSet() {
if (set == null) set = set();
return set;
}
public ISetBlocks set() {
public IChunkSet set() {
return new CharSetBlocks();
}
private IGetBlocks newGet() {
private IChunkGet newGet() {
if (extent instanceof SingleThreadQueueExtent) {
final WorldChunkCache cache = ((SingleThreadQueueExtent) extent).getCache();
return cache.get(MathMan.pairInt(X, Z), this);

View File

@ -1,5 +1,8 @@
package com.boydti.fawe.beta.implementation.holder;
import com.boydti.fawe.beta.FilterBlock;
import com.boydti.fawe.beta.FilterBlockMask;
import com.boydti.fawe.beta.Flood;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IDelegateChunk;

View File

@ -2,6 +2,12 @@ package com.boydti.fawe.jnbt.anvil;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.ArrayFilterBlock;
import com.boydti.fawe.beta.DelegateFilter;
import com.boydti.fawe.beta.Filter;
import com.boydti.fawe.beta.FilterBlock;
import com.boydti.fawe.beta.SimpleFilterBlock;
import com.boydti.fawe.beta.filters.ArrayImageMask;
import com.boydti.fawe.example.SimpleIntFaweChunk;
import com.boydti.fawe.jnbt.anvil.HeightMapMCADrawer;
import com.boydti.fawe.jnbt.anvil.MCAChunk;
@ -1022,7 +1028,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
@Override
public BlockState getBlock(BlockVector3 position) {
return getLazyBlock(position);
return getBlock(position.getX(), position.getY(), position.getZ());
}
public BlockState getFloor(int x, int z) {
@ -1045,12 +1051,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
}
@Override
public BlockState getLazyBlock(BlockVector3 position) {
return getLazyBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ());
}
@Override
public BlockState getLazyBlock(int x, int y, int z) {
public BlockState getBlock(int x, int y, int z) {
return BlockState.getFromInternalId(getCombinedId4Data(x, y, z));
}
@ -1340,6 +1341,11 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
}
}
public void test() {
// ArrayImageMask mask = new ArrayImageMask(img, white);
// filter = new ArrayFilterBlock(this, overlayArr, heights.get(), getWidth(), getLength(), 1);
}
public void setOverlay(BufferedImage img, Pattern pattern, boolean white) {
if (pattern instanceof BlockStateHolder) {
setOverlay(img, ((BlockStateHolder) pattern).getInternalId(), white);

View File

@ -72,7 +72,7 @@ public interface FaweQueue extends HasFaweQueue, Extent {
}
@Override
default BlockState getLazyBlock(int x, int y, int z) {
default BlockState getBlock(int x, int y, int z) {
int combinedId4Data = getCachedCombinedId4Data(x, y, z, BlockTypes.AIR.getInternalId());
try {
BlockState state = BlockState.getFromInternalId(combinedId4Data);

View File

@ -50,6 +50,7 @@ public class SurfaceSpline implements Brush {
n.setContinuity(continuity);
nodes.add(n);
}
MutableBlockVector3 mutable = MutableBlockVector3.at(0, 0, 0);
interpol.setNodes(nodes);
final double splinelength = interpol.arcLength(0, 1);
for (double loop = 0; loop <= 1; loop += 1D / splinelength / quality) {
@ -60,7 +61,7 @@ public class SurfaceSpline implements Brush {
tipy = editSession.getNearestSurfaceTerrainBlock(tipx, tipz, tipy, 0, maxY);
if (tipy == -1) continue;
if (radius == 0) {
BlockVector3 set = MutableBlockVector3.get(tipx, tipy, tipz);
BlockVector3 set = mutable.setComponents(tipx, tipy, tipz);
try {
pattern.apply(editSession, set, set);
} catch (WorldEditException e) {

View File

@ -24,7 +24,12 @@ public interface VirtualWorld extends SimpleWorld, FaweQueue, Closeable {
@Override
default BaseBlock getFullBlock(BlockVector3 position) {
return getLazyBlock(position).toBaseBlock();
return getBlock(position).toBaseBlock();
}
@Override
default BaseBlock getFullBlock(int x, int y, int z) {
return getBlock(x, y, z).toBaseBlock();
}
@Override

View File

@ -43,7 +43,7 @@ public class BlockVectorSet extends AbstractCollection<BlockVector3> implements
int newSize = count + size;
if (newSize > index) {
int localIndex = index - count;
MutableBlockVector3 pos = new MutableBlockVector3(set.getIndex(localIndex));
BlockVector3 pos = set.getIndex(localIndex);
if (pos != null) {
int pair = entry.getIntKey();
int cx = MathMan.unpairX(pair);

View File

@ -244,9 +244,9 @@ public final class DifferentialArray<T> implements DifferentialCollection<T> {
return dataBytes;
}
// public char[] getCharArray() {
// return dataChars;
// }
public char[] getCharArray() {
return dataChars;
}
public int[] getIntArray() {
return dataInts;

View File

@ -0,0 +1,213 @@
package com.boydti.fawe.object.collection;
import com.boydti.fawe.object.FaweInputStream;
import com.boydti.fawe.object.FaweOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
/**
* Records changes made through the {@link #set(int, int, int, char)} method<br/>
* Changes are not recorded if you edit the raw data
*/
public final class DifferentialCharBlockBuffer implements DifferentialCollection<char[][][][][]> {
private final int width, length;
private final int t1, t2;
private char[][][][][] data;
private char[][][][][] changes;
public DifferentialCharBlockBuffer(int width, int length) {
this.width = width;
this.length = length;
this.t1 = (length + 15) >> 4;
this.t2 = (width + 15) >> 4;
}
@Override
public char[][][][][] get() {
return data;
}
@Override
public void flushChanges(FaweOutputStream out) throws IOException {
boolean modified = isModified();
out.writeBoolean(modified);
if (modified) {
writeArray(changes, 0, 0, out);
}
clearChanges();
}
private void writeArray(Object arr, int level, int index, FaweOutputStream out) throws IOException {
if (level == 4) {
if (arr != null) {
char[] level4 = (char[]) arr;
out.writeVarInt(level4.length);
for (char c : level4) {
out.writeChar(c);
}
} else {
out.writeVarInt(0);
}
} else {
int len = arr == null ? 0 : Array.getLength(arr);
out.writeVarInt(len);
for (int i = 0; i < len; i++) {
Object elem = Array.get(arr, i);
writeArray(elem, level + 1, i, out);
}
}
}
@Override
public void undoChanges(FaweInputStream in) throws IOException {
if (changes != null && changes.length != 0) throw new IllegalStateException("There are uncommitted changes, please flush first");
boolean modified = in.readBoolean();
if (modified) {
int len = in.readVarInt();
if (len == 0) {
data = null;
} else {
for (int i = 0; i < len; i++) {
readArray(data, i, 1, in);
}
}
}
clearChanges();
}
@Override
public void redoChanges(FaweInputStream in) throws IOException {
clearChanges();
throw new UnsupportedOperationException("Not implemented");
}
private void readArray(Object dataElem, int index, int level, FaweInputStream in) throws IOException {
int len = in.readVarInt();
if (level == 4) {
char[][] castedElem = (char[][]) dataElem;
if (len == 0) {
castedElem[index] = null;
} else {
char[] current = castedElem[index];
for (int i = 0; i < len; i++) {
current[i] = in.readChar();
}
}
} else {
if (len == 0) {
Array.set(dataElem, index, null);
} else {
Object nextElem = Array.get(dataElem, index);
for (int i = 0; i < len; i++) {
readArray(nextElem, i, level + 1, in);
}
}
}
}
public boolean isModified() {
return changes != null;
}
public void clearChanges() {
changes = null;
}
public void set(int x, int y, int z, char combined) {
if (combined == 0) combined = 1;
int localX = x & 15;
int localZ = z & 15;
int chunkX = x >> 4;
int chunkZ = z >> 4;
if (data == null) {
data = new char[t1][][][][];
changes = new char[0][][][][];
}
char[][][][] arr = data[chunkZ];
if (arr == null) {
arr = data[chunkZ] = new char[t2][][][];
}
char[][][] arr2 = arr[chunkX];
if (arr2 == null) {
arr2 = arr[chunkX] = new char[256][][];
}
char[][] yMap = arr2[y];
if (yMap == null) {
arr2[y] = yMap = new char[16][];
}
boolean newSection;
char current;
char[] zMap = yMap[localZ];
if (zMap == null) {
yMap[localZ] = zMap = new char[16];
if (changes == null) {
changes = new char[t1][][][][];
} else if (changes != null && changes.length != 0) {
initialChange(changes, chunkX, chunkZ, localX, localZ, y, (char) -combined);
}
} else {
if (changes == null || changes.length == 0) changes = new char[t1][][][][];
appendChange(changes, chunkX, chunkZ, localX, localZ, y, (char) (zMap[localX] - combined));
}
zMap[localX] = combined;
}
private void initialChange(char[][][][][] src, int chunkX, int chunkZ, int localX, int localZ, int y, char combined) {
char[][][][] arr = src[chunkZ];
if (arr == null) {
src[chunkZ] = new char[0][][][];
return;
} else if (arr.length == 0) return;
char[][][] arr2 = arr[chunkX];
if (arr2 == null) {
arr[chunkX] = new char[0][][];
return;
} else if (arr2.length == 0) return;
char[][] yMap = arr2[y];
if (yMap == null) {
arr2[y] = new char[0][];
return;
} else if (yMap.length == 0) return;
char[] zMap = yMap[localZ];
if (zMap == null) {
yMap[localZ] = new char[0];
return;
} else if (zMap.length == 0) return;
char current = zMap[localX];
zMap[localX] = combined;
}
private void appendChange(char[][][][][] src, int chunkX, int chunkZ, int localX, int localZ, int y, char combined) {
char[][][][] arr = src[chunkZ];
if (arr == null || arr.length == 0) {
arr = src[chunkZ] = new char[t2][][][];
}
char[][][] arr2 = arr[chunkX];
if (arr2 == null || arr2.length == 0) {
arr2 = arr[chunkX] = new char[256][][];
}
char[][] yMap = arr2[y];
if (yMap == null || yMap.length == 0) {
arr2[y] = yMap = new char[16][];
}
char[] zMap = yMap[localZ];
if (zMap == null || zMap.length == 0) {
yMap[localZ] = zMap = new char[16];
}
zMap[localX] = combined;
}
}

View File

@ -100,7 +100,7 @@ public class LocalBlockVectorSet implements Set<BlockVector3> {
this.offsetZ = z;
}
public BlockVector3 getIndex(int getIndex) {
protected BlockVector3 getIndex(int getIndex) {
int size = size();
if (getIndex > size) {
return null;

View File

@ -2,8 +2,10 @@ package com.boydti.fawe.object.pattern;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.FilterBlock;
import com.boydti.fawe.object.DataAnglePattern;
import com.boydti.fawe.util.TextureHolder;
import com.boydti.fawe.util.TextureUtil;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
@ -15,11 +17,11 @@ import com.sk89q.worldedit.world.block.BlockType;
import java.io.IOException;
public class AngleColorPattern extends DataAnglePattern {
protected transient TextureHolder util;
protected transient TextureUtil util;
public AngleColorPattern(Extent extent, TextureHolder util, int distance) {
public AngleColorPattern(Extent extent, TextureHolder holder, int distance) {
super(extent, distance);
this.util = util;
this.util = holder.getTextureUtil();
}
public int getColor(int color, int slope) {
@ -31,15 +33,28 @@ public class AngleColorPattern extends DataAnglePattern {
return (((color >> 24) & 0xFF) << 24) + (newRed << 16) + (newGreen << 8) + (newBlue << 0);
}
@Override
public void apply(FilterBlock block) {
BlockState state = block.getState();
int slope = getSlope(state, block);
if (slope == -1) return;
int color = util.getColor(state.getBlockType());
if (color == 0) return;
int newColor = getColor(color, slope);
BlockType newBlock = util.getNearestBlock(newColor);
if (newBlock == null) return;
newBlock.apply(block);
}
@Override
public BaseBlock apply(BlockVector3 position) {
BaseBlock block = extent.getFullBlock(position);
int slope = getSlope(block, position);
if (slope == -1) return block;
int color = util.getTextureUtil().getColor(block.getBlockType());
int color = util.getColor(block.getBlockType());
if (color == 0) return block;
int newColor = getColor(color, slope);
return util.getTextureUtil().getNearestBlock(newColor).getDefaultState().toBaseBlock();
return util.getNearestBlock(newColor).getDefaultState().toBaseBlock();
}
@Override
@ -51,7 +66,7 @@ public class AngleColorPattern extends DataAnglePattern {
int z = vector.getBlockZ();
int height = extent.getNearestSurfaceTerrainBlock(x, z, y, 0, maxY);
if (height > 0) {
BlockStateHolder below = extent.getLazyBlock(x, height - 1, z);
BlockStateHolder below = extent.getBlock(x, height - 1, z);
if (!below.getBlockType().getMaterial().isMovementBlocker()) {
return Integer.MAX_VALUE;
}
@ -65,16 +80,11 @@ public class AngleColorPattern extends DataAnglePattern {
BlockStateHolder block = extent.getBlock(getPosition);
int slope = getSlope(block, getPosition);
if (slope == -1) return false;
int color = util.getTextureUtil().getColor(block.getBlockType());
int color = util.getColor(block.getBlockType());
if (color == 0) return false;
int newColor = getColor(color, slope);
BlockType newBlock = util.getTextureUtil().getNearestBlock(newColor);
BlockType newBlock = util.getNearestBlock(newColor);
if (newBlock == null) return false;
return extent.setBlock(setPosition, newBlock.getDefaultState());
}
private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException {
stream.defaultReadObject();
util = Fawe.get().getCachedTextureUtil(true, 0, 100);
}
}

View File

@ -1,5 +1,6 @@
package com.boydti.fawe.object.pattern;
import com.boydti.fawe.beta.FilterBlock;
import com.boydti.fawe.object.PseudoRandom;
import com.boydti.fawe.object.schematic.Schematic;
import com.sk89q.worldedit.WorldEditException;
@ -25,14 +26,15 @@ public class RandomFullClipboardPattern extends AbstractPattern {
private final Extent extent;
private final MutableBlockVector3 mutable = new MutableBlockVector3();
private final List<ClipboardHolder> clipboards;
private boolean randomRotate;
private boolean randomFlip;
private final boolean randomRotate;
private final boolean randomFlip;
public RandomFullClipboardPattern(Extent extent, List<ClipboardHolder> clipboards, boolean randomRotate, boolean randomFlip) {
checkNotNull(clipboards);
this.clipboards = clipboards;
this.extent = extent;
this.randomRotate = randomRotate;
this.randomFlip = randomFlip;
}
@Override

View File

@ -86,16 +86,4 @@ public class FaweQueueDelegateExtent extends DelegateFaweQueue {
public boolean setBlock(int x, int y, int z, BlockStateHolder block) throws WorldEditException {
return parentExtent.setBlock(x, y, z, block);
}
@Override
public BlockState getLazyBlock(BlockVector3 position) {
return parentExtent.getLazyBlock(position);
}
@Override
public BlockState getLazyBlock(int x, int y, int z) {
return parentExtent.getLazyBlock(x, y, z);
}
}

View File

@ -2,14 +2,36 @@ package com.boydti.fawe.util;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.jnbt.anvil.MCAQueue;
import com.boydti.fawe.jnbt.anvil.MCAWorld;
import com.boydti.fawe.logging.LoggingChangeSet;
import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory;
import com.boydti.fawe.object.*;
import com.boydti.fawe.object.brush.visualization.VirtualWorld;
import com.boydti.fawe.object.changeset.BlockBagChangeSet;
import com.boydti.fawe.object.changeset.CPUOptimizedChangeSet;
import com.boydti.fawe.object.changeset.DiskStorageHistory;
import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.boydti.fawe.object.changeset.MemoryOptimizedHistory;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.object.extent.FastWorldEditExtent;
import com.boydti.fawe.object.extent.HeightBoundExtent;
import com.boydti.fawe.object.extent.MultiRegionExtent;
import com.boydti.fawe.object.extent.NullExtent;
import com.boydti.fawe.object.extent.ProcessedWEExtent;
import com.boydti.fawe.object.extent.SingleRegionExtent;
import com.boydti.fawe.object.extent.SlowExtent;
import com.boydti.fawe.object.extent.StripNBTExtent;
import com.boydti.fawe.object.progress.ChatProgressTracker;
import com.boydti.fawe.object.progress.DefaultProgressTracker;
import com.boydti.fawe.wrappers.WorldWrapper;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.event.extent.EditSessionEvent;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.eventbus.EventBus;
@ -190,7 +212,214 @@ public class EditSessionBuilder {
return this;
}
private boolean wrapped;
private AbstractDelegateExtent wrapExtent(final AbstractDelegateExtent extent, final EventBus eventBus, EditSessionEvent event, final EditSession.Stage stage) {
event = event.clone(stage);
event.setExtent(extent);
eventBus.post(event);
if (event.isCancelled()) {
return new NullExtent(extent, BBC.WORLDEDIT_CANCEL_REASON_MANUAL);
}
final Extent toReturn = event.getExtent();
if(toReturn instanceof com.sk89q.worldedit.extent.NullExtent) {
return new NullExtent(toReturn, null);
}
if (!(toReturn instanceof AbstractDelegateExtent)) {
Fawe.debug("Extent " + toReturn + " must be AbstractDelegateExtent");
return extent;
}
if (toReturn != extent) {
String className = toReturn.getClass().getName().toLowerCase();
for (String allowed : Settings.IMP.EXTENT.ALLOWED_PLUGINS) {
if (className.contains(allowed.toLowerCase())) {
this.wrapped = true;
return (AbstractDelegateExtent) toReturn;
}
}
if (Settings.IMP.EXTENT.DEBUG) {
Fawe.debug("&cPotentially unsafe extent blocked: " + toReturn.getClass().getName());
Fawe.debug("&8 - &7For area restrictions, it is recommended to use the FaweAPI");
Fawe.debug("&8 - &7For block logging, it is recommended to use use BlocksHub");
Fawe.debug("&8 - &7To allow this plugin add it to the FAWE `allowed-plugins` list");
Fawe.debug("&8 - &7To hide this message set `debug` to false in the FAWE config.yml");
if (toReturn.getClass().getName().contains("CoreProtect")) {
Fawe.debug("Note on CoreProtect: ");
Fawe.debug(" - If you disable CP's WE logger (CP config) and this still shows, please update CP");
Fawe.debug(" - Use BlocksHub and set `debug` false in the FAWE config");
}
}
}
return extent;
}
public EditSessionBuilder commit() {
// reset
wrapped = false;
//
if (worldName == null) {
if (world == null) {
if (queue == null) {
worldName = "";
} else {
worldName = queue.getWorldName();
}
} else {
worldName = Fawe.imp().getWorldName(world);
}
}
if (world == null && !this.worldName.isEmpty()) {
world = FaweAPI.getWorld(this.worldName);
}
if (eventBus == null) {
eventBus = WorldEdit.getInstance().getEventBus();
}
if (event == null) {
event = new EditSessionEvent(world, player == null ? null : (player.getPlayer()), -1, null);
}
if (player == null && event.getActor() != null) {
player = FawePlayer.wrap(event.getActor());
}
if (limit == null) {
if (player == null) {
limit = FaweLimit.MAX;
} else {
limit = player.getLimit();
}
}
if (autoQueue == null) {
autoQueue = true;
}
if (fastmode == null) {
if (player == null) {
fastmode = !Settings.IMP.HISTORY.ENABLE_FOR_CONSOLE;
} else {
fastmode = player.getSession().hasFastMode();
}
}
if (checkMemory == null) {
checkMemory = player != null && !this.fastmode;
}
if (checkMemory) {
if (MemUtil.isMemoryLimitedSlow()) {
if (Perm.hasPermission(player, "worldedit.fast")) {
BBC.WORLDEDIT_OOM_ADMIN.send(player);
}
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_LOW_MEMORY);
}
}
// this.originalLimit = limit;
this.blockBag = limit.INVENTORY_MODE != 0 ? blockBag : null;
// this.limit = limit.copy();
if (queue == null) {
boolean placeChunks = this.fastmode || this.limit.FAST_PLACEMENT;
World unwrapped = WorldWrapper.unwrap(world);
if (unwrapped instanceof FaweQueue) {
queue = (FaweQueue) unwrapped;
} else if (unwrapped instanceof MCAWorld) {
queue = ((MCAWorld) unwrapped).getQueue();
} else if (player != null && world.equals(player.getWorld())) {
queue = player.getFaweQueue(placeChunks, autoQueue);
} else {
queue = SetQueue.IMP.getNewQueue(world, placeChunks, autoQueue);
}
}
if (combineStages == null) {
combineStages =
// If it's enabled in the settings
Settings.IMP.HISTORY.COMBINE_STAGES
// If fast placement is disabled, it's slower to perform a copy on each chunk
&& this.limit.FAST_PLACEMENT
// If the specific queue doesn't support it
&& queue.supports(FaweQueue.Capability.CHANGE_TASKS)
// If the edit uses items from the inventory we can't use a delayed task
&& this.blockBag == null;
}
// if (Settings.IMP.EXPERIMENTAL.ANVIL_QUEUE_MODE && !(queue instanceof MCAQueue)) {
// queue = new MCAQueue(queue);
// }
if (!Settings.IMP.QUEUE.PROGRESS.DISPLAY.equalsIgnoreCase("false") && player != null) {
switch (Settings.IMP.QUEUE.PROGRESS.DISPLAY.toLowerCase()) {
case "chat":
this.queue.setProgressTask(new ChatProgressTracker(player));
break;
case "title":
case "true":
default:
this.queue.setProgressTask(new DefaultProgressTracker(player));
}
}
// this.bypassAll = wrapExtent(new FastWorldEditExtent(world, queue), eventBus, event, EditSession.Stage.BEFORE_CHANGE);
// this.bypassHistory = (this.extent = wrapExtent(bypassAll, eventBus, event, EditSession.Stage.BEFORE_REORDER));
// if (!this.fastMode || changeSet != null) {
// if (changeSet == null) {
// if (Settings.IMP.HISTORY.USE_DISK) {
// UUID uuid = player == null ? EditSession.CONSOLE : player.getUUID();
// if (Settings.IMP.HISTORY.USE_DATABASE) {
// changeSet = new RollbackOptimizedHistory(world, uuid);
// } else {
// changeSet = new DiskStorageHistory(world, uuid);
// }
// } else if (combineStages && Settings.IMP.HISTORY.COMPRESSION_LEVEL == 0 && !(queue instanceof MCAQueue)) {
// changeSet = new CPUOptimizedChangeSet(world);
// } else {
// changeSet = new MemoryOptimizedHistory(world);
// }
// }
// if (this.limit.SPEED_REDUCTION > 0) {
// this.bypassHistory = new SlowExtent(this.bypassHistory, this.limit.SPEED_REDUCTION);
// }
// if (changeSet instanceof NullChangeSet && Fawe.imp().getBlocksHubApi() != null && player != null) {
// changeSet = LoggingChangeSet.wrap(player, changeSet);
// }
// if (!(changeSet instanceof NullChangeSet)) {
// if (!(changeSet instanceof LoggingChangeSet) && player != null && Fawe.imp().getBlocksHubApi() != null) {
// changeSet = LoggingChangeSet.wrap(player, changeSet);
// }
// if (this.blockBag != null) {
// changeSet = new BlockBagChangeSet(changeSet, blockBag, limit.INVENTORY_MODE == 1);
// }
// if (combineStages) {
// changeTask = changeSet;
// changeSet.addChangeTask(queue);
// } else {
// this.extent = (history = new HistoryExtent(this, bypassHistory, changeSet, queue));
//// if (this.blockBag != null) {
//// this.extent = new BlockBagExtent(this.extent, blockBag, limit.INVENTORY_MODE == 1);
//// }
// }
// }
// }
// if (allowedRegions == null) {
// if (player != null && !player.hasPermission("fawe.bypass") && !player.hasPermission("fawe.bypass.regions") && !(queue instanceof VirtualWorld)) {
// allowedRegions = player.getCurrentRegions();
// }
// }
// this.maxY = getWorld() == null ? 255 : world.getMaxY();
// if (allowedRegions != null) {
// if (allowedRegions.length == 0) {
// this.extent = new NullExtent(this.extent, BBC.WORLDEDIT_CANCEL_REASON_NO_REGION);
// } else {
// this.extent = new ProcessedWEExtent(this.extent, this.limit);
// if (allowedRegions.length == 1) {
// Region region = allowedRegions[0];
// this.extent = new SingleRegionExtent(this.extent, this.limit, allowedRegions[0]);
// } else {
// this.extent = new MultiRegionExtent(this.extent, this.limit, allowedRegions);
// }
// }
// } else {
// this.extent = new HeightBoundExtent(this.extent, this.limit, 0, maxY);
// }
// if (this.limit.STRIP_NBT != null && !this.limit.STRIP_NBT.isEmpty()) {
// this.extent = new StripNBTExtent(this.extent, this.limit.STRIP_NBT);
// }
// this.extent = wrapExtent(this.extent, bus, event, Stage.BEFORE_HISTORY);
return this;
}
public EditSession build() {
return new EditSession(worldName, world, queue, player, limit, changeSet, allowedRegions, autoQueue, fastmode, checkMemory, combineStages, blockBag, eventBus, event);
return new EditSession(worldName, world, queue, player, limit, changeSet, allowedRegions, autoQueue, fastmode, checkMemory, combineStages, blockBag, eventBus, event);
}
}

View File

@ -486,7 +486,7 @@ public class TextureUtil implements TextureHolder {
BlockType block = getNearestBlock(color);
TextureUtil.BiomeColor biome = getNearestBiome(color);
int blockColor = getColor(block);
blockAndBiomeIdOutput[0] = block.getInternalId();
blockAndBiomeIdOutput[0] = block.getDefaultState().getOrdinalChar();
blockAndBiomeIdOutput[1] = biome.id;
if (colorDistance(biome.grassCombined, color) - biomePriority > colorDistance(blockColor,
color)) {

View File

@ -235,11 +235,6 @@ public class WorldWrapper extends AbstractWorld {
return parent.getBlock(position);
}
@Override
public BlockState getLazyBlock(BlockVector3 position) {
return parent.getLazyBlock(position);
}
@Override
public BaseBlock getFullBlock(BlockVector3 position) {
return parent.getFullBlock(position);