diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/FlatBitsetUtil.java b/src/main/java/ca/spottedleaf/moonrise/common/util/FlatBitsetUtil.java index 24fcd3e..0531f25 100644 --- a/src/main/java/ca/spottedleaf/moonrise/common/util/FlatBitsetUtil.java +++ b/src/main/java/ca/spottedleaf/moonrise/common/util/FlatBitsetUtil.java @@ -79,8 +79,8 @@ public final class FlatBitsetUtil { final int fromBitsetIdx = from >>> LOG2_LONG; final int toBitsetIdx = to >>> LOG2_LONG; - final long keepFirst = ALL_SET >>> ((BITS_PER_LONG - 1) ^ from); - final long keepLast = ALL_SET << to; + final long keepFirst = ~(ALL_SET << from); + final long keepLast = ~(ALL_SET >>> ((BITS_PER_LONG - 1) ^ to)); Objects.checkFromToIndex(fromBitsetIdx, toBitsetIdx, bitset.length); @@ -91,7 +91,7 @@ public final class FlatBitsetUtil { bitset[fromBitsetIdx] &= keepFirst; for (int i = fromBitsetIdx + 1; i < toBitsetIdx; ++i) { - bitset[toBitsetIdx] = 0L; + bitset[i] = 0L; } bitset[toBitsetIdx] &= keepLast; diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/collisions/BitSetDiscreteVoxelShapeMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/collisions/BitSetDiscreteVoxelShapeMixin.java index 2d85b72..6554680 100644 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/collisions/BitSetDiscreteVoxelShapeMixin.java +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/collisions/BitSetDiscreteVoxelShapeMixin.java @@ -8,20 +8,100 @@ import net.minecraft.world.phys.shapes.BitSetDiscreteVoxelShape; import net.minecraft.world.phys.shapes.DiscreteVoxelShape; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Unique; +import java.util.ArrayList; +import java.util.List; @Mixin(BitSetDiscreteVoxelShape.class) public abstract class BitSetDiscreteVoxelShapeMixin extends DiscreteVoxelShape { + @Unique + private static final boolean DEBUG_ALL_BOXES = false; + protected BitSetDiscreteVoxelShapeMixin(int i, int j, int k) { super(i, j, k); } + @Unique + private static void forAllBoxesVanilla(DiscreteVoxelShape discreteVoxelShape, DiscreteVoxelShape.IntLineConsumer intLineConsumer, boolean bl) { + BitSetDiscreteVoxelShape bitSetDiscreteVoxelShape = new BitSetDiscreteVoxelShape(discreteVoxelShape); + + for(int i = 0; i < bitSetDiscreteVoxelShape.getYSize(); ++i) { + for(int j = 0; j < bitSetDiscreteVoxelShape.getXSize(); ++j) { + int k = -1; + + for(int l = 0; l <= bitSetDiscreteVoxelShape.getZSize(); ++l) { + if (bitSetDiscreteVoxelShape.isFullWide(j, i, l)) { + if (bl) { + if (k == -1) { + k = l; + } + } else { + intLineConsumer.consume(j, i, l, j + 1, i + 1, l + 1); + } + } else if (k != -1) { + int m = j; + int n = i; + bitSetDiscreteVoxelShape.clearZStrip(k, l, j, i); + + while(bitSetDiscreteVoxelShape.isZStripFull(k, l, m + 1, i)) { + bitSetDiscreteVoxelShape.clearZStrip(k, l, m + 1, i); + ++m; + } + + while(bitSetDiscreteVoxelShape.isXZRectangleFull(j, m + 1, k, l, n + 1)) { + for(int o = j; o <= m; ++o) { + bitSetDiscreteVoxelShape.clearZStrip(k, l, o, n + 1); + } + + ++n; + } + + intLineConsumer.consume(j, i, k, m + 1, n + 1, l); + k = -1; + } + } + } + } + + } + + @Unique + private static void chkForAll(final DiscreteVoxelShape shape, final boolean mergeAdjacent) { + record Range(int sx, int sy, int sz, int ex, int ey, int ez) {} + + if (new Throwable().getStackTrace()[2].getMethodName().contains("chkForAll")) { + return; + } + + final List vanillaRanges = new ArrayList<>(); + final List moonriseRanges = new ArrayList<>(); + + forAllBoxesVanilla(shape, (x1, y1, z1, x2, y2, z2) -> { + vanillaRanges.add(new Range(x1, y1, z1, x2, y2, z2)); + }, mergeAdjacent); + + forAllBoxes(shape, (x1, y1, z1, x2, y2, z2) -> { + moonriseRanges.add(new Range(x1, y1, z1, x2, y2, z2)); + }, mergeAdjacent); + + if (!vanillaRanges.equals(moonriseRanges)) { + forAllBoxesVanilla(shape, (x1, y1, z1, x2, y2, z2) -> {}, mergeAdjacent); + forAllBoxes(shape, (x1, y1, z1, x2, y2, z2) -> {}, mergeAdjacent); + + throw new IllegalStateException(); + } + } + /** * @reason avoid creating temporary shape, interact directly with the bitset * @author Spottedleaf */ @Overwrite public static void forAllBoxes(final DiscreteVoxelShape shape, final DiscreteVoxelShape.IntLineConsumer consumer, final boolean mergeAdjacent) { + if (DEBUG_ALL_BOXES) { + chkForAll(shape, mergeAdjacent); + } // called with the shape of a VoxelShape, so we can expect the cache to exist final CachedShapeData cache = ((CollisionDiscreteVoxelShape)shape).getOrCreateCachedShapeData(); @@ -65,56 +145,58 @@ public abstract class BitSetDiscreteVoxelShapeMixin extends DiscreteVoxelShape { for (int y = 0; y < sizeY; ++y, indexY += incY) { indexX = indexY; for (int x = 0; x < sizeX; ++x, indexX += incX) { - final int startIndex = indexX; - final int endIndex = indexX + sizeZ; + for (int zIdx = indexX, endIndex = indexX + sizeZ; zIdx < endIndex;) { + final int firstSetZ = FlatBitsetUtil.firstSet(bitset, zIdx, endIndex); - final int firstSetZ = FlatBitsetUtil.firstSet(bitset, startIndex, endIndex); + if (firstSetZ == -1) { + break; + } - if (firstSetZ == -1) { - continue; - } + int lastSetZ = FlatBitsetUtil.firstClear(bitset, firstSetZ, endIndex); + if (lastSetZ == -1) { + lastSetZ = endIndex; + } - int lastSetZ = FlatBitsetUtil.firstClear(bitset, firstSetZ, endIndex); - if (lastSetZ == -1) { - lastSetZ = endIndex; - } + FlatBitsetUtil.clearRange(bitset, firstSetZ, lastSetZ); - FlatBitsetUtil.clearRange(bitset, firstSetZ, lastSetZ); + // try to merge neighbouring on the X axis + int endX = x + 1; // exclusive + for (int neighbourIdxStart = firstSetZ + incX, neighbourIdxEnd = lastSetZ + incX; + endX < sizeX && FlatBitsetUtil.isRangeSet(bitset, neighbourIdxStart, neighbourIdxEnd); + neighbourIdxStart += incX, neighbourIdxEnd += incX) { - // try to merge neighbouring on the X axis - int endX = x + 1; // exclusive - for (int neighbourIdxStart = firstSetZ + incX, neighbourIdxEnd = lastSetZ + incX; - endX < sizeX && FlatBitsetUtil.isRangeSet(bitset, neighbourIdxStart, neighbourIdxEnd); - neighbourIdxStart += incX, neighbourIdxEnd += incX) { + ++endX; + FlatBitsetUtil.clearRange(bitset, neighbourIdxStart, neighbourIdxEnd); + } - ++endX; - FlatBitsetUtil.clearRange(bitset, neighbourIdxStart, neighbourIdxEnd); - } + // try to merge neighbouring on the Y axis - // try to merge neighbouring on the Y axis + int endY; // exclusive + int firstSetZY, lastSetZY; + y_merge: + for (endY = y + 1, firstSetZY = firstSetZ + incY, lastSetZY = lastSetZ + incY; endY < sizeY; + firstSetZY += incY, lastSetZY += incY) { - int endY; // exclusive - int firstSetZY, lastSetZY; - y_merge: - for (endY = y + 1, firstSetZY = firstSetZ + incY, lastSetZY = lastSetZ + incY; endY < sizeY; - ++endY, firstSetZY += incY, lastSetZY += incY) { + // test the whole XZ range + for (int testX = x, start = firstSetZY, end = lastSetZY; testX < endX; + ++testX, start += incX, end += incX) { + if (!FlatBitsetUtil.isRangeSet(bitset, start, end)) { + break y_merge; + } + } - // test the whole XZ range - for (int testX = x, start = firstSetZY, end = lastSetZY; testX < endX; - ++testX, start += incX, end += incX) { - if (!FlatBitsetUtil.isRangeSet(bitset, start, end)) { - break y_merge; + ++endY; + + // passed, so we can clear it + for (int testX = x, start = firstSetZY, end = lastSetZY; testX < endX; + ++testX, start += incX, end += incX) { + FlatBitsetUtil.clearRange(bitset, start, end); } } - // passed, so we can clear it - for (int testX = x, start = firstSetZY, end = lastSetZY; testX < endX; - ++testX, start += incX, end += incX) { - FlatBitsetUtil.clearRange(bitset, start, end); - } + consumer.consume(x, y, firstSetZ - indexX, endX, endY, lastSetZ - indexX); + zIdx = lastSetZ; } - - consumer.consume(x, y, firstSetZ - startIndex, endX, endY, lastSetZ - startIndex); } } } diff --git a/src/main/resources/moonrise.accesswidener b/src/main/resources/moonrise.accesswidener index f8af3d2..12e170a 100644 --- a/src/main/resources/moonrise.accesswidener +++ b/src/main/resources/moonrise.accesswidener @@ -92,7 +92,9 @@ accessible field net/minecraft/world/phys/shapes/BitSetDiscreteVoxelShape xMax I accessible field net/minecraft/world/phys/shapes/BitSetDiscreteVoxelShape yMax I accessible field net/minecraft/world/phys/shapes/BitSetDiscreteVoxelShape zMax I accessible method net/minecraft/world/phys/shapes/BitSetDiscreteVoxelShape join (Lnet/minecraft/world/phys/shapes/DiscreteVoxelShape;Lnet/minecraft/world/phys/shapes/DiscreteVoxelShape;Lnet/minecraft/world/phys/shapes/IndexMerger;Lnet/minecraft/world/phys/shapes/IndexMerger;Lnet/minecraft/world/phys/shapes/IndexMerger;Lnet/minecraft/world/phys/shapes/BooleanOp;)Lnet/minecraft/world/phys/shapes/BitSetDiscreteVoxelShape; - +accessible method net/minecraft/world/phys/shapes/BitSetDiscreteVoxelShape isZStripFull (IIII)Z +accessible method net/minecraft/world/phys/shapes/BitSetDiscreteVoxelShape isXZRectangleFull (IIIII)Z +accessible method net/minecraft/world/phys/shapes/BitSetDiscreteVoxelShape clearZStrip (IIII)V # IndexMerger accessible class net/minecraft/world/phys/shapes/IndexMerger