Fix setting the same block multiple times sequencially

This commit is contained in:
Jesse Boyd
2019-04-17 01:12:09 +10:00
parent 2a373b1390
commit 274c52163b
12 changed files with 382 additions and 150 deletions

View File

@ -1,19 +1,17 @@
package com.boydti.fawe.example;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.util.MathMan;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockID;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.*;
public abstract class IntFaweChunk<T, V extends FaweQueue> extends FaweChunk<T> {
public final int[][] ids;
public final int[][] setBlocks;
public final short[] count;
public final short[] air;
@ -24,9 +22,9 @@ public abstract class IntFaweChunk<T, V extends FaweQueue> extends FaweChunk<T>
public T chunk;
public IntFaweChunk(FaweQueue parent, int x, int z, int[][] ids, short[] count, short[] air) {
public IntFaweChunk(FaweQueue parent, int x, int z, int[][] setBlocks, short[] count, short[] air) {
super(parent, x, z);
this.ids = ids;
this.setBlocks = setBlocks;
this.count = count;
this.air = air;
}
@ -40,7 +38,7 @@ public abstract class IntFaweChunk<T, V extends FaweQueue> extends FaweChunk<T>
*/
public IntFaweChunk(FaweQueue parent, int x, int z) {
super(parent, x, z);
this.ids = new int[HEIGHT >> 4][];
this.setBlocks = new int[HEIGHT >> 4][];
this.count = new short[HEIGHT >> 4];
this.air = new short[HEIGHT >> 4];
}
@ -103,8 +101,8 @@ public abstract class IntFaweChunk<T, V extends FaweQueue> extends FaweChunk<T>
@Override
public int getBitMask() {
int bitMask = 0;
for (int section = 0; section < ids.length; section++) {
if (ids[section] != null) {
for (int section = 0; section < setBlocks.length; section++) {
if (setBlocks[section] != null) {
bitMask += 1 << section;
}
}
@ -119,12 +117,12 @@ public abstract class IntFaweChunk<T, V extends FaweQueue> extends FaweChunk<T>
*/
@Override
public int[] getIdArray(final int i) {
return this.ids[i];
return this.setBlocks[i];
}
@Override
public int[][] getCombinedIdArrays() {
return this.ids;
return this.setBlocks;
}
@Override
@ -193,18 +191,37 @@ public abstract class IntFaweChunk<T, V extends FaweQueue> extends FaweChunk<T>
@Override
public void setBlock(int x, int y, int z, int combinedId) {
final int i = y >> 4;
int[] vs = this.ids[i];
int[] vs = this.setBlocks[i];
if (vs == null) {
vs = this.ids[i] = new int[4096];
vs = this.setBlocks[i] = new int[4096];
}
vs[(((y & 15) << 8) | (z << 4) | x)] = combinedId;
this.count[i]++;
switch (combinedId) {
int index = (((y & 15) << 8) | (z << 4) | x);
int existing = vs[index];
vs[index] = combinedId;
switch (existing) {
case 0:
this.count[i]++;
switch (combinedId) {
case 0:
case BlockID.AIR:
case BlockID.CAVE_AIR:
case BlockID.VOID_AIR:
this.air[i]++;
}
break;
case BlockID.AIR:
case BlockID.CAVE_AIR:
case BlockID.VOID_AIR:
this.air[i]++;
switch (combinedId) {
case 0:
case BlockID.AIR:
case BlockID.CAVE_AIR:
case BlockID.VOID_AIR:
break;
default:
this.air[i]--;
}
}
return;
}

View File

@ -21,9 +21,9 @@ public class NullQueueIntFaweChunk extends IntFaweChunk {
@Override
public IntFaweChunk copy(boolean shallow) {
if (shallow) {
return new NullQueueIntFaweChunk(getX(), getZ(), ids, count, air);
return new NullQueueIntFaweChunk(getX(), getZ(), setBlocks, count, air);
} else {
return new NullQueueIntFaweChunk(getX(), getZ(), (int[][]) MainUtil.copyNd(ids), count.clone(), air.clone());
return new NullQueueIntFaweChunk(getX(), getZ(), (int[][]) MainUtil.copyNd(setBlocks), count.clone(), air.clone());
}
}

View File

@ -23,10 +23,10 @@ public class SimpleIntFaweChunk extends IntFaweChunk {
public IntFaweChunk copy(boolean shallow) {
SimpleIntFaweChunk copy;
if (shallow) {
copy = new SimpleIntFaweChunk(getParent(), getX(), getZ(), ids, count, air);
copy = new SimpleIntFaweChunk(getParent(), getX(), getZ(), setBlocks, count, air);
copy.biomes = biomes;
} else {
copy = new SimpleIntFaweChunk(getParent(), getX(), getZ(), (int[][]) MainUtil.copyNd(ids), count.clone(), air.clone());
copy = new SimpleIntFaweChunk(getParent(), getX(), getZ(), (int[][]) MainUtil.copyNd(setBlocks), count.clone(), air.clone());
copy.biomes = biomes != null ? biomes.clone() : null;
}
return copy;

View File

@ -302,10 +302,16 @@ public abstract class FaweChangeSet implements ChangeSet {
switch (combinedIdCurrent) {
case 0:
continue;
case 1:
combinedIdCurrent = 0;
default:
int combinedIdPrevious = previousLayer != null ? previousLayer[index] : BlockID.AIR;
int combinedIdPrevious;
if (previousLayer != null) {
combinedIdPrevious = previousLayer[index];
if (combinedIdPrevious == 0) {
combinedIdPrevious = BlockID.AIR;
}
} else {
combinedIdPrevious = BlockID.AIR;
}
if (combinedIdCurrent != combinedIdPrevious) {
add(xx, yy, zz, combinedIdPrevious, combinedIdCurrent);
}

View File

@ -0,0 +1,233 @@
package com.boydti.fawe.object.collection;
import javax.annotation.Nonnull;
import java.util.Arrays;
import static it.unimi.dsi.fastutil.HashCommon.arraySize;
public class ObjObjMap<K, V>
{
private static final Object FREE_KEY = new Object();
private static final Object REMOVED_KEY = new Object();
/** Keys and values */
private Object[] m_data;
/** Value for the null key (if inserted into a map) */
private Object m_nullValue;
private boolean m_hasNull;
/** Fill factor, must be between (0 and 1) */
private final float m_fillFactor;
/** We will resize a map once it reaches this size */
private int m_threshold;
/** Current map size */
private int m_size;
/** Mask to calculate the original position */
private int m_mask;
/** Mask to wrap the actual array pointer */
private int m_mask2;
public ObjObjMap( final int size, final float fillFactor )
{
if ( fillFactor <= 0 || fillFactor >= 1 )
throw new IllegalArgumentException( "FillFactor must be in (0, 1)" );
if ( size <= 0 )
throw new IllegalArgumentException( "Size must be positive!" );
final int capacity = arraySize(size, fillFactor);
m_mask = capacity - 1;
m_mask2 = capacity * 2 - 1;
m_fillFactor = fillFactor;
m_data = new Object[capacity * 2];
Arrays.fill( m_data, FREE_KEY );
m_threshold = (int) (capacity * fillFactor);
}
public V get( @Nonnull final K key )
{
// if ( key == null )
// return (V) m_nullValue; //we null it on remove, so safe not to check a flag here
int ptr = (key.hashCode() & m_mask) << 1;
Object k = m_data[ ptr ];
// if ( k == FREE_KEY )
// return null; //end of chain already
if ( k == ( key ) ) //we check FREE and REMOVED prior to this call
return (V) m_data[ ptr + 1 ];
while ( true )
{
ptr = (ptr + 2) & m_mask2; //that's next index
k = m_data[ ptr ];
// if ( k == FREE_KEY )
// return null;
if ( k == ( key ) )
return (V) m_data[ ptr + 1 ];
}
}
public V put( final K key, final V value )
{
if ( key == null )
return insertNullKey(value);
int ptr = getStartIndex(key) << 1;
Object k = m_data[ptr];
if ( k == FREE_KEY ) //end of chain already
{
m_data[ ptr ] = key;
m_data[ ptr + 1 ] = value;
if ( m_size >= m_threshold )
rehash( m_data.length * 2 ); //size is set inside
else
++m_size;
return null;
}
else if ( k == ( key ) ) //we check FREE and REMOVED prior to this call
{
final Object ret = m_data[ ptr + 1 ];
m_data[ ptr + 1 ] = value;
return (V) ret;
}
int firstRemoved = -1;
if ( k == REMOVED_KEY )
firstRemoved = ptr; //we may find a key later
while ( true )
{
ptr = ( ptr + 2 ) & m_mask2; //that's next index calculation
k = m_data[ ptr ];
if ( k == FREE_KEY )
{
if ( firstRemoved != -1 )
ptr = firstRemoved;
m_data[ ptr ] = key;
m_data[ ptr + 1 ] = value;
if ( m_size >= m_threshold )
rehash( m_data.length * 2 ); //size is set inside
else
++m_size;
return null;
}
else if ( k == ( key ) )
{
final Object ret = m_data[ ptr + 1 ];
m_data[ ptr + 1 ] = value;
return (V) ret;
}
else if ( k == REMOVED_KEY )
{
if ( firstRemoved == -1 )
firstRemoved = ptr;
}
}
}
public V remove( final K key )
{
if ( key == null )
return removeNullKey();
int ptr = getStartIndex(key) << 1;
Object k = m_data[ ptr ];
if ( k == FREE_KEY )
return null; //end of chain already
else if ( k == ( key ) ) //we check FREE and REMOVED prior to this call
{
--m_size;
if ( m_data[ ( ptr + 2 ) & m_mask2 ] == FREE_KEY )
m_data[ ptr ] = FREE_KEY;
else
m_data[ ptr ] = REMOVED_KEY;
final V ret = (V) m_data[ ptr + 1 ];
m_data[ ptr + 1 ] = null;
return ret;
}
while ( true )
{
ptr = ( ptr + 2 ) & m_mask2; //that's next index calculation
k = m_data[ ptr ];
if ( k == FREE_KEY )
return null;
else if ( k == ( key ) )
{
--m_size;
if ( m_data[ ( ptr + 2 ) & m_mask2 ] == FREE_KEY )
m_data[ ptr ] = FREE_KEY;
else
m_data[ ptr ] = REMOVED_KEY;
final V ret = (V) m_data[ ptr + 1 ];
m_data[ ptr + 1 ] = null;
return ret;
}
}
}
private V insertNullKey(final V value)
{
if ( m_hasNull )
{
final Object ret = m_nullValue;
m_nullValue = value;
return (V) ret;
}
else
{
m_nullValue = value;
++m_size;
return null;
}
}
private V removeNullKey()
{
if ( m_hasNull )
{
final Object ret = m_nullValue;
m_nullValue = null;
m_hasNull = false;
--m_size;
return (V) ret;
}
else
{
return null;
}
}
public int size()
{
return m_size;
}
private void rehash( final int newCapacity )
{
m_threshold = (int) (newCapacity/2 * m_fillFactor);
m_mask = newCapacity/2 - 1;
m_mask2 = newCapacity - 1;
final int oldCapacity = m_data.length;
final Object[] oldData = m_data;
m_data = new Object[ newCapacity ];
Arrays.fill( m_data, FREE_KEY );
m_size = m_hasNull ? 1 : 0;
for ( int i = 0; i < oldCapacity; i += 2 ) {
final Object oldKey = oldData[ i ];
if( oldKey != FREE_KEY && oldKey != REMOVED_KEY )
put( (K)oldKey, (V)oldData[ i + 1 ]);
}
}
public int getStartIndex( final Object key )
{
//key is not null here
return key.hashCode() & m_mask;
}
}

View File

@ -2484,6 +2484,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public int makeSphere(final BlockVector3 pos, final Pattern block, double radiusX, double radiusY, double radiusZ, final boolean filled) {
System.out.println("Make sphere");
radiusX += 0.5;
radiusY += 0.5;
radiusZ += 0.5;
@ -2500,35 +2501,37 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
final int ceilRadiusY = (int) Math.ceil(radiusY);
final int ceilRadiusZ = (int) Math.ceil(radiusZ);
double nextXn = 0;
double dx, dy, dz, dxy, dxyz;
double nextXn = invRadiusX;
double dx, dy, dz, dxz, dxyz;
forX:
for (int x = 0; x <= ceilRadiusX; ++x) {
final double xn = nextXn;
dx = xn * xn;
nextXn = (x + 1) * invRadiusX;
double nextYn = 0;
forY:
for (int y = 0; y <= ceilRadiusY; ++y) {
final double yn = nextYn;
dy = yn * yn;
dxy = dx + dy;
nextYn = (y + 1) * invRadiusY;
double nextZn = 0;
forZ:
for (int z = 0; z <= ceilRadiusZ; ++z) {
final double zn = nextZn;
dz = zn * zn;
dxyz = dxy + dz;
nextZn = (z + 1) * invRadiusZ;
double nextZn = invRadiusZ;
forZ:
for (int z = 0; z <= ceilRadiusZ; ++z) {
final double zn = nextZn;
dz = zn * zn;
dxz = dx + dz;
nextZn = (z + 1) * invRadiusZ;
double nextYn = invRadiusY;
forY:
for (int y = 0; y <= ceilRadiusY; ++y) {
final double yn = nextYn;
dy = yn * yn;
dxyz = dxz + dy;
nextYn = (y + 1) * invRadiusY;
if (dxyz > 1) {
if (z == 0) {
if (y == 0) {
if (y == 0) {
if (z == 0) {
break forX;
}
break forY;
break forZ;
}
break forZ;
break forY;
}
if (!filled) {
@ -2538,13 +2541,19 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
}
this.setBlock(px + x, py + y, pz + z, block);
this.setBlock(px - x, py + y, pz + z, block);
this.setBlock(px + x, py - y, pz + z, block);
this.setBlock(px + x, py + y, pz - z, block);
this.setBlock(px - x, py - y, pz + z, block);
this.setBlock(px + x, py - y, pz - z, block);
this.setBlock(px - x, py + y, pz - z, block);
this.setBlock(px - x, py - y, pz - z, block);
if (x != 0) this.setBlock(px - x, py + y, pz + z, block);
if (z != 0) {
this.setBlock(px + x, py + y, pz - z, block);
if (x != 0) this.setBlock(px - x, py + y, pz - z, block);
}
if (y != 0) {
this.setBlock(px + x, py - y, pz + z, block);
if (x != 0) this.setBlock(px - x, py - y, pz + z, block);
if (z != 0) {
this.setBlock(px + x, py - y, pz - z, block);
if (x != 0) this.setBlock(px - x, py - y, pz - z, block);
}
}
}
}
}