Skip to content

Commit ab35efc

Browse files
authored
Let ParCool see sub-levels
1 parent bf9713a commit ab35efc

3 files changed

Lines changed: 126 additions & 0 deletions

File tree

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package dev.ryanhcode.sable.mixin.compatibility.parcool;
2+
3+
import dev.ryanhcode.sable.mixinhelpers.SubLevelNoCollisionHelper;
4+
import net.minecraft.world.entity.Entity;
5+
import net.minecraft.world.level.Level;
6+
import net.minecraft.world.phys.AABB;
7+
import org.spongepowered.asm.mixin.Mixin;
8+
import org.spongepowered.asm.mixin.injection.At;
9+
import org.spongepowered.asm.mixin.injection.Redirect;
10+
11+
@Mixin(targets = "com.alrex.parcool.utilities.WorldUtil", remap = false)
12+
public class WorldUtilMixin {
13+
14+
@Redirect(method = "*", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;noCollision(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/AABB;)Z"), require = 0)
15+
private static boolean sable$noCollisionForEntity(final Level level, final Entity entity, final AABB aabb) {
16+
if (!level.noCollision(entity, aabb)) {
17+
return false;
18+
}
19+
20+
return SubLevelNoCollisionHelper.noCollisionWithSubLevels(level, aabb);
21+
}
22+
23+
@Redirect(method = "*", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;noCollision(Lnet/minecraft/world/phys/AABB;)Z"), require = 0)
24+
private static boolean sable$noCollision(final Level level, final AABB aabb) {
25+
if (!level.noCollision(aabb)) {
26+
return false;
27+
}
28+
29+
return SubLevelNoCollisionHelper.noCollisionWithSubLevels(level, aabb);
30+
}
31+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package dev.ryanhcode.sable.mixinhelpers;
2+
3+
import dev.ryanhcode.sable.Sable;
4+
import dev.ryanhcode.sable.api.math.LevelReusedVectors;
5+
import dev.ryanhcode.sable.api.math.OrientedBoundingBox3d;
6+
import dev.ryanhcode.sable.companion.math.BoundingBox3d;
7+
import dev.ryanhcode.sable.companion.math.BoundingBox3dc;
8+
import dev.ryanhcode.sable.companion.math.Pose3dc;
9+
import dev.ryanhcode.sable.mixinterface.entity.entity_sublevel_collision.LevelExtension;
10+
import dev.ryanhcode.sable.mixinterface.voxel_shape_iteration.FastVoxelShapeIterable;
11+
import dev.ryanhcode.sable.sublevel.SubLevel;
12+
import dev.ryanhcode.sable.sublevel.entity_collision.SubLevelEntityCollision;
13+
import net.minecraft.core.BlockPos;
14+
import net.minecraft.world.level.Level;
15+
import net.minecraft.world.level.block.state.BlockState;
16+
import net.minecraft.world.phys.AABB;
17+
import net.minecraft.world.phys.shapes.VoxelShape;
18+
import org.joml.Matrix4d;
19+
import org.joml.Vector3d;
20+
21+
import java.util.Iterator;
22+
23+
public class SubLevelNoCollisionHelper {
24+
25+
public static boolean noCollisionWithSubLevels(final Level level, final AABB aabb) {
26+
final BoundingBox3d considerationBounds = new BoundingBox3d(aabb);
27+
considerationBounds.expand(1.05, considerationBounds);
28+
29+
final Iterable<SubLevel> intersecting = Sable.HELPER.getAllIntersecting(level, considerationBounds);
30+
31+
final LevelReusedVectors sink = ((LevelExtension) level).sable$getJOMLSink();
32+
33+
sink.entityBoxOrientation.identity();
34+
final OrientedBoundingBox3d queryOBB = new OrientedBoundingBox3d(
35+
(aabb.minX + aabb.maxX) / 2.0,
36+
(aabb.minY + aabb.maxY) / 2.0,
37+
(aabb.minZ + aabb.maxZ) / 2.0,
38+
aabb.getXsize(),
39+
aabb.getYsize(),
40+
aabb.getZsize(),
41+
sink.entityBoxOrientation,
42+
sink);
43+
44+
final OrientedBoundingBox3d cubeOBB = new OrientedBoundingBox3d(sink);
45+
final BoundingBox3d localBounds = new BoundingBox3d();
46+
final Matrix4d bakedPose = new Matrix4d();
47+
48+
final Vector3d center = new Vector3d();
49+
final Vector3d satResult = new Vector3d();
50+
51+
for (final SubLevel subLevel : intersecting) {
52+
final Pose3dc pose = subLevel.lastPose();
53+
localBounds.set(aabb);
54+
localBounds.transformInverse(pose, bakedPose, localBounds);
55+
56+
final Iterable<BlockPos> blocks = BlockPos.betweenClosed(
57+
BlockPos.containing(localBounds.minX, localBounds.minY, localBounds.minZ),
58+
BlockPos.containing(localBounds.maxX, localBounds.maxY, localBounds.maxZ));
59+
60+
cubeOBB.getOrientation().set(pose.orientation());
61+
62+
sink.entityBoxOrientation.identity().rotateY(SubLevelEntityCollision.getHitBoxYaw(pose));
63+
queryOBB.setOrientation(sink.entityBoxOrientation);
64+
65+
for (final BlockPos block : blocks) {
66+
final BlockState state = level.getBlockState(block);
67+
68+
if (state.isAir()) {
69+
continue;
70+
}
71+
72+
final VoxelShape voxelShape = state.getCollisionShape(level, block);
73+
74+
final Iterator<BoundingBox3dc> iterator = ((FastVoxelShapeIterable) voxelShape).sable$allBoxes();
75+
while (iterator.hasNext()) {
76+
final BoundingBox3dc box = iterator.next();
77+
box.center(center);
78+
cubeOBB.getPosition().set(block.getX() + center.x,
79+
block.getY() + center.y,
80+
block.getZ() + center.z);
81+
pose.transformPosition(cubeOBB.getPosition());
82+
box.size(cubeOBB.getDimensions());
83+
84+
OrientedBoundingBox3d.sat(queryOBB, cubeOBB, satResult);
85+
if (satResult.lengthSquared() > 0 && satResult.x() != Double.MAX_VALUE && satResult.y() != Double.MAX_VALUE && satResult.z() != Double.MAX_VALUE) {
86+
return false;
87+
}
88+
}
89+
}
90+
}
91+
92+
return true;
93+
}
94+
}

common/src/main/resources/sable.mixins.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
114114
"compatibility.jade.BlockAccessorImplMixin",
115115
"compatibility.jade.RayTracingMixin",
116116
"compatibility.jadeaddons.CreatePluginMixin",
117+
"compatibility.parcool.WorldUtilMixin",
117118
"compatibility.shouldersurfing.EntityHelperMixin",
118119
"compatibility.shouldersurfing.PerspectiveMixin",
119120
"compatibility.shouldersurfing.ShoulderSurfingCameraMixin",

0 commit comments

Comments
 (0)