From 8011d0dbccde9918ce385c1eebf3490e611cbcc3 Mon Sep 17 00:00:00 2001 From: winggar Date: Sun, 17 May 2026 11:39:28 -0700 Subject: [PATCH 1/2] Fix standing up from crawling, resolve #7, resolve #422 --- .../mixin/player_standup/PlayerMixin.java | 32 +++++++++++++++++++ common/src/main/resources/sable.mixins.json | 1 + 2 files changed, 33 insertions(+) create mode 100644 common/src/main/java/dev/ryanhcode/sable/mixin/player_standup/PlayerMixin.java diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/player_standup/PlayerMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/player_standup/PlayerMixin.java new file mode 100644 index 00000000..619e1f05 --- /dev/null +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/player_standup/PlayerMixin.java @@ -0,0 +1,32 @@ +package dev.ryanhcode.sable.mixin.player_standup; + +import dev.ryanhcode.sable.mixinhelpers.CanFallAtleastHelper; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.AABB; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(Player.class) +public class PlayerMixin { + + @Redirect( + method = "canPlayerFitWithinBlocksAndEntitiesWhen", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/level/Level;noCollision(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/AABB;)Z" + ) + ) + private boolean sable$noCollisionWithSubLevels(final Level level, final Entity entity, final AABB aabb) { + final boolean original = level.noCollision(entity, aabb); + + if (!original) return false; + + // If vanilla says no collision, also check sublevel blocks. + // canFallAtleastWithSubLevels returns non-null when there IS a collision, + // meaning the player does NOT fit → return false. + return CanFallAtleastHelper.canFallAtleastWithSubLevels(level, aabb) == null; + } +} diff --git a/common/src/main/resources/sable.mixins.json b/common/src/main/resources/sable.mixins.json index ad2263af..01cb74db 100644 --- a/common/src/main/resources/sable.mixins.json +++ b/common/src/main/resources/sable.mixins.json @@ -50,6 +50,7 @@ "particle.SuspendedParticleMixin", "particle.TerrainParticleMixin", "player_freezing.LocalPlayerMixin", + "player_standup.PlayerMixin", "plot.ClientChunkCacheMixin", "plot.MinecraftMixin", "plot.lighting.ClientPacketListenerMixin", From a87a686b28d97b77f7f1fff7ca10c7917c78e909 Mon Sep 17 00:00:00 2001 From: Ocelot Date: Sun, 17 May 2026 12:49:01 -0600 Subject: [PATCH 2/2] Replace redirect with wrap operation --- .../sable/mixin/player_standup/PlayerMixin.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/player_standup/PlayerMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/player_standup/PlayerMixin.java index 619e1f05..c92d306d 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/player_standup/PlayerMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/player_standup/PlayerMixin.java @@ -1,5 +1,7 @@ package dev.ryanhcode.sable.mixin.player_standup; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import dev.ryanhcode.sable.mixinhelpers.CanFallAtleastHelper; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; @@ -7,26 +9,25 @@ import net.minecraft.world.phys.AABB; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(Player.class) public class PlayerMixin { - @Redirect( + @WrapOperation( method = "canPlayerFitWithinBlocksAndEntitiesWhen", at = @At( value = "INVOKE", target = "Lnet/minecraft/world/level/Level;noCollision(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/AABB;)Z" ) ) - private boolean sable$noCollisionWithSubLevels(final Level level, final Entity entity, final AABB aabb) { - final boolean original = level.noCollision(entity, aabb); - - if (!original) return false; + private boolean sable$noCollisionWithSubLevels(final Level instance, final Entity entity, final AABB aabb, final Operation original) { + if (!original.call(instance, entity, aabb)) { + return false; + } // If vanilla says no collision, also check sublevel blocks. // canFallAtleastWithSubLevels returns non-null when there IS a collision, // meaning the player does NOT fit → return false. - return CanFallAtleastHelper.canFallAtleastWithSubLevels(level, aabb) == null; + return CanFallAtleastHelper.canFallAtleastWithSubLevels(instance, aabb) == null; } }