From 77e3ab5c0139bb83c05125b23fd26f026efbd0f8 Mon Sep 17 00:00:00 2001 From: sery Date: Thu, 14 May 2026 04:05:21 +0200 Subject: [PATCH 1/8] mixin compatibility improvements --- .../camera/camera_rotation/EntityMixin.java | 10 ++-- .../clip_overwrite/BlockGetterMixin.java | 51 ++++--------------- 2 files changed, 15 insertions(+), 46 deletions(-) diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/camera/camera_rotation/EntityMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/camera/camera_rotation/EntityMixin.java index 84ebbf49..8afc3854 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/camera/camera_rotation/EntityMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/camera/camera_rotation/EntityMixin.java @@ -1,5 +1,6 @@ package dev.ryanhcode.sable.mixin.camera.camera_rotation; +import com.llamalad7.mixinextras.injector.ModifyReturnValue; import dev.ryanhcode.sable.companion.math.JOMLConversion; import dev.ryanhcode.sable.companion.math.Pose3dc; import dev.ryanhcode.sable.mixinhelpers.camera.camera_rotation.EntitySubLevelRotationHelper; @@ -22,8 +23,8 @@ public abstract class EntityMixin { @Shadow private Level level; - @Inject(method = "calculateViewVector", at = @At("RETURN"), cancellable = true) - public void sable$calculateViewVector(final float f, final float g, final CallbackInfoReturnable cir) { + @ModifyReturnValue(method = "calculateViewVector", at = @At("RETURN")) + public Vec3 sable$calculateViewVector(final Vec3 viewVector, final float f, final float g) { final Function provider; if (this.level instanceof final LevelPoseProviderExtension levelPoseProvider) { @@ -35,9 +36,10 @@ public abstract class EntityMixin { final Quaterniond orientation = EntitySubLevelRotationHelper.getEntityOrientation((Entity) (Object) this, provider, 0.0f, EntitySubLevelRotationHelper.Type.CAMERA); if (orientation != null) { - final Vec3 viewVector = cir.getReturnValue(); - cir.setReturnValue(JOMLConversion.toMojang(orientation.transform(JOMLConversion.toJOML(viewVector)))); + return JOMLConversion.toMojang(orientation.transform(JOMLConversion.toJOML(viewVector))); } + + return viewVector; } } diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/clip_overwrite/BlockGetterMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/clip_overwrite/BlockGetterMixin.java index dc88ef04..8a082cee 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/clip_overwrite/BlockGetterMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/clip_overwrite/BlockGetterMixin.java @@ -1,8 +1,9 @@ package dev.ryanhcode.sable.mixin.clip_overwrite; +import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import dev.ryanhcode.sable.ActiveSableCompanion; import dev.ryanhcode.sable.Sable; -import dev.ryanhcode.sable.api.SubLevelHelper; import dev.ryanhcode.sable.companion.math.BoundingBox3d; import dev.ryanhcode.sable.companion.math.JOMLConversion; import dev.ryanhcode.sable.companion.math.Pose3dc; @@ -15,42 +16,29 @@ import net.minecraft.world.level.ClipContext; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.FluidState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; -import net.minecraft.world.phys.shapes.VoxelShape; -import org.jetbrains.annotations.NotNull; import org.joml.Vector3dc; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; import java.util.function.Predicate; /** * Overwrites raycasts to take sublevels into account - * - * TODO: The priority is currently higher simply to take priority over lithium, but usage of Lithium's raycast replacement alongside our sub-level stuff would be far nicer. */ -@Mixin(value = BlockGetter.class, priority = 1100) +@Mixin(BlockGetter.class) public interface BlockGetterMixin { @Shadow BlockState getBlockState(BlockPos blockPos); - /** - * @author RyanH - * @reason Overwrites raycasts to take sublevels into account - */ - @Overwrite - default BlockHitResult clip(ClipContext clipContext) { - final BlockGetter self = (BlockGetter) this; - + @WrapMethod(method = "clip", order = Integer.MIN_VALUE) + default BlockHitResult clip(ClipContext clipContext, final Operation original) { if (!(this instanceof final Level level) || (clipContext instanceof final ClipContextExtension extension && extension.sable$doNotProject())) { // If the level cannot have sublevels, use the original method - return originalClip(self, clipContext); + return original.call(clipContext); } final SubLevel ignoredSubLevel = clipContext instanceof final ClipContextExtension extension ? @@ -93,7 +81,7 @@ default BlockHitResult clip(ClipContext clipContext) { final Vec3 diff = clipContext.getFrom().subtract(clipContext.getTo()); minResult = BlockHitResult.miss(clipContext.getTo(), Direction.getNearest(diff.x, diff.y, diff.z), BlockPos.containing(clipContext.getTo())); } else { - minResult = originalClip(self, clipContext); + minResult = original.call(clipContext); minDistance = minResult.getLocation().distanceTo(clipContext.getFrom()); } @@ -121,7 +109,8 @@ default BlockHitResult clip(ClipContext clipContext) { final ClipContext subClipContext = new ClipContext(JOMLConversion.toMojang(from), JOMLConversion.toMojang(to), clipContext.block, clipContext.fluid, clipContext.collisionContext); - final BlockHitResult subResult = originalClip(subLevel.getLevel(), subClipContext); + ((ClipContextExtension) subClipContext).sable$setDoNotProject(true); + final BlockHitResult subResult = subLevel.getLevel().clip(subClipContext); final double distance = subResult.getLocation().distanceTo(subClipContext.getFrom()); if ((distance < minDistance || minResult.getType() == HitResult.Type.MISS) && subResult.getType() != HitResult.Type.MISS) { @@ -132,26 +121,4 @@ default BlockHitResult clip(ClipContext clipContext) { return minResult; } - - @Unique - private static @NotNull BlockHitResult originalClip(final BlockGetter level, final ClipContext clipContext) { - return BlockGetter.traverseBlocks(clipContext.getFrom(), clipContext.getTo(), clipContext, (clipContextx, blockPos) -> { - final BlockState blockState = level.getBlockState(blockPos); - final FluidState fluidState = level.getFluidState(blockPos); - final Vec3 vec3 = clipContextx.getFrom(); - final Vec3 vec32 = clipContextx.getTo(); - final VoxelShape voxelShape = clipContextx.getBlockShape(blockState, level, blockPos); - final BlockHitResult blockHitResult = level.clipWithInteractionOverride(vec3, vec32, blockPos, voxelShape, blockState); - final VoxelShape voxelShape2 = clipContextx.getFluidShape(fluidState, level, blockPos); - final BlockHitResult blockHitResult2 = voxelShape2.clip(vec3, vec32, blockPos); - final double d = blockHitResult == null ? Double.MAX_VALUE : clipContextx.getFrom().distanceToSqr(blockHitResult.getLocation()); - final double e = blockHitResult2 == null ? Double.MAX_VALUE : clipContextx.getFrom().distanceToSqr(blockHitResult2.getLocation()); - return d <= e ? blockHitResult : blockHitResult2; - }, clipContextx -> { - final Vec3 vec3 = clipContextx.getFrom().subtract(clipContextx.getTo()); - return BlockHitResult.miss(clipContextx.getTo(), Direction.getNearest(vec3.x, vec3.y, vec3.z), BlockPos.containing(clipContextx.getTo())); - }); - } - - } From 10e0ffc1732cd10ff8006e3c04a259916c209027 Mon Sep 17 00:00:00 2001 From: sery Date: Thu, 14 May 2026 16:25:32 +0200 Subject: [PATCH 2/8] replace some redirects with safer injectors --- .../camera/camera_rotation/EntityMixin.java | 4 +-- .../camera/camera_rotation/GuiMixin.java | 29 ++++++++++++------- .../camera/camera_zoom/MouseHandlerMixin.java | 11 ++++--- .../entity_tracking/TrackedEntityMixin.java | 12 ++++---- 4 files changed, 31 insertions(+), 25 deletions(-) diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/camera/camera_rotation/EntityMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/camera/camera_rotation/EntityMixin.java index 8afc3854..d449d255 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/camera/camera_rotation/EntityMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/camera/camera_rotation/EntityMixin.java @@ -37,9 +37,9 @@ public abstract class EntityMixin { if (orientation != null) { return JOMLConversion.toMojang(orientation.transform(JOMLConversion.toJOML(viewVector))); + } else { + return viewVector; } - - return viewVector; } } diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/camera/camera_rotation/GuiMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/camera/camera_rotation/GuiMixin.java index 832bef4f..81dccaf2 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/camera/camera_rotation/GuiMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/camera/camera_rotation/GuiMixin.java @@ -1,5 +1,6 @@ package dev.ryanhcode.sable.mixin.camera.camera_rotation; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.sugar.Share; import com.llamalad7.mixinextras.sugar.ref.LocalRef; import dev.ryanhcode.sable.mixinhelpers.camera.camera_rotation.EntitySubLevelRotationHelper; @@ -9,7 +10,6 @@ import net.minecraft.client.gui.Gui; import net.minecraft.world.entity.Entity; import org.joml.Matrix4f; -import org.joml.Matrix4fStack; import org.joml.Quaterniond; import org.joml.Quaternionf; import org.spongepowered.asm.mixin.Final; @@ -17,7 +17,7 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; /** @@ -38,32 +38,39 @@ public class GuiMixin { mountedOrientation.set(ridingOrientation); } - @Redirect(method = "renderCrosshair", at = @At(value = "INVOKE", target = "Lorg/joml/Matrix4fStack;rotateX(F)Lorg/joml/Matrix4f;")) - private Matrix4f sable$redirectRotateX(final Matrix4fStack stack, final float angle, @Share("mountedOrientation") final LocalRef mountedOrientation) { + @ModifyArg(method = "renderCrosshair", at = @At(value = "INVOKE", target = "Lorg/joml/Matrix4fStack;rotateX(F)Lorg/joml/Matrix4f;"), index = 0) + private float sable$modifyRotateXAngle(final float angle, @Share("mountedOrientation") final LocalRef mountedOrientation) { if (mountedOrientation.get() != null) { final float pt = this.minecraft.getTimer().getGameTimeDeltaPartialTick(true); final Camera camera = this.minecraft.gameRenderer.getMainCamera(); final Entity entity = camera.getEntity(); - return stack.rotateX(-entity.getViewXRot(pt) * (float) (Math.PI / 180.0)); + return -entity.getViewXRot(pt) * (float) (Math.PI / 180.0); } - return stack.rotateX(angle); + return angle; } - @Redirect(method = "renderCrosshair", at = @At(value = "INVOKE", target = "Lorg/joml/Matrix4fStack;rotateY(F)Lorg/joml/Matrix4f;")) - private Matrix4f sable$redirectRotateY(final Matrix4fStack stack, final float angle, @Share("mountedOrientation") final LocalRef mountedOrientation) { + @ModifyArg(method = "renderCrosshair", at = @At(value = "INVOKE", target = "Lorg/joml/Matrix4fStack;rotateY(F)Lorg/joml/Matrix4f;"), index = 0) + private float sable$modifyRotateYAngle(final float angle, @Share("mountedOrientation") final LocalRef mountedOrientation) { if (mountedOrientation.get() != null) { final float pt = this.minecraft.getTimer().getGameTimeDeltaPartialTick(true); final Camera camera = this.minecraft.gameRenderer.getMainCamera(); final Entity entity = camera.getEntity(); - stack.rotateY(entity.getViewYRot(pt) * (float) (Math.PI / 180.0)); + return entity.getViewYRot(pt) * (float) (Math.PI / 180.0); + } + + return angle; + } - return stack.rotate(new Quaternionf(mountedOrientation.get()).conjugate()); + @ModifyExpressionValue(method = "renderCrosshair", at = @At(value = "INVOKE", target = "Lorg/joml/Matrix4fStack;rotateY(F)Lorg/joml/Matrix4f;")) + private Matrix4f sable$modifyRotateY(final Matrix4f original, @Share("mountedOrientation") final LocalRef mountedOrientation) { + if (mountedOrientation.get() != null) { + return original.rotate(new Quaternionf(mountedOrientation.get()).conjugate()); } - return stack.rotateY(angle); + return original; } } diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/camera/camera_zoom/MouseHandlerMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/camera/camera_zoom/MouseHandlerMixin.java index 3fca8f46..e4687df1 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/camera/camera_zoom/MouseHandlerMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/camera/camera_zoom/MouseHandlerMixin.java @@ -1,7 +1,6 @@ package dev.ryanhcode.sable.mixin.camera.camera_zoom; -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; import dev.ryanhcode.sable.SableClientConfig; import dev.ryanhcode.sable.mixinhelpers.camera.new_camera_types.SableCameraTypes; import dev.ryanhcode.sable.mixinterface.camera.camera_zoom.CameraZoomExtension; @@ -19,16 +18,16 @@ public class MouseHandlerMixin { @Shadow @Final private Minecraft minecraft; - @WrapOperation(method = "onScroll", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Inventory;swapPaint(D)V")) - private void sable$onScroll(final Inventory instance, final double d, final Operation original) { + @WrapWithCondition(method = "onScroll", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Inventory;swapPaint(D)V")) + private boolean sable$onScroll(final Inventory instance, final double d) { final CameraType cameraType = this.minecraft.options.getCameraType(); if (cameraType == SableCameraTypes.SUB_LEVEL_VIEW || cameraType == SableCameraTypes.SUB_LEVEL_VIEW_UNLOCKED) { final CameraZoomExtension extension = ((CameraZoomExtension) this.minecraft.gameRenderer.getMainCamera()); extension.sable$setZoomAmount((float) (extension.sable$getZoomAmount() - d * SableClientConfig.ZOOM_SENSITIVITY.get())); - return; + return false; } - original.call(instance, d); + return true; } } \ No newline at end of file diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/entity/entity_tracking/TrackedEntityMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/entity_tracking/TrackedEntityMixin.java index ee8f0539..462ae453 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/entity/entity_tracking/TrackedEntityMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/entity_tracking/TrackedEntityMixin.java @@ -1,26 +1,26 @@ package dev.ryanhcode.sable.mixin.entity.entity_tracking; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import dev.ryanhcode.sable.Sable; -import dev.ryanhcode.sable.api.SubLevelHelper; import dev.ryanhcode.sable.sublevel.SubLevel; import net.minecraft.world.entity.Entity; import net.minecraft.world.phys.Vec3; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(targets = "net.minecraft.server.level.ChunkMap$TrackedEntity") public class TrackedEntityMixin { - @Redirect(method = "updatePlayer", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;position()Lnet/minecraft/world/phys/Vec3;")) - private Vec3 sable$trackSubLevelEntities(final Entity instance) { - final Vec3 pos = instance.position(); + @WrapOperation(method = "updatePlayer", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;position()Lnet/minecraft/world/phys/Vec3;")) + private Vec3 sable$trackSubLevelEntities(final Entity instance, final Operation original) { + final Vec3 pos = original.call(instance); final SubLevel subLevel = Sable.HELPER.getContaining(instance.level(), pos); if (subLevel != null) { return subLevel.logicalPose().transformPosition(pos); } else { - return instance.position(); + return pos; } } } From 9afca855d81e9340870f25100ac83cd57eb5186c Mon Sep 17 00:00:00 2001 From: sery Date: Thu, 14 May 2026 16:26:12 +0200 Subject: [PATCH 3/8] dont think order matters here --- .../ryanhcode/sable/mixin/clip_overwrite/BlockGetterMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/clip_overwrite/BlockGetterMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/clip_overwrite/BlockGetterMixin.java index 8a082cee..63b17d4b 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/clip_overwrite/BlockGetterMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/clip_overwrite/BlockGetterMixin.java @@ -34,7 +34,7 @@ public interface BlockGetterMixin { @Shadow BlockState getBlockState(BlockPos blockPos); - @WrapMethod(method = "clip", order = Integer.MIN_VALUE) + @WrapMethod(method = "clip") default BlockHitResult clip(ClipContext clipContext, final Operation original) { if (!(this instanceof final Level level) || (clipContext instanceof final ClipContextExtension extension && extension.sable$doNotProject())) { // If the level cannot have sublevels, use the original method From 1128539455592c13d4a45ddce1aa7d263beb174f Mon Sep 17 00:00:00 2001 From: sery Date: Thu, 14 May 2026 18:51:03 +0200 Subject: [PATCH 4/8] some little mixin improvements --- .../mixin/clip_overwrite/BlockGetterMixin.java | 5 +++-- .../sable/mixin/command/DataCommandsMixin.java | 9 ++++----- .../sable/mixin/command/ExecuteCommandMixin.java | 12 +++++------- .../EnchantingTableBlockEntityMixin.java | 16 ++++++++-------- .../effects/EntityMixin.java | 11 ++++++----- .../entity_leashing/EntityRendererMixin.java | 15 +++++++++------ .../sable/mixin/options/OptionsScreenMixin.java | 13 ++++++------- .../mixin/player_freezing/LocalPlayerMixin.java | 8 +++++--- .../mixin/portal/NetherPortalBlockMixin.java | 8 ++++++-- 9 files changed, 52 insertions(+), 45 deletions(-) diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/clip_overwrite/BlockGetterMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/clip_overwrite/BlockGetterMixin.java index 63b17d4b..f8d1d1a5 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/clip_overwrite/BlockGetterMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/clip_overwrite/BlockGetterMixin.java @@ -34,8 +34,9 @@ public interface BlockGetterMixin { @Shadow BlockState getBlockState(BlockPos blockPos); - @WrapMethod(method = "clip") - default BlockHitResult clip(ClipContext clipContext, final Operation original) { + // order to make sure this is the innermost wrap + @WrapMethod(method = "clip", order = Integer.MIN_VALUE) + default BlockHitResult sable$wrapClip(ClipContext clipContext, final Operation original) { if (!(this instanceof final Level level) || (clipContext instanceof final ClipContextExtension extension && extension.sable$doNotProject())) { // If the level cannot have sublevels, use the original method return original.call(clipContext); diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/command/DataCommandsMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/command/DataCommandsMixin.java index 17e034ed..142db245 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/command/DataCommandsMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/command/DataCommandsMixin.java @@ -1,6 +1,7 @@ package dev.ryanhcode.sable.mixin.command; import com.google.common.collect.ImmutableList; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import dev.ryanhcode.sable.command.data_accessor.SubLevelDataAccessor; @@ -14,13 +15,11 @@ @Mixin(DataCommands.class) public class DataCommandsMixin { - @WrapOperation(method = "", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/ImmutableList;of(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Lcom/google/common/collect/ImmutableList;", remap = false)) - private static ImmutableList> sable$allProviders(final E e1, final E e2, final E e3, final Operation>> original) { - @SuppressWarnings("unchecked") - final ImmutableList> providers = (ImmutableList>) ((Operation) original).call(e1, e2, e3); + @ModifyExpressionValue(method = "", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/ImmutableList;of(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Lcom/google/common/collect/ImmutableList;", remap = false)) + private static ImmutableList> sable$allProviders(final ImmutableList> providers) { final ObjectArrayList> mutableList = new ObjectArrayList<>(providers); mutableList.add(SubLevelDataAccessor.PROVIDER); - return ImmutableList.copyOf(mutableList); + return ImmutableList.copyOf(mutableList); } } diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/command/ExecuteCommandMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/command/ExecuteCommandMixin.java index 9f418692..260e22bc 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/command/ExecuteCommandMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/command/ExecuteCommandMixin.java @@ -1,17 +1,15 @@ package dev.ryanhcode.sable.mixin.command; import com.google.common.collect.Lists; -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.sugar.Local; import com.mojang.brigadier.builder.ArgumentBuilder; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.tree.LiteralCommandNode; import dev.ryanhcode.sable.api.command.SableCommandHelper; import dev.ryanhcode.sable.api.command.SubLevelArgumentType; -import dev.ryanhcode.sable.companion.math.Pose3d; import dev.ryanhcode.sable.api.sublevel.ServerSubLevelContainer; import dev.ryanhcode.sable.api.sublevel.SubLevelContainer; +import dev.ryanhcode.sable.companion.math.Pose3d; import dev.ryanhcode.sable.sublevel.SubLevel; import dev.ryanhcode.sable.sublevel.plot.LevelPlot; import net.minecraft.commands.CommandSourceStack; @@ -34,9 +32,9 @@ public class ExecuteCommandMixin { * TODO: Better injection target here would be nice. And to split these out of the mixins. */ @SuppressWarnings("unchecked") - @WrapOperation(method = "register", at = @At(value = "INVOKE", target = "Lcom/mojang/brigadier/builder/LiteralArgumentBuilder;then(Lcom/mojang/brigadier/builder/ArgumentBuilder;)Lcom/mojang/brigadier/builder/ArgumentBuilder;", ordinal = 31, remap = false)) - private static ArgumentBuilder sable$then(final LiteralArgumentBuilder instance, final ArgumentBuilder argumentBuilder, final Operation original, @Local final LiteralCommandNode literalCommandNode) { - return instance.then(argumentBuilder) + @ModifyExpressionValue(method = "register", at = @At(value = "INVOKE", target = "Lcom/mojang/brigadier/builder/LiteralArgumentBuilder;then(Lcom/mojang/brigadier/builder/ArgumentBuilder;)Lcom/mojang/brigadier/builder/ArgumentBuilder;", ordinal = 31, remap = false)) + private static ArgumentBuilder sable$then(final ArgumentBuilder original, @Local final LiteralCommandNode literalCommandNode) { + return original .then( Commands.literal("in_sub_level") .then( diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/enchanting_table/EnchantingTableBlockEntityMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/enchanting_table/EnchantingTableBlockEntityMixin.java index 6d54016a..88462032 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/enchanting_table/EnchantingTableBlockEntityMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/enchanting_table/EnchantingTableBlockEntityMixin.java @@ -1,39 +1,39 @@ package dev.ryanhcode.sable.mixin.enchanting_table; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Local; import dev.ryanhcode.sable.Sable; -import dev.ryanhcode.sable.api.SubLevelHelper; import dev.ryanhcode.sable.sublevel.SubLevel; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.block.entity.EnchantingTableBlockEntity; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(EnchantingTableBlockEntity.class) public class EnchantingTableBlockEntityMixin { - @Redirect(method = "bookAnimationTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getX()D")) - private static double sable$getPlayerX(final Player instance, @Local(argsOnly = true) final BlockPos blockPos) { + @WrapOperation(method = "bookAnimationTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getX()D")) + private static double sable$getPlayerX(final Player instance, final Operation original, @Local(argsOnly = true) final BlockPos blockPos) { final SubLevel subLevel = Sable.HELPER.getContaining(instance.level(), blockPos); if (subLevel != null) { return subLevel.logicalPose().transformPositionInverse(instance.getEyePosition()).x(); } - return instance.getX(); + return original.call(instance); } - @Redirect(method = "bookAnimationTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getZ()D")) - private static double sable$getPlayerZ(final Player instance, @Local(argsOnly = true) final BlockPos blockPos) { + @WrapOperation(method = "bookAnimationTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getZ()D")) + private static double sable$getPlayerZ(final Player instance, final Operation original, @Local(argsOnly = true) final BlockPos blockPos) { final SubLevel subLevel = Sable.HELPER.getContaining(instance.level(), blockPos); if (subLevel != null) { return subLevel.logicalPose().transformPositionInverse(instance.getEyePosition()).z(); } - return instance.getZ(); + return original.call(instance); } } diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/entity/entities_stick_sublevels/effects/EntityMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/entities_stick_sublevels/effects/EntityMixin.java index 0ebe8e5c..41f705e2 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/entity/entities_stick_sublevels/effects/EntityMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/entities_stick_sublevels/effects/EntityMixin.java @@ -1,5 +1,7 @@ package dev.ryanhcode.sable.mixin.entity.entities_stick_sublevels.effects; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Local; import com.llamalad7.mixinextras.sugar.Share; import com.llamalad7.mixinextras.sugar.ref.LocalRef; @@ -93,13 +95,12 @@ public abstract class EntityMixin { return localPosition.get().y; } - - @Redirect(method = "spawnSprintParticle", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;addParticle(Lnet/minecraft/core/particles/ParticleOptions;DDDDDD)V")) - private void sable$addParticle(final Level instance, final ParticleOptions particleOptions, final double d, final double e, final double f, final double g, final double h, final double i, @Share("localPosition") final LocalRef localPosition, @Local(ordinal = 0) final BlockPos pos) { + @WrapOperation(method = "spawnSprintParticle", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;addParticle(Lnet/minecraft/core/particles/ParticleOptions;DDDDDD)V")) + private void sable$addParticle(final Level instance, final ParticleOptions particleOptions, final double d, final double e, final double f, final double g, final double h, final double i, final Operation original, @Share("localPosition") final LocalRef localPosition, @Local(ordinal = 0) final BlockPos pos) { final SubLevel subLevel = Sable.HELPER.getContaining(this.level, pos); if (subLevel == null) { - instance.addParticle(particleOptions, d, e, f, g, h, i); + original.call(instance, particleOptions, d, e, f, g, h, i); return; } @@ -122,7 +123,7 @@ public abstract class EntityMixin { v = v.subtract(upDir.x * dot, upDir.y * dot, upDir.z * dot).add(upDir.x * 1.5, upDir.y * 1.5, upDir.z * 1.5); } - instance.addParticle(particleOptions, p.x, p.y, p.z, v.x, v.y, v.z); + original.call(instance, particleOptions, p.x, p.y, p.z, v.x, v.y, v.z); } /** diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/entity/entity_leashing/EntityRendererMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/entity_leashing/EntityRendererMixin.java index 1b2de938..6de4f6ac 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/entity/entity_leashing/EntityRendererMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/entity_leashing/EntityRendererMixin.java @@ -1,11 +1,14 @@ package dev.ryanhcode.sable.mixin.entity.entity_leashing; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Local; import dev.ryanhcode.sable.ActiveSableCompanion; import dev.ryanhcode.sable.Sable; import dev.ryanhcode.sable.companion.math.JOMLConversion; import dev.ryanhcode.sable.sublevel.SubLevel; import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.core.Position; import net.minecraft.world.entity.Entity; import net.minecraft.world.phys.Vec3; import org.joml.Vector3d; @@ -16,12 +19,12 @@ @Mixin(EntityRenderer.class) public class EntityRendererMixin { - @Redirect(method = "renderLeash", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;getRopeHoldPosition(F)Lnet/minecraft/world/phys/Vec3;")) - private Vec3 sable$getRopeHoldPosition(final Entity instance, final float f, @Local(argsOnly = true, ordinal = 0) final Entity leashedEntity){ + @WrapOperation(method = "renderLeash", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;getRopeHoldPosition(F)Lnet/minecraft/world/phys/Vec3;")) + private Vec3 sable$getRopeHoldPosition(final Entity instance, final float f, final Operation original, @Local(argsOnly = true, ordinal = 0) final Entity leashedEntity){ final ActiveSableCompanion helper = Sable.HELPER; final SubLevel leashedSubLevel = helper.getContaining(leashedEntity); - final Vector3d ropeHoldPosition = JOMLConversion.toJOML(instance.getRopeHoldPosition(f)); + final Vector3d ropeHoldPosition = JOMLConversion.toJOML(original.call(instance, f)); final SubLevel holdingSubLevel = helper.getContaining(leashedEntity.level(), ropeHoldPosition); if (holdingSubLevel != null) { @@ -35,12 +38,12 @@ public class EntityRendererMixin { return JOMLConversion.toMojang(ropeHoldPosition); } - @Redirect(method = "renderLeash", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;getEyePosition(F)Lnet/minecraft/world/phys/Vec3;")) - private Vec3 sable$getEyePosition(final Entity instance, final float f, @Local(argsOnly = true, ordinal = 0) final Entity leashedEntity){ + @WrapOperation(method = "renderLeash", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;getEyePosition(F)Lnet/minecraft/world/phys/Vec3;")) + private Vec3 sable$getEyePosition(final Entity instance, final float f, final Operation original, @Local(argsOnly = true, ordinal = 0) final Entity leashedEntity){ final ActiveSableCompanion helper = Sable.HELPER; final SubLevel leashedSubLevel = helper.getContaining(leashedEntity); - final Vector3d eyePosition = JOMLConversion.toJOML(instance.getEyePosition(f)); + final Vector3d eyePosition = JOMLConversion.toJOML(original.call(instance, f)); final SubLevel holdingSubLevel = helper.getContaining(leashedEntity.level(), eyePosition); if (holdingSubLevel != null) { diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/options/OptionsScreenMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/options/OptionsScreenMixin.java index c5d5d31b..ef59a595 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/options/OptionsScreenMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/options/OptionsScreenMixin.java @@ -1,5 +1,6 @@ package dev.ryanhcode.sable.mixin.options; +import com.llamalad7.mixinextras.injector.ModifyReturnValue; import dev.ryanhcode.sable.config.SubLevelSettingsScreen; import net.minecraft.client.Options; import net.minecraft.client.gui.components.Button; @@ -12,8 +13,6 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; /** * Adds a button to access the sable menu on integrated servers to the {@link OptionsScreen} @@ -27,10 +26,10 @@ protected OptionsScreenMixin(final Component component) { super(component); } - @Inject(method = "createOnlineButton", at = @At("RETURN"), cancellable = true) - public void sable$createSableButton(final CallbackInfoReturnable cir) { + @ModifyReturnValue(method = "createOnlineButton", at = @At("RETURN")) + public LayoutElement sable$createSableButton(final LayoutElement original) { if (this.minecraft.level == null || !this.minecraft.hasSingleplayerServer()) { - return; + return original; } final LinearLayout layout = LinearLayout.vertical(); @@ -39,10 +38,10 @@ protected OptionsScreenMixin(final Component component) { this.minecraft.setScreen(new SubLevelSettingsScreen(this, this.options, SubLevelSettingsScreen.TITLE)); }).pos(0, 30).size(150, 20).build(); - layout.addChild(cir.getReturnValue()); + layout.addChild(original); layout.spacing(5); layout.addChild(sableButton); - cir.setReturnValue(layout); + return original; } diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/player_freezing/LocalPlayerMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/player_freezing/LocalPlayerMixin.java index 8ac46679..ca470c2d 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/player_freezing/LocalPlayerMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/player_freezing/LocalPlayerMixin.java @@ -1,5 +1,7 @@ package dev.ryanhcode.sable.mixin.player_freezing; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.mojang.authlib.GameProfile; import dev.ryanhcode.sable.api.sublevel.SubLevelContainer; import dev.ryanhcode.sable.mixinterface.player_freezing.PlayerFreezeExtension; @@ -21,8 +23,8 @@ public LocalPlayerMixin(final Level level, final BlockPos blockPos, final float super(level, blockPos, f, gameProfile); } - @Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;hasChunkAt(II)Z")) - private boolean sable$freezeTicking(final Level instance, final int x, final int z) { + @WrapOperation(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;hasChunkAt(II)Z")) + private boolean sable$freezeTicking(final Level instance, final int x, final int z, final Operation original) { this.sable$tickStopFreezing(); final UUID uuid = this.sable$getFrozenToSubLevel(); @@ -40,6 +42,6 @@ public LocalPlayerMixin(final Level level, final BlockPos blockPos, final float this.sable$freezeTo(null, null); } - return instance.hasChunkAt(x, z); + return original.call(instance, x, z); } } diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/portal/NetherPortalBlockMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/portal/NetherPortalBlockMixin.java index a9182fd3..9a417001 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/portal/NetherPortalBlockMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/portal/NetherPortalBlockMixin.java @@ -1,5 +1,7 @@ package dev.ryanhcode.sable.mixin.portal; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Local; import dev.ryanhcode.sable.Sable; import dev.ryanhcode.sable.api.SubLevelHelper; @@ -15,18 +17,20 @@ @Mixin(NetherPortalBlock.class) public class NetherPortalBlockMixin { - @Redirect(method = "getPortalDestination", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/border/WorldBorder;clampToBounds(DDD)Lnet/minecraft/core/BlockPos;")) + @WrapOperation(method = "getPortalDestination", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/border/WorldBorder;clampToBounds(DDD)Lnet/minecraft/core/BlockPos;")) private BlockPos sable$getPortalDestination(final WorldBorder instance, final double x, final double y, final double z, + Operation original, @Local(argsOnly = true) final Entity entity, @Local(ordinal = 0) final double multiplier) { final Vec3 position = new Vec3(entity.getX(), entity.getY(), entity.getZ()); final Vec3 globalPos = Sable.HELPER.projectOutOfSubLevel(entity.level(), position); - return instance.clampToBounds( + return original.call( + instance, globalPos.x * multiplier, globalPos.y * multiplier, globalPos.z * multiplier From 6dd2df49c866aba7b154ac0a4e4e646f180f94a0 Mon Sep 17 00:00:00 2001 From: sery Date: Thu, 14 May 2026 19:14:27 +0200 Subject: [PATCH 5/8] a few more --- .../sable/mixin/particle/ParticleEngineMixin.java | 8 ++++---- .../sable/mixin/plot/lighting/LevelChunkMixin.java | 7 ++++--- .../effects/LivingEntityMixin.java | 7 +++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/particle/ParticleEngineMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/particle/ParticleEngineMixin.java index 67705db9..1eceb8fb 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/particle/ParticleEngineMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/particle/ParticleEngineMixin.java @@ -47,8 +47,8 @@ public abstract class ParticleEngineMixin { extension.sable$moveWithInheritedVelocity(); } - @Redirect(method = "crack", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/TerrainParticle;setPower(F)Lnet/minecraft/client/particle/Particle;")) - private Particle sable$addCrackParticle(final TerrainParticle particle, final float v, @Local(argsOnly = true) final BlockPos pos, @Local final BlockState state) { + @WrapOperation(method = "crack", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/TerrainParticle;setPower(F)Lnet/minecraft/client/particle/Particle;")) + private Particle sable$addCrackParticle(final TerrainParticle particle, final float v, final Operation original, @Local(argsOnly = true) final BlockPos pos, @Local final BlockState state) { final Vec3 particlePosition = new Vec3(particle.x, particle.y, particle.z); final SubLevel subLevel = Sable.HELPER.getContaining(this.level, particlePosition); @@ -60,7 +60,7 @@ public abstract class ParticleEngineMixin { particle.yd = globalVelocity.y; particle.zd = globalVelocity.z; - particle.setPower(v); + original.call(particle, v); final Vec3 localVelocity = subLevel.logicalPose().transformNormalInverse(new Vec3(particle.xd, particle.yd, particle.zd)); @@ -71,7 +71,7 @@ public abstract class ParticleEngineMixin { return particle; } else { - return particle.setPower(v); + return original.call(particle, v); } } diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/plot/lighting/LevelChunkMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/plot/lighting/LevelChunkMixin.java index 50deb318..b67b8a3b 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/plot/lighting/LevelChunkMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/plot/lighting/LevelChunkMixin.java @@ -1,5 +1,6 @@ package dev.ryanhcode.sable.mixin.plot.lighting; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import dev.ryanhcode.sable.api.sublevel.SubLevelContainer; import dev.ryanhcode.sable.sublevel.plot.LevelPlot; import net.minecraft.server.level.ServerLevel; @@ -21,8 +22,8 @@ public class LevelChunkMixin { /** * Return the plot light engine if we're in a plot */ - @Redirect(method ="setBlockState", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/ChunkSource;getLightEngine()Lnet/minecraft/world/level/lighting/LevelLightEngine;")) - public LevelLightEngine sable$getLightEngine(final ChunkSource instance) { + @ModifyExpressionValue(method = "setBlockState", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/ChunkSource;getLightEngine()Lnet/minecraft/world/level/lighting/LevelLightEngine;")) + public LevelLightEngine sable$getLightEngine(final LevelLightEngine original) { final SubLevelContainer container = SubLevelContainer.getContainer(this.level); if (container != null && this.level instanceof ServerLevel) { @@ -34,7 +35,7 @@ public class LevelChunkMixin { } } - return instance.getLightEngine(); + return original; } } diff --git a/fabric/src/main/java/dev/ryanhcode/sable/fabric/mixin/entities_stick_sublevels/effects/LivingEntityMixin.java b/fabric/src/main/java/dev/ryanhcode/sable/fabric/mixin/entities_stick_sublevels/effects/LivingEntityMixin.java index a08ce32e..ade75b7b 100644 --- a/fabric/src/main/java/dev/ryanhcode/sable/fabric/mixin/entities_stick_sublevels/effects/LivingEntityMixin.java +++ b/fabric/src/main/java/dev/ryanhcode/sable/fabric/mixin/entities_stick_sublevels/effects/LivingEntityMixin.java @@ -5,7 +5,6 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; @@ -19,8 +18,8 @@ public LivingEntityMixin(final EntityType entityType, final Level level) { /** * Changes the blockpos offset to use getOnPos */ - @Redirect(method = "playBlockFallSound", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;getBlockState(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/block/state/BlockState;")) - private BlockState playBlockFallSound(final Level instance, final BlockPos blockPos) { - return instance.getBlockState(this.getOnPos(0.2f)); + @Redirect(method = "playBlockFallSound", at = @At(value = "NEW", target = "(III)Lnet/minecraft/core/BlockPos;")) + private BlockPos sable$redirectBlockPos(final int x, final int y, final int z) { + return this.getOnPos(0.2f); } } From 9b450245f74c8c7582f9a037c50abd8870395c1c Mon Sep 17 00:00:00 2001 From: sery Date: Thu, 14 May 2026 19:18:35 +0200 Subject: [PATCH 6/8] this one --- .../sable/mixin/particle/TerrainParticleMixin.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/particle/TerrainParticleMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/particle/TerrainParticleMixin.java index 4f552c75..b7387bed 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/particle/TerrainParticleMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/particle/TerrainParticleMixin.java @@ -1,5 +1,7 @@ package dev.ryanhcode.sable.mixin.particle; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Local; import dev.ryanhcode.sable.Sable; import dev.ryanhcode.sable.api.SubLevelHelper; @@ -32,21 +34,21 @@ protected TerrainParticleMixin(final ClientLevel clientLevel, final double d, fi super(clientLevel, d, e, f); } - @Redirect(method = "getLightColor", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/LevelRenderer;getLightColor(Lnet/minecraft/world/level/BlockAndTintGetter;Lnet/minecraft/core/BlockPos;)I")) - private int sable$getLightColor(final BlockAndTintGetter blockAndTintGetter, final BlockPos blockPos, @Local final int existingColor) { + @WrapOperation(method = "getLightColor", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/LevelRenderer;getLightColor(Lnet/minecraft/world/level/BlockAndTintGetter;Lnet/minecraft/core/BlockPos;)I")) + private int sable$getLightColor(final BlockAndTintGetter blockAndTintGetter, final BlockPos blockPos, final Operation original, @Local final int existingColor) { final ClientSubLevelContainer container = SubLevelContainer.getContainer(Minecraft.getInstance().level); assert container != null; final SubLevel subLevel = Sable.HELPER.getContainingClient(this.pos); if (subLevel instanceof final ClientSubLevel clientSubLevel) { - final int color = LevelRenderer.getLightColor(blockAndTintGetter, blockPos); + final int color = original.call(blockAndTintGetter, blockPos); return clientSubLevel.scaleLightColor(color); } else if (container.inBounds(blockPos)) { return existingColor; } - return LevelRenderer.getLightColor(blockAndTintGetter, blockPos); + return original.call(blockAndTintGetter, blockPos); } } From dce6af8f3e0d1d3704b90156e9cd01c00f49ee6a Mon Sep 17 00:00:00 2001 From: sery Date: Thu, 14 May 2026 19:30:56 +0200 Subject: [PATCH 7/8] yet another mrv --- .../mixin/entity/entity_aabb_lookup/LevelsMixin.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/entity/entity_aabb_lookup/LevelsMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/entity_aabb_lookup/LevelsMixin.java index 1ecde680..0cc55da7 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/entity/entity_aabb_lookup/LevelsMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/entity_aabb_lookup/LevelsMixin.java @@ -1,5 +1,6 @@ package dev.ryanhcode.sable.mixin.entity.entity_aabb_lookup; +import com.llamalad7.mixinextras.injector.ModifyReturnValue; import dev.ryanhcode.sable.util.SubLevelInclusiveLevelEntityGetter; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.server.level.ServerLevel; @@ -9,8 +10,6 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Pseudo; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; /** * Wraps the client and server level {@link net.minecraft.world.level.entity.LevelEntityGetterAdapter} in a {@link SubLevelInclusiveLevelEntityGetter} @@ -19,9 +18,9 @@ @Mixin({ServerLevel.class, ClientLevel.class,}) public class LevelsMixin { - @Inject(method = "getEntities()Lnet/minecraft/world/level/entity/LevelEntityGetter;", at = @At("RETURN"), cancellable = true) - private void sable$postGetEntities(final CallbackInfoReturnable> cir) { - cir.setReturnValue(new SubLevelInclusiveLevelEntityGetter<>((Level) (Object) this, cir.getReturnValue())); + @ModifyReturnValue(method = "getEntities()Lnet/minecraft/world/level/entity/LevelEntityGetter;", at = @At("RETURN")) + private LevelEntityGetter sable$postGetEntities(final LevelEntityGetter original) { + return new SubLevelInclusiveLevelEntityGetter<>((Level) (Object) this, original); } } From 79419c55c230d60a9dfdefd75c90c83a067aac16 Mon Sep 17 00:00:00 2001 From: sery Date: Fri, 15 May 2026 00:50:20 +0200 Subject: [PATCH 8/8] apparently order doesn't exist yet --- .../ryanhcode/sable/mixin/clip_overwrite/BlockGetterMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/clip_overwrite/BlockGetterMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/clip_overwrite/BlockGetterMixin.java index f8d1d1a5..24fc1855 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/clip_overwrite/BlockGetterMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/clip_overwrite/BlockGetterMixin.java @@ -35,7 +35,7 @@ public interface BlockGetterMixin { BlockState getBlockState(BlockPos blockPos); // order to make sure this is the innermost wrap - @WrapMethod(method = "clip", order = Integer.MIN_VALUE) + @WrapMethod(method = "clip") default BlockHitResult sable$wrapClip(ClipContext clipContext, final Operation original) { if (!(this instanceof final Level level) || (clipContext instanceof final ClipContextExtension extension && extension.sable$doNotProject())) { // If the level cannot have sublevels, use the original method