Luke100000 / ImmersiveArmors

Unique vanilla-friendly armor sets for Minecraft

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[1.19.2-Fabric] Rare crash within modpacks with Cosmetic Armor

TelepathicGrunt opened this issue · comments

Hello, a user approached me saying that when wearing my mod Bumblezone's armor and then putting on another armor in the cosmetic slot provided by Cosmetic Armor, they would crash. The stacktrack seems to ultimately lead to Immersive Armor's mixin which brings me here. The modpack the user was playing on was Medieval Minecraft Fabric 1.19.2. I was not able to figure out the exact conditions for the crash but even then, a null check should fix this on Immersive Armor's side.

The mapped stacktrace of the crash provided to me:

java.lang.NullPointerException: Cannot invoke "net.minecraft.item.ItemStack.getItem()" because "this.equippedStack" is null
	at net.minecraft.client.render.entity.feature.ArmorFeatureRenderer.handler$gko000$injectRenderArmorParts(ArmorFeatureRenderer.java:6044)
	at net.minecraft.client.render.entity.feature.ArmorFeatureRenderer.renderArmorParts(ArmorFeatureRenderer.java)
	at net.minecraft.client.render.entity.feature.ArmorFeatureRenderer.cosmeticarmor$renderArmor(ArmorFeatureRenderer.java:615)
	at net.minecraft.client.render.entity.feature.ArmorFeatureRenderer.mdfdcc2c$lambda$renderCustomArmor$1$0(ArmorFeatureRenderer.java:569)
	at java.base/java.lang.Iterable.forEach(Iterable.java:75)
	at net.minecraft.client.render.entity.feature.ArmorFeatureRenderer.handler$dop000$renderDelayed(ArmorFeatureRenderer.java:580)
	at net.minecraft.client.render.entity.feature.ArmorFeatureRenderer.render(ArmorFeatureRenderer.java:39)
	at net.minecraft.client.render.entity.feature.ArmorFeatureRenderer.render(ArmorFeatureRenderer.java:22)
	at net.minecraft.client.render.entity.LivingEntityRenderer.redirect$zmo000$preventFeatureRendering(LivingEntityRenderer.java:1063)
	at net.minecraft.client.render.entity.LivingEntityRenderer.render(LivingEntityRenderer.java:145)
	at net.minecraft.client.render.entity.PlayerEntityRenderer.render(PlayerEntityRenderer.java:63)
	at net.minecraft.client.render.entity.PlayerEntityRenderer.render(PlayerEntityRenderer.java:41)
	at net.minecraft.client.render.entity.EntityRenderDispatcher.render(EntityRenderDispatcher.java:141)
	at net.minecraft.client.gui.screen.ingame.InventoryScreen.method_29977(InventoryScreen.java:152)
	at com.mojang.blaze3d.systems.RenderSystem.runAsFancy(RenderSystem.java:1171)
	at net.minecraft.client.gui.screen.ingame.InventoryScreen.drawEntity(InventoryScreen.java:152)
	at net.minecraft.client.gui.screen.ingame.InventoryScreen.drawBackground(InventoryScreen.java:110)
	at net.minecraft.client.gui.screen.ingame.HandledScreen.render(HandledScreen.java:100)
	at net.minecraft.client.gui.screen.ingame.AbstractInventoryScreen.render(AbstractInventoryScreen.java:27)
	at net.minecraft.client.gui.screen.ingame.InventoryScreen.render(InventoryScreen.java:90)
	at net.minecraft.client.render.GameRenderer.render(GameRenderer.java:881)
	at net.minecraft.client.MinecraftClient.render(MinecraftClient.java:1177)
	at net.minecraft.client.MinecraftClient.run(MinecraftClient.java:768)
	at net.minecraft.client.main.Main.main(Main.java:244)
	at net.minecraft.client.main.Main.main(Main.java:51)
	at net.fabricmc.loader.impl.game.minecraft.MinecraftGameProvider.launch(MinecraftGameProvider.java:461)
	at net.fabricmc.loader.impl.launch.knot.Knot.launch(Knot.java:74)
	at net.fabricmc.loader.impl.launch.knot.KnotClient.main(KnotClient.java:23)

The mixin that is crashing is this on in Immersive Armors

if (!Main.FORGE && equippedStack.getItem() == item && item instanceof ExtendedArmorItem armorItem) {

Now there's a few thing here that I would like to provide advice on for best practice. The first is when adding new fields in mixins like tickDelta, equippedStack, and entity, You should always annotate these fields with Unique and prefix them with your modid so they do not conflict with another mod's mixin that tries to add the same fields with same names. So those field should be:

    @Unique
    float immersivearmors$tickDelta;
    @Unique
    ItemStack immersivearmors$equippedStack;
    @Unique
    T immersivearmors$entity;

The second advice is all these mixin methods that aren't invokers or accessors should have your modid prefixed as well so that your modid shows up in stacktraces. This lets users be able to report problems to you much easier. So instead of void injectRenderArmorParts(, it should be void immersivearmors$injectRenderArmorParts( and same for all the other mixins.

Now for fixing the actual crash, just throw in a immersivearmors$equippedStack != null check before trying to call its methods and hopefully that should be enough. Though not sure why it was null in the first place but it could be due to immersivearmors$equippedStack not getting assigned a value in the first place?

Edit: It seems cosmetic armor may be at fault or something along the rendering pipeline. Got a crash but pointing to a different mod when using cosmetic armor slot. And this user doesn't show immersive armors in stacktrace. apace100/cosmetic-armor#23

After talking with another dev here:
emilyploszaj/trinkets#228 (comment)

The issue is renderArmor mixin here is prevented from running due to Cosmetic Armor's inject cancel mixin that's at 800 priority. They had to do this to bypass Fabric API's inject cancel that is running at head.

private ItemStack fetchItemStack(ItemStack itemStack) {

A solution could be to change this Immersive Armors mixin to be an inject at head at 700 or higher priority (lower number) and do entity.getEquippedStack(armorSlot) right away to get your itemstack you need and let Cosmetic Armor run afterwards safely.

Thanks for the advice and solution, I will implement and test this asap!

I wasn't able to reconstruct the crash, so I added both the priority fix and null checks. Thanks again for your help, @TelepathicGrunt !