Implement the Ref interfaces explicitly in their mixins

Several mixins implemented a Ref method only through a vanilla method
of the same name. Released jars rename vanilla methods to intermediary
names, so those Ref methods had no implementation there and threw
AbstractMethodError: the armour display's durability, the status
effects' icon and infinite checks, the SVG texture size and the
pre-1.21.6 matrix stack's push and pop. With Mojang's names the same
happens in development (1.21.4 crashed on the title screen).

Each mixin now shadows the vanilla method and implements the Ref
method by calling it. Points common at the Ref renames this needs.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-09-30 17:42:48 +02:00
co-authored by claude
parent af27907356
commit 09bc223b8b
6 changed files with 65 additions and 2 deletions
+2
View File
@@ -18,6 +18,8 @@ Every version is built with Mojang's official names (`loom.officialMojangMapping
Mojang renamed a few classes within 1.21.x. `src/` uses the newest names, and `stonecutter.gradle.kts` lists replacements that swap in the older name when Stonecutter processes an older version (for example `Identifier`, which was `ResourceLocation` before 1.21.11, and `AvatarRenderState`, which was `PlayerRenderState` before 1.21.9). Add a replacement there when a rename touches many lines. A class that only moved package needs just a version comment on its import, and a renamed method a version comment where it's called.
Released jars run on intermediary names (`method_1234`), not Mojang's, and Loom renames everything that refers to Minecraft when it builds them. So a mixin can't implement one of `common`'s Ref interfaces by relying on a vanilla method that happens to have the same name: the vanilla method is renamed in the jar, and the interface method is left without an implementation (`AbstractMethodError`). Shadow the vanilla method and implement the Ref method explicitly, as `WindowMixin` does. For the same reason, Ref methods mustn't share a name and parameters with a method of the class they're mixed into, or the mixin replaces the vanilla method in development.
## Version-specific code with Stonecutter
The code in `src/` is always plain Java for the **active** version (1.21.11, set in `stonecutter.gradle.kts`). Code for other versions sits in comments that Stonecutter swaps before building each version:
+1 -1
Submodule common updated: b0d75af8c4...a6a324a61a
@@ -16,4 +16,20 @@ public abstract class ItemStackMixin implements ItemStackRef {
@Shadow
public abstract int getDamageValue();
// ItemStackRef's methods delegate to ItemStack's, whose names production renames.
@Override
public boolean isEmptyStack() {
return isEmpty();
}
@Override
public int getMaxItemDamage() {
return getMaxDamage();
}
@Override
public int getItemDamage() {
return getDamageValue();
}
}
@@ -44,6 +44,17 @@ import com.mojang.math.Axis;
//? if <1.21.5
//public abstract void rotateAround(Quaternionf quaternion, float originX, float originY, float originZ);
// MatrixStackRef's methods delegate to PoseStack's, whose names production renames.
@Override
public void push() {
pushPose();
}
@Override
public void pop() {
popPose();
}
@Override
public void translate(float x, float y) {
translate(x, y, 0);
@@ -29,6 +29,17 @@ public abstract class StatusEffectMixin implements EffectRef {
@Shadow
public abstract Holder<MobEffect> getEffect();
// EffectRef's methods delegate to MobEffectInstance's, whose names production renames.
@Override
public boolean shouldShowIcon() {
return showIcon();
}
@Override
public boolean isInfinite() {
return isInfiniteDuration();
}
@Override
public SpriteRef getIcon() {
// 1.21.9 changed the GUI atlas, so newer versions draw the effect's texture (getIconId) instead.
@@ -1,10 +1,11 @@
package org.saturnclient.impl.mixins;
import com.mojang.blaze3d.platform.Window;
import org.saturnclient.common.ref.render.WindowRef;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import com.mojang.blaze3d.platform.Window;
@Mixin(Window.class)
public abstract class WindowMixin implements WindowRef {
@Shadow
@@ -13,9 +14,31 @@ public abstract class WindowMixin implements WindowRef {
@Shadow
public abstract int getScreenHeight();
// The framebuffer's size
@Shadow
public abstract int getWidth();
@Shadow
public abstract int getHeight();
// WindowRef's methods delegate to Window's, whose names production renames.
@Override
public int getWindowWidth() {
return getScreenWidth();
}
@Override
public int getWindowHeight() {
return getScreenHeight();
}
@Override
public int getFramebufferWidth() {
return getWidth();
}
@Override
public int getFramebufferHeight() {
return getHeight();
}
}