Skip to content

Commit

Permalink
Avoid creating SliceShape when retrieving Voxelshape faces
Browse files Browse the repository at this point in the history
SliceShape is not always the ideal shape, as sometimes the
face result is empty or full cube - but is represented as
SliceShape. Additionally, sometimes SliceShape should be
empty but isEmpty() is false.
  • Loading branch information
Spottedleaf committed Aug 12, 2024
1 parent c0a2e48 commit e68d381
Show file tree
Hide file tree
Showing 10 changed files with 447 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
@Mixin(ClientSuggestionProvider.class)
abstract class ClientSuggestionProviderMixin implements CommandClientCommandSource, FabricClientCommandSource {
@Override
public void moonrise$sendSuccess(final Component message) {
public final void moonrise$sendSuccess(final Component message) {
this.sendFeedback(message);
}

@Override
public void moonrise$sendFailure(final Component message) {
public final void moonrise$sendFailure(final Component message) {
this.sendError(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import ca.spottedleaf.moonrise.common.PlatformHooks;
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
Expand All @@ -15,7 +14,6 @@
import net.minecraft.world.level.EmptyBlockGetter;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ImposterProtoChunk;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ public ClientCommandSourceStackMixin(CommandSource arg, Vec3 arg2, Vec2 arg3, Se
public abstract void sendSuccess(Supplier<Component> message, boolean sendToAdmins);

@Override
public void moonrise$sendFailure(final Component message) {
public final void moonrise$sendFailure(final Component message) {
this.sendFailure(message);
}

@Override
public void moonrise$sendSuccess(final Component message) {
public final void moonrise$sendSuccess(final Component message) {
this.sendSuccess(() -> message, true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
@Mixin(ServerChunkCache.MainThreadExecutor.class)
abstract class ServerChunkCache$MainThreadExecutorMixin extends BlockableEventLoop<Runnable> {

@Shadow(aliases = "this$0")
@Shadow(aliases = "this$0") // Neoforge
@Final
ServerChunkCache field_18810;
ServerChunkCache field_18810; // Fabric

protected ServerChunkCache$MainThreadExecutorMixin(String string) {
super(string);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ abstract class StructureTemplate$PaletteMixin {
value = "RETURN"
)
)
private <K, V> void makeCacheCHM(final CallbackInfo ci) {
private void makeCacheCHM(final CallbackInfo ci) {
this.cache = new ConcurrentHashMap<>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,19 @@ protected BlockStateBaseMixin(Block object, Reference2ObjectArrayMap<Property<?>
private AABB constantAABBCollision;

@Unique
private static void initCaches(final VoxelShape shape) {
private static void initCaches(final VoxelShape shape, final boolean neighbours) {
((CollisionVoxelShape)shape).moonrise$isFullBlock();
((CollisionVoxelShape)shape).moonrise$occludesFullBlock();
shape.toAabbs();
if (!shape.isEmpty()) {
shape.bounds();
}
if (neighbours) {
for (final Direction direction : DIRECTIONS_CACHED) {
initCaches(Shapes.getFaceShape(shape, direction), false);
initCaches(shape.getFaceShape(direction), false);
}
}
}

/**
Expand All @@ -98,17 +104,13 @@ private void initCollisionState(final CallbackInfo ci) {
this.occludesFullBlock = ((CollisionVoxelShape)collisionShape).moonrise$occludesFullBlock();
this.emptyCollisionShape = collisionShape.isEmpty();
// init caches
initCaches(collisionShape);
if (collisionShape != Shapes.empty() && collisionShape != Shapes.block()) {
for (final Direction direction : DIRECTIONS_CACHED) {
// initialise the directional face shape cache as well
final VoxelShape shape = Shapes.getFaceShape(collisionShape, direction);
initCaches(shape);
}
initCaches(collisionShape, true);
if (this.constantCollisionShape != null) {
initCaches(this.constantCollisionShape, true);
}
if (this.cache.occlusionShapes != null) {
for (final VoxelShape shape : this.cache.occlusionShapes) {
initCaches(shape);
initCaches(shape, false);
}
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ abstract class DiscreteVoxelShapeMixin implements CollisionDiscreteVoxelShape {
}
}

final boolean hasSingleAABB = sizeX == 1 && sizeY == 1 && sizeZ == 1 && !isEmpty && discreteVoxelShape.isFull(0, 0, 0);
final boolean hasSingleAABB = sizeX == 1 && sizeY == 1 && sizeZ == 1 && !isEmpty && (voxelSet[0] & 1L) != 0L;

final int minFullX = discreteVoxelShape.firstFull(Direction.Axis.X);
final int minFullY = discreteVoxelShape.firstFull(Direction.Axis.Y);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import net.minecraft.world.phys.shapes.DiscreteVoxelShape;
import net.minecraft.world.phys.shapes.OffsetDoubleList;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.SliceShape;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
Expand Down Expand Up @@ -208,13 +207,13 @@ private static double[] extractRawArray(final DoubleList list) {

if (direction.getAxisDirection() == Direction.AxisDirection.POSITIVE) {
if (DoubleMath.fuzzyEquals(this.max(axis), 1.0, CollisionUtil.COLLISION_EPSILON)) {
ret = tryForceBlock(new SliceShape((VoxelShape)(Object)this, axis, this.shape.getSize(axis) - 1));
ret = CollisionUtil.sliceShape((VoxelShape)(Object)this, axis, this.shape.getSize(axis) - 1);
} else {
ret = Shapes.empty();
}
} else {
if (DoubleMath.fuzzyEquals(this.min(axis), 0.0, CollisionUtil.COLLISION_EPSILON)) {
ret = tryForceBlock(new SliceShape((VoxelShape)(Object)this, axis, 0));
ret = CollisionUtil.sliceShape((VoxelShape)(Object)this, axis, 0);
} else {
ret = Shapes.empty();
}
Expand All @@ -225,24 +224,6 @@ private static double[] extractRawArray(final DoubleList list) {
return ret;
}

@Unique
private static VoxelShape tryForceBlock(final VoxelShape other) {
if (other == Shapes.block()) {
return other;
}

final AABB otherAABB = ((CollisionVoxelShape)other).moonrise$getSingleAABBRepresentation();
if (otherAABB == null) {
return other;
}

if (((CollisionVoxelShape)Shapes.block()).moonrise$getSingleAABBRepresentation().equals(otherAABB)) {
return Shapes.block();
}

return other;
}

@Unique
private boolean computeOccludesFullBlock() {
if (this.isEmpty) {
Expand Down Expand Up @@ -353,6 +334,115 @@ public boolean isEmpty() {
return this.isEmpty;
}

/**
* @author Spottedleaf
* @reason Use cached bounds
*/
@Overwrite
public VoxelShape singleEncompassing() {
if (this.isEmpty) {
return Shapes.empty();
}
return Shapes.create(this.bounds());
}

/**
* @author Spottedleaf
* @reason Optimise implementation to avoid indirection
*/
@Overwrite
protected double get(final Direction.Axis axis, final int idx) {
switch (axis) {
case X: {
return this.rootCoordinatesX[idx] + this.offsetX;
}
case Y: {
return this.rootCoordinatesY[idx] + this.offsetY;
}
case Z: {
return this.rootCoordinatesZ[idx] + this.offsetZ;
}
default: {
throw new IllegalStateException("Unknown axis: " + axis);
}
}
}

/**
* @author Spottedleaf
* @reason Optimise implementation to avoid indirection
*/
@Overwrite
public int findIndex(final Direction.Axis axis, final double value) {
switch (axis) {
case X: {
final double[] values = this.rootCoordinatesX;
return CollisionUtil.findFloor(
values, value - this.offsetX, 0, values.length - 1
);
}
case Y: {
final double[] values = this.rootCoordinatesY;
return CollisionUtil.findFloor(
values, value - this.offsetY, 0, values.length - 1
);
}
case Z: {
final double[] values = this.rootCoordinatesZ;
return CollisionUtil.findFloor(
values, value - this.offsetZ, 0, values.length - 1
);
}
default: {
throw new IllegalStateException("Unknown axis: " + axis);
}
}
}

@Unique
private VoxelShape calculateFaceDirect(final Direction direction, final Direction.Axis axis, final double[] coords, final double offset) {
if (coords.length == 2 &&
DoubleMath.fuzzyEquals(coords[0] + offset, 0.0, CollisionUtil.COLLISION_EPSILON) &&
DoubleMath.fuzzyEquals(coords[1] + offset, 1.0, CollisionUtil.COLLISION_EPSILON)) {
return (VoxelShape)(Object)this;
}

final boolean positiveDir = direction.getAxisDirection() == Direction.AxisDirection.POSITIVE;

// see findIndex
final int index = CollisionUtil.findFloor(
coords, (positiveDir ? (1.0 - CollisionUtil.COLLISION_EPSILON) : (0.0 + CollisionUtil.COLLISION_EPSILON)) - offset,
0, coords.length - 1
);

return CollisionUtil.sliceShape(
(VoxelShape)(Object)this, axis, index
);
}

/**
* @author Spottedleaf
* @reason Avoid creating SliceShape
*/
@Overwrite
public VoxelShape calculateFace(final Direction direction) {
final Direction.Axis axis = direction.getAxis();
switch (axis) {
case X: {
return this.calculateFaceDirect(direction, axis, this.rootCoordinatesX, this.offsetX);
}
case Y: {
return this.calculateFaceDirect(direction, axis, this.rootCoordinatesY, this.offsetY);
}
case Z: {
return this.calculateFaceDirect(direction, axis, this.rootCoordinatesZ, this.offsetZ);
}
default: {
throw new IllegalStateException("Unknown axis: " + axis);
}
}
}

/**
* @author Spottedleaf
* @reason Route to optimized collision method
Expand Down Expand Up @@ -382,11 +472,12 @@ public double collide(final Direction.Axis axis, final AABB source, final double
}

@Unique
private static DoubleList offsetList(final DoubleList src, final double by) {
if (src instanceof OffsetDoubleList offsetDoubleList) {
return new OffsetDoubleList(offsetDoubleList.delegate, by + offsetDoubleList.offset);
private static DoubleList offsetList(final double[] src, final double by) {
final DoubleArrayList wrap = DoubleArrayList.wrap(src);
if (by == 0.0) {
return wrap;
}
return new OffsetDoubleList(src, by);
return new OffsetDoubleList(wrap, by);
}

/**
Expand All @@ -400,10 +491,10 @@ public VoxelShape move(final double x, final double y, final double z) {
}

final ArrayVoxelShape ret = new ArrayVoxelShape(
this.shape,
offsetList(this.getCoords(Direction.Axis.X), x),
offsetList(this.getCoords(Direction.Axis.Y), y),
offsetList(this.getCoords(Direction.Axis.Z), z)
this.shape,
offsetList(this.rootCoordinatesX, this.offsetX + x),
offsetList(this.rootCoordinatesY, this.offsetY + y),
offsetList(this.rootCoordinatesZ, this.offsetZ + z)
);

final CachedToAABBs cachedToAABBs = this.cachedToAABBs;
Expand All @@ -416,10 +507,12 @@ public VoxelShape move(final double x, final double y, final double z) {

@Unique
private List<AABB> toAabbsUncached() {
final List<AABB> ret = new ArrayList<>();
final List<AABB> ret;
if (this.singleAABBRepresentation != null) {
ret = new ArrayList<>(1);
ret.add(this.singleAABBRepresentation);
} else {
ret = new ArrayList<>();
final double[] coordsX = this.rootCoordinatesX;
final double[] coordsY = this.rootCoordinatesY;
final double[] coordsZ = this.rootCoordinatesZ;
Expand Down Expand Up @@ -718,6 +811,11 @@ public VoxelShape optimize() {

final List<AABB> aabbs = this.toAabbs();

if (aabbs.isEmpty()) {
// We are a SliceShape, which does not properly fill isEmpty for every case
return Shapes.empty();
}

if (aabbs.size() == 1) {
final AABB singleAABB = aabbs.get(0);
final VoxelShape ret = Shapes.create(singleAABB);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;

Expand All @@ -29,9 +27,10 @@ interface ServerAddressResolverMixin {
private static InetAddress eliminateRDNS(final String name) throws UnknownHostException {
final InetAddress ret = InetAddress.getByName(name);

if (ret instanceof Inet4Address || ret instanceof Inet6Address) {
final byte[] address = ret.getAddress();
if (address != null) {
// pass name to prevent rDNS
return InetAddress.getByAddress(name, ret.getAddress());
return InetAddress.getByAddress(name, address);
}

return ret;
Expand Down
Loading

0 comments on commit e68d381

Please sign in to comment.