Fuzss / overflowingbars

Expand health, armor and armor toughness bars beyond vanilla. Nice and compact without confusing colors.
https://www.curseforge.com/minecraft/mc-mods/overflowing-bars
Mozilla Public License 2.0
0 stars 4 forks source link

[Suggestion]: Make the class `HealthBarRenderer.ModHeartType` public #30

Open TheDeathlyCow opened 1 month ago

TheDeathlyCow commented 1 month ago

Mod Loader (Optional)

Fabric

Minecraft Version(s) (Optional)

1.21.1

Mod Version(s) (Optional)

v21.1.1-1.21.1-Fabric

Suggestion (Required)

TL;DR: I need the HealthBarRenderer.ModHeartType class to be made public so that I can mixin to the health bar renderer without using weird workarounds.

I am working on updating a compatibility patch between Overflowing Bars and Frostiful/Scorchful that allows for temperature information to be rendered on the player health like normal again. This patch is provided along side several other similar patches for similar mods in Thermoo Patches. This patch is "optional" with Thermoo Patches, meaning that players who use Thermoo Patches arent required to also have Overflowing Bars (but it will provide the functionality if they have Overflowing Bars).

Part of this patch involves mixins to your health bar renderer to capture the position information I need for my render event. However, I've encountered a problem when updating to 1.21 where the class HealthBarRenderer.ModHeartType is package-private, and therefore I cannot access it from my mixin package. With normal vanilla classes, this isn't a problem - just use an accesswidener to open up the class. However, the specific requirement of this mod being an optional integration with Thermoo Patches means this does not work - as adding the accesswidener will force players to use Overflowing Bars with Thermoo Patches (in fact, it will not even apply the access widener in my dev enviornment since I specify the Overflowing Bars dependency as compile only and not as an implementation). There might be a way to work around this, but it probably would not work as well, and would be far less stable than it already is (also it would just be really messy and messy code makes me sad).

lot of yapping for requesting a one word change lol

Fuzss commented 1 month ago

For the mixin target or anything else? For the Mixin target you can do this for an unaccessible class:

@Mixin(targets = "fuzs.overflowingbars.client.gui.HealthBarRenderer$ModHeartType")
TheDeathlyCow commented 1 month ago

it's for a wrap operation within the a health bar renderer mixin that requires the heart type as a parameter. afaik no way to make it work without the class being public.

Fuzss commented 1 month ago

Try to set the parameter as @Coerce Object heartType, that should work.

TheDeathlyCow commented 1 month ago

In the dev environment, it does not show a compiler error when I use @Coerce. But, when I run it in production theres a mixin failure. I'm not sure exactly what's causing the failure, but an education guess might be that coercing the instance class instead of a parameter is the reason for the failure.

For reference, this is my mixin class:

@Environment(EnvType.CLIENT)
@Mixin(
        value = HealthBarRenderer.class,
        remap = false
)
public class HealthBarRendererMixin {

    @Unique
    private final ThreadLocal<Integer> thermoo_patches$currentHeart = ThreadLocal.withInitial(() -> 0);

    @WrapOperation(
            method = "renderHearts",
            at = @At(
                    value = "INVOKE",
                    target = "Lfuzs/overflowingbars/client/gui/HealthBarRenderer$ModHeartType;renderHeart(Lnet/minecraft/client/gui/DrawContext;IIZZZ)V",
                    ordinal = 0)
    )
    private void captureHeartPosition(
            @Coerce Object instance,
            DrawContext guiGraphics,
            int posX, int posY,
            boolean blinking,
            boolean halfHeart,
            boolean hardcore,
            Operation<Void> original
    ) {
        int index = thermoo_patches$currentHeart.get();
        HeartOverlayRecorder.INSTANCE.setHeartPosition(index, posX, posY);
        thermoo_patches$currentHeart.set(index + 1);

        original.call(instance, guiGraphics, posX, posY, blinking, halfHeart, hardcore);
    }

    @Inject(
            method = "renderHearts",
            at = @At("TAIL")
    )
    private void renderOverlayBar(
            DrawContext guiGraphics,
            PlayerEntity player,
            int posX, int posY,
            int heartOffsetByRegen,
            float maxHealth,
            int currentHealth,
            int displayHealth,
            int currentAbsorptionHealth,
            boolean blink,
            CallbackInfo ci
    ) {
        StatusBarOverlayRenderEvents.AFTER_HEALTH_BAR.invoker()
                .render(
                        guiGraphics,
                        player,
                        HeartOverlayRecorder.INSTANCE.getHeartPositions(),
                        displayHealth,
                        20
                );
        Arrays.fill(HeartOverlayRecorder.INSTANCE.getHeartPositions(), null);
        thermoo_patches$currentHeart.remove();
    }

}

and this is the exception stacktrace in prod:

[10/10/2024 17:54:17 pm] java.lang.RuntimeException: Could not execute entrypoint stage 'client' due to errors, provided by 'overflowingbars' at 'fuzs.overflowingbars.fabric.client.OverflowingBarsFabricClient'!
[10/10/2024 17:54:17 pm]    at net.fabricmc.loader.impl.FabricLoaderImpl.lambda$invokeEntrypoints$2(FabricLoaderImpl.java:403)
[10/10/2024 17:54:17 pm]    at net.fabricmc.loader.impl.util.ExceptionUtil.gatherExceptions(ExceptionUtil.java:33)
[10/10/2024 17:54:17 pm]    at net.fabricmc.loader.impl.FabricLoaderImpl.invokeEntrypoints(FabricLoaderImpl.java:401)
[10/10/2024 17:54:17 pm]    at net.fabricmc.loader.impl.game.minecraft.Hooks.startClient(Hooks.java:53)
[10/10/2024 17:54:17 pm]    at knot//net.minecraft.class_310.<init>(class_310.java:477)
[10/10/2024 17:54:17 pm]    at knot//net.minecraft.client.main.Main.main(Main.java:239)
[10/10/2024 17:54:17 pm]    at net.fabricmc.loader.impl.game.minecraft.MinecraftGameProvider.launch(MinecraftGameProvider.java:480)
[10/10/2024 17:54:17 pm]    at net.fabricmc.loader.impl.launch.knot.Knot.launch(Knot.java:74)
[10/10/2024 17:54:17 pm]    at net.fabricmc.loader.impl.launch.knot.KnotClient.main(KnotClient.java:23)
[10/10/2024 17:54:17 pm] Caused by: java.lang.RuntimeException: Mixin transformation of fuzs.overflowingbars.client.gui.HealthBarRenderer failed
[10/10/2024 17:54:17 pm]    at net.fabricmc.loader.impl.launch.knot.KnotClassDelegate.getPostMixinClassByteArray(KnotClassDelegate.java:427)
[10/10/2024 17:54:17 pm]    at net.fabricmc.loader.impl.launch.knot.KnotClassDelegate.tryLoadClass(KnotClassDelegate.java:323)
[10/10/2024 17:54:17 pm]    at net.fabricmc.loader.impl.launch.knot.KnotClassDelegate.loadClass(KnotClassDelegate.java:218)
[10/10/2024 17:54:17 pm]    at net.fabricmc.loader.impl.launch.knot.KnotClassLoader.loadClass(KnotClassLoader.java:119)
[10/10/2024 17:54:17 pm]    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)
[10/10/2024 17:54:17 pm]    at knot//fuzs.overflowingbars.client.OverflowingBarsClient.registerEventHandlers(OverflowingBarsClient.java:20)
[10/10/2024 17:54:17 pm]    at knot//fuzs.overflowingbars.client.OverflowingBarsClient.onConstructMod(OverflowingBarsClient.java:16)
[10/10/2024 17:54:17 pm]    at knot//fuzs.puzzleslib.fabric.impl.client.core.FabricClientModConstructor.construct(FabricClientModConstructor.java:37)
[10/10/2024 17:54:17 pm]    at knot//fuzs.puzzleslib.fabric.impl.client.core.FabricClientFactories.constructClientMod(FabricClientFactories.java:17)
[10/10/2024 17:54:17 pm]    at knot//fuzs.puzzleslib.api.client.core.v1.ClientModConstructor.lambda$construct$0(ClientModConstructor.java:48)
[10/10/2024 17:54:17 pm]    at knot//fuzs.puzzleslib.impl.core.ModContext.scheduleClientModConstruction(ModContext.java:109)
[10/10/2024 17:54:17 pm]    at knot//fuzs.puzzleslib.api.client.core.v1.ClientModConstructor.construct(ClientModConstructor.java:44)
[10/10/2024 17:54:17 pm]    at knot//fuzs.overflowingbars.fabric.client.OverflowingBarsFabricClient.onInitializeClient(OverflowingBarsFabricClient.java:14)
[10/10/2024 17:54:17 pm]    at net.fabricmc.loader.impl.FabricLoaderImpl.invokeEntrypoints(FabricLoaderImpl.java:399)
[10/10/2024 17:54:17 pm]    ... 6 more
[10/10/2024 17:54:17 pm] Caused by: org.spongepowered.asm.mixin.transformer.throwables.MixinTransformerError: An unexpected critical error was encountered
[10/10/2024 17:54:17 pm]    at org.spongepowered.asm.mixin.transformer.MixinProcessor.applyMixins(MixinProcessor.java:392)
[10/10/2024 17:54:17 pm]    at org.spongepowered.asm.mixin.transformer.MixinTransformer.transformClass(MixinTransformer.java:234)
[10/10/2024 17:54:17 pm]    at org.spongepowered.asm.mixin.transformer.MixinTransformer.transformClassBytes(MixinTransformer.java:202)
[10/10/2024 17:54:17 pm]    at net.fabricmc.loader.impl.launch.knot.KnotClassDelegate.getPostMixinClassByteArray(KnotClassDelegate.java:422)
[10/10/2024 17:54:17 pm]    ... 19 more
[10/10/2024 17:54:17 pm] Caused by: org.spongepowered.asm.mixin.injection.throwables.InjectionError: Critical injection failure: Callback method captureHeartPosition(Ljava/lang/Object;Lnet/minecraft/class_332;IIZZZLcom/llamalad7/mixinextras/injector/wrapoperation/Operation;)V in thermoo-patches.client.mixins.json:compat.overflowingbars.present.HealthBarRendererMixin from mod thermoo-patches failed injection check, (0/1) succeeded. Scanned 0 target(s). Using refmap client-thermoo-patches-refmap.json
[10/10/2024 17:54:17 pm]    at org.spongepowered.asm.mixin.injection.struct.InjectionInfo.postInject(InjectionInfo.java:531)
[10/10/2024 17:54:17 pm]    at knot//com.llamalad7.mixinextras.injector.MixinExtrasLateInjectionInfo.latePostInject(MixinExtrasLateInjectionInfo.java:57)
[10/10/2024 17:54:17 pm]    at knot//com.llamalad7.mixinextras.injector.LateInjectionApplicatorExtension.postApply(LateInjectionApplicatorExtension.java:43)
[10/10/2024 17:54:17 pm]    at org.spongepowered.asm.mixin.transformer.ext.Extensions.postApply(Extensions.java:167)
[10/10/2024 17:54:17 pm]    at org.spongepowered.asm.mixin.transformer.TargetClassContext.postApply(TargetClassContext.java:448)
[10/10/2024 17:54:17 pm]    at org.spongepowered.asm.mixin.transformer.TargetClassContext.applyMixins(TargetClassContext.java:420)
[10/10/2024 17:54:17 pm]    at org.spongepowered.asm.mixin.transformer.MixinProcessor.applyMixins(MixinProcessor.java:363)
[10/10/2024 17:54:17 pm]    ... 22 more
TheDeathlyCow commented 1 month ago

ok maybe im a bit silly actually, removing the remap=false from the mixin class annotation made it work. also using @Local with a name works fine i think, shouldnt be very brittle (assuming you dont change the names of the local variables often lol)

TheDeathlyCow commented 1 month ago

Ok I have my patch working again. There seemed to be a weird quirk in it though where it would seem overflowing bars would render an additional set of hearts on top of what it renders normally? So it appeared as if my temperature overlay was rendering under the hearts, even though I invoked my overlay render event from the tail of render player hearts. But, when I switched to using the HUD render event in Fabric it renders them just fine on top. Not sure if thats a bug in OB/Puzzles lib but seems kinda weird.