From d4462610b2633572a133d211b3eefff847d91874 Mon Sep 17 00:00:00 2001 From: MACTEP-ABATAP <61243966+MACTEP-ABATAP@users.noreply.github.com> Date: Sat, 4 Jul 2026 19:29:48 +0300 Subject: [PATCH] Prevent crashes during collision shape baking Wrapped collision shape retrieval in defensive error handling so problematic block states do not crash collider baking. This also ensures the temporary block getter state is reset after shape retrieval and treats failed or null shapes as empty collision data. --- .../collider/RapierVoxelColliderBakery.java | 44 +++++++++++++++---- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/sable_rapier/src/main/java/dev/ryanhcode/sable/physics/impl/rapier/collider/RapierVoxelColliderBakery.java b/sable_rapier/src/main/java/dev/ryanhcode/sable/physics/impl/rapier/collider/RapierVoxelColliderBakery.java index f4baf892..6f84f864 100644 --- a/sable_rapier/src/main/java/dev/ryanhcode/sable/physics/impl/rapier/collider/RapierVoxelColliderBakery.java +++ b/sable_rapier/src/main/java/dev/ryanhcode/sable/physics/impl/rapier/collider/RapierVoxelColliderBakery.java @@ -1,5 +1,6 @@ package dev.ryanhcode.sable.physics.impl.rapier.collider; +import dev.ryanhcode.sable.Sable; import dev.ryanhcode.sable.api.block.BlockSubLevelCollisionShape; import dev.ryanhcode.sable.api.block.BlockWithSubLevelCollisionCallback; import dev.ryanhcode.sable.api.physics.callback.BlockSubLevelCollisionCallback; @@ -13,6 +14,7 @@ import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -66,15 +68,7 @@ public RapierVoxelColliderBakery(@NotNull final BlockGetter blockGetter) { return entry; } - final VoxelShape shape; - - this.level.setup(childState); - if (childState.getBlock() instanceof final BlockSubLevelCollisionShape extension) { - shape = extension.getSubLevelCollisionShape(this.level, childState); - } else { - shape = childState.getCollisionShape(this.level, BlockPos.ZERO, SableCollisionContext.get()); - } - this.level.setup(Blocks.AIR.defaultBlockState()); + final VoxelShape shape = this.getCollisionShapeOrFallback(childState); if (shape.isEmpty()) { return RapierVoxelColliderData.EMPTY; @@ -92,6 +86,38 @@ public RapierVoxelColliderBakery(@NotNull final BlockGetter blockGetter) { return entry; } + private @NotNull VoxelShape getCollisionShapeOrFallback(final BlockState childState) { + try { + this.level.setup(childState); + + final VoxelShape shape; + if (childState.getBlock() instanceof final BlockSubLevelCollisionShape extension) { + shape = extension.getSubLevelCollisionShape(this.level, childState); + } else { + shape = childState.getCollisionShape(this.level, BlockPos.ZERO, SableCollisionContext.get()); + } + + if (shape == null) { + Sable.LOGGER.warn( + "Block state {} returned a null collision shape. Falling back to a full block collision shape.", + childState + ); + return Shapes.block(); + } + + return shape; + } catch (final Exception exception) { + Sable.LOGGER.warn( + "Failed to get collision shape for block state {}. Falling back to a full block collision shape.", + childState, + exception + ); + return Shapes.block(); + } finally { + this.level.setup(Blocks.AIR.defaultBlockState()); + } + } + /** * Builds / gets a saved box or compound collision shape for a block *