From 6cce31434122fb8ad6fe1ecd7f30dfa5e28140e5 Mon Sep 17 00:00:00 2001 From: PeTcHeNkA <60981731+PeTcHeNkA@users.noreply.github.com> Date: Wed, 24 Dec 2025 03:28:09 +0300 Subject: [PATCH 1/3] fix: add fallback skin for invalid CustomNPC texture paths - Add empty string check in skinType 0 else branch - Set textureLocation to fallBackSkin(npc) for invalid textures - Add null safety check before returning textureLocation - Prevents transparent NPCs when invalid paths like "customnpcs:textures/entity/test.png" or "teststring" are used --- .../npcs/client/renderer/RenderNPCInterface.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/noppes/npcs/client/renderer/RenderNPCInterface.java b/src/main/java/noppes/npcs/client/renderer/RenderNPCInterface.java index 2d1d1f258..951bfc84c 100644 --- a/src/main/java/noppes/npcs/client/renderer/RenderNPCInterface.java +++ b/src/main/java/noppes/npcs/client/renderer/RenderNPCInterface.java @@ -536,7 +536,6 @@ protected void renderLivingAt(EntityLivingBase entityliving, double d, double d1 @Override public ResourceLocation getEntityTexture(Entity entity) { - EntityNPCInterface npc = (EntityNPCInterface) entity; if (npc.textureLocation == null) { if (npc.display.skinType == 0) { @@ -548,10 +547,15 @@ public ResourceLocation getEntityTexture(Entity entity) { } } } else { - npc.textureLocation = new ResourceLocation(npc.display.texture); + if (!(npc.display.texture).isEmpty()) { + npc.textureLocation = new ResourceLocation(npc.display.texture); + // TODO: Also validate if this ResourceLocation actually exists + } else { + npc.textureLocation = fallBackSkin(npc); + } } } else if (npc.display.skinType == 1 && npc.display.playerProfile != null) { - Minecraft minecraft = Minecraft.getMinecraft(); + final Minecraft minecraft = Minecraft.getMinecraft(); Map map = minecraft.func_152342_ad().func_152788_a(npc.display.playerProfile); if (map.containsKey(Type.SKIN)) { npc.textureLocation = minecraft.func_152342_ad().func_152792_a((MinecraftProfileTexture) map.get(Type.SKIN), Type.SKIN); @@ -594,7 +598,8 @@ else if (LastTextureTick < 5) { //fixes request flood somewhat return fallBackSkin(npc); } } - return npc.textureLocation; + + return npc.textureLocation == null ? fallBackSkin(npc) : npc.textureLocation; } private ResourceLocation adjustLocalTexture(EntityNPCInterface npc, ResourceLocation location) throws IOException { From 9f30438c4f9b4a770f869555afc3fb914807caa9 Mon Sep 17 00:00:00 2001 From: PeTcHeNkA <60981731+PeTcHeNkA@users.noreply.github.com> Date: Wed, 24 Dec 2025 03:39:33 +0300 Subject: [PATCH 2/3] Validate ResourceLocation existence before assignment in getEntityTexture Previously, skinType==0 branch created a ResourceLocation directly without checking if the resource actually exists. This was inconsistent with adjustLocalTexture(), which probes the ResourceManager and falls back on missing assets. Now we call Minecraft.geMinecraft().getResourceManager().getResource(resLoc) and catch IOException. On failure, we fall back to a valid texture via fallBackSkin(npc), ensuring rendering always uses a valid path and avoiding invalid ResourceLocation assignments. This change aligns behavior across texture loading paths and prevents rendering errors when NPC textures are missing. --- .../client/renderer/RenderNPCInterface.java | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/main/java/noppes/npcs/client/renderer/RenderNPCInterface.java b/src/main/java/noppes/npcs/client/renderer/RenderNPCInterface.java index 951bfc84c..1bc81c672 100644 --- a/src/main/java/noppes/npcs/client/renderer/RenderNPCInterface.java +++ b/src/main/java/noppes/npcs/client/renderer/RenderNPCInterface.java @@ -537,19 +537,28 @@ protected void renderLivingAt(EntityLivingBase entityliving, double d, double d1 @Override public ResourceLocation getEntityTexture(Entity entity) { EntityNPCInterface npc = (EntityNPCInterface) entity; + if (npc.textureLocation == null) { if (npc.display.skinType == 0) { if (npc instanceof EntityCustomNpc && ((EntityCustomNpc) npc).modelData.entityClass == null) { - if (!(npc.display.texture).isEmpty()) { + if (!npc.display.texture.isEmpty()) { try { npc.textureLocation = adjustLocalTexture(npc, new ResourceLocation(npc.display.texture)); } catch (IOException ignored) { + return fallBackSkin(npc); } + } else { + npc.textureLocation = fallBackSkin(npc); } } else { - if (!(npc.display.texture).isEmpty()) { - npc.textureLocation = new ResourceLocation(npc.display.texture); - // TODO: Also validate if this ResourceLocation actually exists + if (!npc.display.texture.isEmpty()) { + ResourceLocation resLoc = new ResourceLocation(npc.display.texture); + try { + Minecraft.getMinecraft().getResourceManager().getResource(resLoc); + npc.textureLocation = resLoc; + } catch (IOException e) { + return fallBackSkin(npc); + } } else { npc.textureLocation = fallBackSkin(npc); } @@ -563,28 +572,29 @@ public ResourceLocation getEntityTexture(Entity entity) { LastTextureTick = 0; } else if (npc.display.skinType == 2 || npc.display.skinType == 3) { ResourceLocation location = new ResourceLocation("skins/" + (npc.display.skinType + npc.display.url).hashCode()); - // If URL Empty Steve - if (npc.display.url.isEmpty()) { + if (npc.display.url.isEmpty()) { // If URL Empty Steve return fallBackSkin(npc); - } - // If URL Cached then grab it - else if (ClientCacheHandler.isCachedNPC(location)) { + } else if (ClientCacheHandler.isCachedNPC(location)) { // If URL Cached then grab it try { - ResourceLocation loc = ClientCacheHandler.getNPCTexture(npc.display.url, npc.display.skinType == 3, location).getLocation(); + ResourceLocation loc = ClientCacheHandler + .getNPCTexture(npc.display.url, npc.display.skinType == 3, location) + .getLocation(); if (loc != null) { npc.textureLocation = loc; } else { return fallBackSkin(npc); } } catch (Exception ignored) { + return fallBackSkin(npc); } - } // For New URL Requests do not spam it - else if (LastTextureTick < 5) { //fixes request flood somewhat + } else if (LastTextureTick < 5) { //fixes request flood somewhat return fallBackSkin(npc); } else { try { - ResourceLocation loc = ClientCacheHandler.getNPCTexture(npc.display.url, npc.display.skinType == 3, location).getLocation(); + ResourceLocation loc = ClientCacheHandler + .getNPCTexture(npc.display.url, npc.display.skinType == 3, location) + .getLocation(); if (loc != null) { npc.textureLocation = loc; } else { @@ -592,6 +602,7 @@ else if (LastTextureTick < 5) { //fixes request flood somewhat } LastTextureTick = 0; } catch (Exception ignored) { + return fallBackSkin(npc); } } } else { From 6e2fe788d23a3ebac9adcb45785896ac77d2c90e Mon Sep 17 00:00:00 2001 From: PeTcHeNkA <60981731+PeTcHeNkA@users.noreply.github.com> Date: Wed, 24 Dec 2025 03:50:03 +0300 Subject: [PATCH 3/3] Improve readability in getEntityTexture#RenderNPCInterface --- .../client/renderer/RenderNPCInterface.java | 129 +++++++++--------- 1 file changed, 64 insertions(+), 65 deletions(-) diff --git a/src/main/java/noppes/npcs/client/renderer/RenderNPCInterface.java b/src/main/java/noppes/npcs/client/renderer/RenderNPCInterface.java index 1bc81c672..2e4273816 100644 --- a/src/main/java/noppes/npcs/client/renderer/RenderNPCInterface.java +++ b/src/main/java/noppes/npcs/client/renderer/RenderNPCInterface.java @@ -537,79 +537,78 @@ protected void renderLivingAt(EntityLivingBase entityliving, double d, double d1 @Override public ResourceLocation getEntityTexture(Entity entity) { EntityNPCInterface npc = (EntityNPCInterface) entity; - - if (npc.textureLocation == null) { - if (npc.display.skinType == 0) { + + // Early exit if texture already resolved + if (npc.textureLocation != null) { + return npc.textureLocation; + } + + // SkinType 0: custom texture or default + if (npc.display.skinType == 0) { + if (npc.display.texture.isEmpty()) { + return npc.textureLocation = fallBackSkin(npc); + } + + try { if (npc instanceof EntityCustomNpc && ((EntityCustomNpc) npc).modelData.entityClass == null) { - if (!npc.display.texture.isEmpty()) { - try { - npc.textureLocation = adjustLocalTexture(npc, new ResourceLocation(npc.display.texture)); - } catch (IOException ignored) { - return fallBackSkin(npc); - } - } else { - npc.textureLocation = fallBackSkin(npc); - } + npc.textureLocation = adjustLocalTexture(npc, new ResourceLocation(npc.display.texture)); } else { - if (!npc.display.texture.isEmpty()) { - ResourceLocation resLoc = new ResourceLocation(npc.display.texture); - try { - Minecraft.getMinecraft().getResourceManager().getResource(resLoc); - npc.textureLocation = resLoc; - } catch (IOException e) { - return fallBackSkin(npc); - } - } else { - npc.textureLocation = fallBackSkin(npc); - } + ResourceLocation resLoc = new ResourceLocation(npc.display.texture); + Minecraft.getMinecraft().getResourceManager().getResource(resLoc); + npc.textureLocation = resLoc; } - } else if (npc.display.skinType == 1 && npc.display.playerProfile != null) { - final Minecraft minecraft = Minecraft.getMinecraft(); - Map map = minecraft.func_152342_ad().func_152788_a(npc.display.playerProfile); - if (map.containsKey(Type.SKIN)) { - npc.textureLocation = minecraft.func_152342_ad().func_152792_a((MinecraftProfileTexture) map.get(Type.SKIN), Type.SKIN); - } - LastTextureTick = 0; - } else if (npc.display.skinType == 2 || npc.display.skinType == 3) { - ResourceLocation location = new ResourceLocation("skins/" + (npc.display.skinType + npc.display.url).hashCode()); - if (npc.display.url.isEmpty()) { // If URL Empty Steve - return fallBackSkin(npc); - } else if (ClientCacheHandler.isCachedNPC(location)) { // If URL Cached then grab it - try { - ResourceLocation loc = ClientCacheHandler - .getNPCTexture(npc.display.url, npc.display.skinType == 3, location) - .getLocation(); - if (loc != null) { - npc.textureLocation = loc; - } else { - return fallBackSkin(npc); - } - } catch (Exception ignored) { - return fallBackSkin(npc); - } - // For New URL Requests do not spam it - } else if (LastTextureTick < 5) { //fixes request flood somewhat - return fallBackSkin(npc); + } catch (IOException ignored) { + return fallBackSkin(npc); + } + } + + // SkinType 1: player profile skin + else if (npc.display.skinType == 1 && npc.display.playerProfile != null) { + final Minecraft minecraft = Minecraft.getMinecraft(); + Map map = minecraft.func_152342_ad().func_152788_a(npc.display.playerProfile); + if (map.containsKey(Type.SKIN)) { + npc.textureLocation = minecraft.func_152342_ad() + .func_152792_a((MinecraftProfileTexture) map.get(Type.SKIN), Type.SKIN); + } + LastTextureTick = 0; + } + + // SkinType 2 / 3: load from URL + else if (npc.display.skinType == 2 || npc.display.skinType == 3) { + if (npc.display.url.isEmpty()) { // If URL is empty → fallback + return fallBackSkin(npc); + } + + ResourceLocation location = new ResourceLocation("skins/" + (npc.display.skinType + npc.display.url).hashCode()); + + try { + if (ClientCacheHandler.isCachedNPC(location)) { // If URL is cached + ResourceLocation loc = ClientCacheHandler + .getNPCTexture(npc.display.url, npc.display.skinType == 3, location) + .getLocation(); + if (loc == null) return fallBackSkin(npc); + npc.textureLocation = loc; + } else if (LastTextureTick >= 5) { // Prevent request flooding + ResourceLocation loc = ClientCacheHandler + .getNPCTexture(npc.display.url, npc.display.skinType == 3, location) + .getLocation(); + if (loc == null) return fallBackSkin(npc); + npc.textureLocation = loc; + LastTextureTick = 0; } else { - try { - ResourceLocation loc = ClientCacheHandler - .getNPCTexture(npc.display.url, npc.display.skinType == 3, location) - .getLocation(); - if (loc != null) { - npc.textureLocation = loc; - } else { - return fallBackSkin(npc); - } - LastTextureTick = 0; - } catch (Exception ignored) { - return fallBackSkin(npc); - } + return fallBackSkin(npc); } - } else { + } catch (Exception ignored) { return fallBackSkin(npc); } } - + + // Fallback: if no valid skin type matched + else { + return fallBackSkin(npc); + } + + // Final safety net return npc.textureLocation == null ? fallBackSkin(npc) : npc.textureLocation; }