Add ZeroCollidingReferenceStateTable for StateHolder property operations
This patch optimises property updating optimisations for StateHolder operations.98ae59d859Additionally, implement some basic optimisations to some BlockPos operations.9c4490bda4
This commit is contained in:
@@ -86,10 +86,11 @@ public abstract class SimpleBitStorageMixin implements BitStorage {
|
||||
final long[] dataArray = this.data;
|
||||
|
||||
final long data = dataArray[dataIndex];
|
||||
final int valuesPerLong = this.valuesPerLong;
|
||||
final long mask = (1L << bits) - 1; // avoid extra memory read
|
||||
|
||||
|
||||
final int bitIndex = (index - (dataIndex * this.valuesPerLong)) * bits;
|
||||
final int bitIndex = (index - (dataIndex * valuesPerLong)) * bits;
|
||||
final int prev = (int)(data >> bitIndex & mask);
|
||||
final long write = data & ~(mask << bitIndex) | ((long)value & mask) << bitIndex;
|
||||
|
||||
@@ -116,9 +117,10 @@ public abstract class SimpleBitStorageMixin implements BitStorage {
|
||||
final long[] dataArray = this.data;
|
||||
|
||||
final long data = dataArray[dataIndex];
|
||||
final int valuesPerLong = this.valuesPerLong;
|
||||
final long mask = (1L << bits) - 1; // avoid extra memory read
|
||||
|
||||
final int bitIndex = (index - (dataIndex * this.valuesPerLong)) * bits;
|
||||
final int bitIndex = (index - (dataIndex * valuesPerLong)) * bits;
|
||||
final long write = data & ~(mask << bitIndex) | ((long)value & mask) << bitIndex;
|
||||
|
||||
LONG_ARRAY_HANDLE.setOpaque(dataArray, dataIndex, write);
|
||||
@@ -140,8 +142,9 @@ public abstract class SimpleBitStorageMixin implements BitStorage {
|
||||
|
||||
final long mask = (1L << bits) - 1; // avoid extra memory read
|
||||
final long data = (long)LONG_ARRAY_HANDLE.getOpaque(this.data, dataIndex);
|
||||
final int valuesPerLong = this.valuesPerLong;
|
||||
|
||||
final int bitIndex = (index - (dataIndex * this.valuesPerLong)) * bits;
|
||||
final int bitIndex = (index - (dataIndex * valuesPerLong)) * bits;
|
||||
|
||||
return (int)(data >> bitIndex & mask);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package ca.spottedleaf.moonrise.mixin.blockstate_propertyaccess;
|
||||
|
||||
import ca.spottedleaf.moonrise.patches.blockstate_propertyaccess.PropertyAccess;
|
||||
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
|
||||
@Mixin(BooleanProperty.class)
|
||||
public abstract class BooleanPropertyMixin extends Property<Boolean> implements PropertyAccess<Boolean> {
|
||||
protected BooleanPropertyMixin(String string, Class<Boolean> class_) {
|
||||
super(string, class_);
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Properties are identity comparable
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
return this == obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getIdFor(final Boolean value) {
|
||||
return value.booleanValue() ? 1 : 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package ca.spottedleaf.moonrise.mixin.blockstate_propertyaccess;
|
||||
|
||||
import ca.spottedleaf.moonrise.patches.blockstate_propertyaccess.PropertyAccess;
|
||||
import net.minecraft.util.StringRepresentable;
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(EnumProperty.class)
|
||||
public abstract class EnumPropertyMixin<T extends Enum<T> & StringRepresentable> extends Property<T> implements PropertyAccess<T> {
|
||||
|
||||
@Unique
|
||||
private int[] idLookupTable;
|
||||
|
||||
protected EnumPropertyMixin(String string, Class<T> class_) {
|
||||
super(string, class_);
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Hook into constructor to init fields
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Inject(
|
||||
method = "<init>",
|
||||
at = @At(
|
||||
value = "RETURN"
|
||||
)
|
||||
)
|
||||
private void init(final CallbackInfo ci) {
|
||||
int id = 0;
|
||||
this.idLookupTable = new int[getValueClass().getEnumConstants().length];
|
||||
java.util.Arrays.fill(this.idLookupTable, -1);
|
||||
for (final T value : this.getPossibleValues()) {
|
||||
this.idLookupTable[value.ordinal()] = id++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Properties are identity comparable
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
return this == obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getIdFor(final T value) {
|
||||
return this.idLookupTable[value.ordinal()];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package ca.spottedleaf.moonrise.mixin.blockstate_propertyaccess;
|
||||
|
||||
import ca.spottedleaf.moonrise.patches.blockstate_propertyaccess.PropertyAccess;
|
||||
import net.minecraft.world.level.block.state.properties.IntegerProperty;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
@Mixin(IntegerProperty.class)
|
||||
public abstract class IntegerPropertyMixin extends Property<Integer> implements PropertyAccess<Integer> {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private int min;
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private int max;
|
||||
|
||||
protected IntegerPropertyMixin(String string, Class<Integer> class_) {
|
||||
super(string, class_);
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Properties are identity comparable
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
return this == obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getIdFor(final Integer value) {
|
||||
final int val = value.intValue();
|
||||
final int ret = val - this.min;
|
||||
|
||||
return ret | ((this.max - ret) >> 31);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package ca.spottedleaf.moonrise.mixin.blockstate_propertyaccess;
|
||||
|
||||
import ca.spottedleaf.moonrise.patches.blockstate_propertyaccess.PropertyAccess;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@Mixin(Property.class)
|
||||
public abstract class PropertyMixin<T extends Comparable<T>> implements PropertyAccess<T> {
|
||||
|
||||
@Unique
|
||||
private static final AtomicInteger ID_GENERATOR = new AtomicInteger();
|
||||
|
||||
@Unique
|
||||
private int id;
|
||||
|
||||
/**
|
||||
* @reason Hook into constructor to init fields
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Inject(
|
||||
method = "<init>",
|
||||
at = @At(
|
||||
value = "RETURN"
|
||||
)
|
||||
)
|
||||
private void initId(final CallbackInfo ci) {
|
||||
this.id = ID_GENERATOR.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Properties are identity comparable
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
return this == obj;
|
||||
}
|
||||
|
||||
// this is re-declared here so that calls to Property#getIdFor are a virtual method invoke, rather than an interface invoke
|
||||
@Override
|
||||
public abstract int getIdFor(final T value);
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package ca.spottedleaf.moonrise.mixin.blockstate_propertyaccess;
|
||||
|
||||
import ca.spottedleaf.moonrise.patches.blockstate_propertyaccess.util.ZeroCollidingReferenceStateTable;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Table;
|
||||
import net.minecraft.world.level.block.state.StateHolder;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(StateHolder.class)
|
||||
public abstract class StateHolderMixin<O, S> {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private ImmutableMap<Property<?>, Comparable<?>> values;
|
||||
|
||||
@Shadow
|
||||
private Table<Property<?>, Comparable<?>, S> neighbours;
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
protected O owner;
|
||||
|
||||
|
||||
@Unique
|
||||
protected ZeroCollidingReferenceStateTable optimisedTable;
|
||||
|
||||
/**
|
||||
* @reason Hook into constructor to init fields
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Inject(
|
||||
method = "<init>",
|
||||
at = @At(
|
||||
value = "RETURN"
|
||||
)
|
||||
)
|
||||
private void init(final CallbackInfo ci) {
|
||||
this.optimisedTable = new ZeroCollidingReferenceStateTable((StateHolder<O, S>)(Object)this, this.values); // Paper - optimise state lookup
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Init table for ZCST
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Inject(
|
||||
method = "populateNeighbours",
|
||||
at = @At(
|
||||
value = "RETURN"
|
||||
)
|
||||
)
|
||||
private void loadTable(final Map<Map<Property<?>, Comparable<?>>, S> map, final CallbackInfo ci) {
|
||||
this.optimisedTable.loadInTable((Table<Property<?>, Comparable<?>, StateHolder<?,?>>)this.neighbours, this.values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Replace with optimisedTable
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public <T extends Comparable<T>, V extends T> S setValue(final Property<T> property, final V value) {
|
||||
final S ret = (S)this.optimisedTable.get(property, value);
|
||||
if (ret == null) {
|
||||
throw new IllegalArgumentException("Cannot set property " + property + " to " + value + " on " + this.owner + ", it is not an allowed value");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Replace with optimisedTable
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public <T extends Comparable<T>> Optional<T> getOptionalValue(final Property<T> property) {
|
||||
final Comparable<?> ret = this.optimisedTable.get(property);
|
||||
return ret == null ? Optional.empty() : Optional.of((T)ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Replace with optimisedTable
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public <T extends Comparable<T>> T getValue(final Property<T> property) {
|
||||
final Comparable<?> ret = this.optimisedTable.get(property);
|
||||
if (ret == null) {
|
||||
throw new IllegalArgumentException("Cannot get property " + property + " as it does not exist in " + this.owner);
|
||||
} else {
|
||||
return (T)ret;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Replace with optimisedTable
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public <T extends Comparable<T>> boolean hasProperty(final Property<T> property) {
|
||||
return this.optimisedTable.get(property) != null; // Paper - optimise state lookup
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package ca.spottedleaf.moonrise.mixin.collisions;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
|
||||
@Mixin(BlockPos.class)
|
||||
public abstract class BlockPosMixin extends Vec3i {
|
||||
|
||||
public BlockPosMixin(int i, int j, int k) {
|
||||
super(i, j, k);
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason https://bugs.mojang.com/browse/MC-136025
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
@Override
|
||||
public BlockPos above() {
|
||||
return new BlockPos(this.getX(), this.getY() + 1, this.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason https://bugs.mojang.com/browse/MC-136025
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
@Override
|
||||
public BlockPos above(final int distance) {
|
||||
return distance == 0 ? (BlockPos)(Object)this : new BlockPos(this.getX(), this.getY() + distance, this.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason https://bugs.mojang.com/browse/MC-136025
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
@Override
|
||||
public BlockPos below() {
|
||||
return new BlockPos(this.getX(), this.getY() - 1, this.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason https://bugs.mojang.com/browse/MC-136025
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
@Override
|
||||
public BlockPos below(final int distance) {
|
||||
return distance == 0 ? (BlockPos)(Object)this : new BlockPos(this.getX(), this.getY() - distance, this.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason https://bugs.mojang.com/browse/MC-136025
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
@Override
|
||||
public BlockPos north() {
|
||||
return new BlockPos(this.getX(), this.getY(), this.getZ() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason https://bugs.mojang.com/browse/MC-136025
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
@Override
|
||||
public BlockPos north(final int distance) {
|
||||
return distance == 0 ? (BlockPos)(Object)this : new BlockPos(this.getX(), this.getY(), this.getZ() - distance);
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason https://bugs.mojang.com/browse/MC-136025
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
@Override
|
||||
public BlockPos south() {
|
||||
return new BlockPos(this.getX(), this.getY(), this.getZ() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason https://bugs.mojang.com/browse/MC-136025
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
@Override
|
||||
public BlockPos south(final int distance) {
|
||||
return distance == 0 ? (BlockPos)(Object)this : new BlockPos(this.getX(), this.getY(), this.getZ() + distance);
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason https://bugs.mojang.com/browse/MC-136025
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
@Override
|
||||
public BlockPos west() {
|
||||
return new BlockPos(this.getX() - 1, this.getY(), this.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason https://bugs.mojang.com/browse/MC-136025
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
@Override
|
||||
public BlockPos west(final int distance) {
|
||||
return distance == 0 ? (BlockPos)(Object)this : new BlockPos(this.getX() - distance, this.getY(), this.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason https://bugs.mojang.com/browse/MC-136025
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
@Override
|
||||
public BlockPos east() {
|
||||
return new BlockPos(this.getX() + 1, this.getY(), this.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason https://bugs.mojang.com/browse/MC-136025
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
@Override
|
||||
public BlockPos east(final int distance) {
|
||||
return distance == 0 ? (BlockPos)(Object)this : new BlockPos(this.getX() + distance, this.getY(), this.getZ());
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_getblock.GetBlockChunk;
|
||||
import ca.spottedleaf.moonrise.patches.collisions.CollisionUtil;
|
||||
import ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState;
|
||||
import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape;
|
||||
import ca.spottedleaf.moonrise.patches.explosions.ExplosionBlockCache;
|
||||
import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
@@ -357,12 +356,18 @@ public abstract class ExplosionMixin {
|
||||
this.chunkCache = new LevelChunk[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
|
||||
|
||||
ExplosionBlockCache[] blockCache = new ExplosionBlockCache[BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH];
|
||||
// avoid checking for initial state in loop by always defaulting to a position that will fail the first cache check
|
||||
ExplosionBlockCache initialCache = new ExplosionBlockCache(
|
||||
BlockPos.containing(this.x, this.y, this.z).above(2).asLong(),
|
||||
null, null, null, 0f, true
|
||||
);
|
||||
ExplosionBlockCache cachedBlock;
|
||||
|
||||
// use initial cache value that is most likely to be used: the source position
|
||||
final ExplosionBlockCache initialCache;
|
||||
{
|
||||
final int blockX = Mth.floor(this.x);
|
||||
final int blockY = Mth.floor(this.y);
|
||||
final int blockZ = Mth.floor(this.z);
|
||||
|
||||
final long key = BlockPos.asLong(blockX, blockY, blockZ);
|
||||
|
||||
initialCache = this.getOrCacheExplosionBlock(blockX, blockY, blockZ, key, true);
|
||||
}
|
||||
|
||||
// only ~1/3rd of the loop iterations in vanilla will result in a ray, as it is iterating the perimeter of
|
||||
// a 16x16x16 cube
|
||||
@@ -371,24 +376,24 @@ public abstract class ExplosionMixin {
|
||||
// additional aggressive caching of block retrieval is very significant, as at low power (i.e tnt) most
|
||||
// block retrievals are not unique
|
||||
for (int ray = 0, len = CACHED_RAYS.length; ray < len;) {
|
||||
cachedBlock = initialCache;
|
||||
ExplosionBlockCache cachedBlock = initialCache;
|
||||
|
||||
double currX = this.x;
|
||||
double currY = this.y;
|
||||
double currZ = this.z;
|
||||
|
||||
double incX = CACHED_RAYS[ray];
|
||||
double incY = CACHED_RAYS[ray + 1];
|
||||
double incZ = CACHED_RAYS[ray + 2];
|
||||
final double incX = CACHED_RAYS[ray];
|
||||
final double incY = CACHED_RAYS[ray + 1];
|
||||
final double incZ = CACHED_RAYS[ray + 2];
|
||||
|
||||
ray += 3;
|
||||
|
||||
float power = this.radius * (0.7F + this.level.random.nextFloat() * 0.6F);
|
||||
|
||||
do {
|
||||
int blockX = Mth.floor(currX);
|
||||
int blockY = Mth.floor(currY);
|
||||
int blockZ = Mth.floor(currZ);
|
||||
final int blockX = Mth.floor(currX);
|
||||
final int blockY = Mth.floor(currY);
|
||||
final int blockZ = Mth.floor(currZ);
|
||||
|
||||
final long key = BlockPos.asLong(blockX, blockY, blockZ);
|
||||
|
||||
@@ -432,13 +437,13 @@ public abstract class ExplosionMixin {
|
||||
// use null predicate to avoid indirection on test(), but we need to move the spectator check into the loop itself
|
||||
final List<Entity> entities = this.level.getEntities(this.source,
|
||||
new AABB(
|
||||
Mth.floor(this.x - (diameter + 1.0)),
|
||||
Mth.floor(this.y - (diameter + 1.0)),
|
||||
Mth.floor(this.z - (diameter + 1.0)),
|
||||
(double)Mth.floor(this.x - (diameter + 1.0)),
|
||||
(double)Mth.floor(this.y - (diameter + 1.0)),
|
||||
(double)Mth.floor(this.z - (diameter + 1.0)),
|
||||
|
||||
Mth.floor(this.x + (diameter + 1.0)),
|
||||
Mth.floor(this.y + (diameter + 1.0)),
|
||||
Mth.floor(this.z + (diameter + 1.0))
|
||||
(double)Mth.floor(this.x + (diameter + 1.0)),
|
||||
(double)Mth.floor(this.y + (diameter + 1.0)),
|
||||
(double)Mth.floor(this.z + (diameter + 1.0))
|
||||
),
|
||||
null
|
||||
);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package ca.spottedleaf.moonrise.patches.blockstate_propertyaccess;
|
||||
|
||||
public interface PropertyAccess<T> {
|
||||
|
||||
public int getId();
|
||||
|
||||
public int getIdFor(final T value);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
package ca.spottedleaf.moonrise.patches.blockstate_propertyaccess.util;
|
||||
|
||||
import ca.spottedleaf.moonrise.patches.blockstate_propertyaccess.PropertyAccess;
|
||||
import com.google.common.collect.Table;
|
||||
import net.minecraft.world.level.block.state.StateHolder;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public final class ZeroCollidingReferenceStateTable {
|
||||
|
||||
// upper 32 bits: starting index
|
||||
// lower 32 bits: bitset for contained ids
|
||||
protected final long[] this_index_table;
|
||||
protected final Comparable<?>[] this_table;
|
||||
protected final StateHolder<?, ?> this_state;
|
||||
|
||||
protected long[] index_table;
|
||||
protected StateHolder<?, ?>[][] value_table;
|
||||
|
||||
private boolean inited;
|
||||
|
||||
public ZeroCollidingReferenceStateTable(final StateHolder<?, ?> state, final Map<Property<?>, Comparable<?>> this_map) {
|
||||
this.this_state = state;
|
||||
this.this_index_table = this.create_table(this_map.keySet());
|
||||
|
||||
int max_id = -1;
|
||||
for (final Property<?> property : this_map.keySet()) {
|
||||
final int id = lookup_vindex(property, this.this_index_table);
|
||||
if (id > max_id) {
|
||||
max_id = id;
|
||||
}
|
||||
}
|
||||
|
||||
this.this_table = new Comparable[max_id + 1];
|
||||
for (final Map.Entry<Property<?>, Comparable<?>> entry : this_map.entrySet()) {
|
||||
this.this_table[lookup_vindex(entry.getKey(), this.this_index_table)] = entry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
public void loadInTable(final Table<Property<?>, Comparable<?>, StateHolder<?, ?>> table,
|
||||
final Map<Property<?>, Comparable<?>> this_map) {
|
||||
if (this.inited) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
this.inited = true;
|
||||
final Set<Property<?>> combined = new HashSet<>(table.rowKeySet());
|
||||
combined.addAll(this_map.keySet());
|
||||
|
||||
this.index_table = this.create_table(combined);
|
||||
|
||||
int max_id = -1;
|
||||
for (final Property<?> property : combined) {
|
||||
final int id = lookup_vindex(property, this.index_table);
|
||||
if (id > max_id) {
|
||||
max_id = id;
|
||||
}
|
||||
}
|
||||
|
||||
this.value_table = new StateHolder[max_id + 1][];
|
||||
|
||||
final Map<Property<?>, Map<Comparable<?>, StateHolder<?, ?>>> map = table.rowMap();
|
||||
for (final Property<?> property : map.keySet()) {
|
||||
final Map<Comparable<?>, StateHolder<?, ?>> propertyMap = map.get(property);
|
||||
|
||||
final int id = lookup_vindex(property, this.index_table);
|
||||
final StateHolder<?, ?>[] states = this.value_table[id] = new StateHolder[property.getPossibleValues().size()];
|
||||
|
||||
for (final Map.Entry<Comparable<?>, StateHolder<?, ?>> entry : propertyMap.entrySet()) {
|
||||
if (entry.getValue() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
states[((PropertyAccess)property).getIdFor(entry.getKey())] = entry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (final Map.Entry<Property<?>, Comparable<?>> entry : this_map.entrySet()) {
|
||||
final Property<?> property = entry.getKey();
|
||||
final int index = lookup_vindex(property, this.index_table);
|
||||
|
||||
if (this.value_table[index] == null) {
|
||||
this.value_table[index] = new StateHolder[property.getPossibleValues().size()];
|
||||
}
|
||||
|
||||
this.value_table[index][((PropertyAccess)property).getIdFor(entry.getValue())] = this.this_state;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected long[] create_table(final Collection<Property<?>> collection) {
|
||||
int max_id = -1;
|
||||
for (final Property<?> property : collection) {
|
||||
final int id = ((PropertyAccess)property).getId();
|
||||
if (id > max_id) {
|
||||
max_id = id;
|
||||
}
|
||||
}
|
||||
|
||||
final long[] ret = new long[((max_id + 1) + 31) >>> 5]; // ceil((max_id + 1) / 32)
|
||||
|
||||
for (final Property<?> property : collection) {
|
||||
final int id = ((PropertyAccess)property).getId();
|
||||
|
||||
ret[id >>> 5] |= (1L << (id & 31));
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
for (int i = 1, len = ret.length; i < len; ++i) {
|
||||
ret[i] |= (long)(total += Long.bitCount(ret[i - 1] & 0xFFFFFFFFL)) << 32;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Comparable<?> get(final Property<?> state) {
|
||||
final Comparable<?>[] table = this.this_table;
|
||||
final int index = lookup_vindex(state, this.this_index_table);
|
||||
|
||||
if (index < 0 || index >= table.length) {
|
||||
return null;
|
||||
}
|
||||
return table[index];
|
||||
}
|
||||
|
||||
public StateHolder<?, ?> get(final Property<?> property, final Comparable<?> with) {
|
||||
final int index = lookup_vindex(property, this.index_table);
|
||||
final StateHolder<?, ?>[][] table = this.value_table;
|
||||
if (index < 0 || index >= table.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final StateHolder<?, ?>[] values = table[index];
|
||||
|
||||
final int withId = ((PropertyAccess)property).getIdFor(with);
|
||||
if (withId < 0 || withId >= values.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return values[withId];
|
||||
}
|
||||
|
||||
protected static int lookup_vindex(final Property<?> property, final long[] index_table) {
|
||||
final int id = ((PropertyAccess)property).getId();
|
||||
final long bitset_mask = (1L << (id & 31));
|
||||
final long lower_mask = bitset_mask - 1;
|
||||
final int index = id >>> 5;
|
||||
if (index >= index_table.length) {
|
||||
return -1;
|
||||
}
|
||||
final long index_value = index_table[index];
|
||||
final long contains_check = ((index_value & bitset_mask) - 1) >> (Long.SIZE - 1); // -1L if doesn't contain
|
||||
|
||||
// index = total bits set in lower table values (upper 32 bits of index_value) plus total bits set in lower indices below id
|
||||
// contains_check is 0 if the bitset had id set, else it's -1: so index is unaffected if contains_check == 0,
|
||||
// otherwise it comes out as -1.
|
||||
return (int)(((index_value >>> 32) + Long.bitCount(index_value & lower_mask)) | contains_check);
|
||||
}
|
||||
}
|
||||
@@ -6,12 +6,18 @@
|
||||
"mixins": [
|
||||
"bitstorage.SimpleBitStorageMixin",
|
||||
"bitstorage.ZeroBitStorageMixin",
|
||||
"blockstate_propertyaccess.BooleanPropertyMixin",
|
||||
"blockstate_propertyaccess.EnumPropertyMixin",
|
||||
"blockstate_propertyaccess.IntegerPropertyMixin",
|
||||
"blockstate_propertyaccess.PropertyMixin",
|
||||
"blockstate_propertyaccess.StateHolderMixin",
|
||||
"chunk_getblock.ChunkAccessMixin",
|
||||
"chunk_getblock.LevelChunkMixin",
|
||||
"collisions.ArmorStandMixin",
|
||||
"collisions.ArrayVoxelShapeMixin",
|
||||
"collisions.BitSetDiscreteVoxelShapeMixin",
|
||||
"collisions.BlockMixin",
|
||||
"collisions.BlockPosMixin",
|
||||
"collisions.BlockStateBaseMixin",
|
||||
"collisions.CubeVoxelShapeMixin",
|
||||
"collisions.DirectionMixin",
|
||||
|
||||
Reference in New Issue
Block a user