From c6e361f8e6a5cb94f902774cc94eab075b97d1cc Mon Sep 17 00:00:00 2001 From: KAMKEEL <28842281+KAMKEEL@users.noreply.github.com> Date: Tue, 11 Aug 2026 05:56:08 -0400 Subject: [PATCH] Register inventory tabs from the client proxy, not the mod class Deferring registration to loadComplete is right - TConstruct needs to have registered first - but naming TabRegistry and the tab classes in CustomNpcs put client-only GUI types in a class the server loads, which the verifier resolves at link time regardless of any runtime side check. A proxy hook keeps them in ClientProxy while still running at the same point. --- src/main/java/noppes/npcs/CommonProxy.java | 8 ++++++++ src/main/java/noppes/npcs/CustomNpcs.java | 17 ++++------------- .../java/noppes/npcs/client/ClientProxy.java | 13 +++++++++++++ 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/main/java/noppes/npcs/CommonProxy.java b/src/main/java/noppes/npcs/CommonProxy.java index 6229b0f4e..0c60d14ac 100644 --- a/src/main/java/noppes/npcs/CommonProxy.java +++ b/src/main/java/noppes/npcs/CommonProxy.java @@ -225,6 +225,14 @@ public class CommonProxy implements IGuiHandler { public void buildPackageIndex() { } + /** + * Called from the mod's FMLLoadCompleteEvent, after every other mod has finished loading. + * Anything that has to observe another mod's registrations belongs here rather than in + * load(), and it stays on the proxy so client-only types never reach the server. + */ + public void loadComplete() { + } + public boolean isScriptingEnabled() { return ConfigScript.ScriptingEnabled; } diff --git a/src/main/java/noppes/npcs/CustomNpcs.java b/src/main/java/noppes/npcs/CustomNpcs.java index 65f4a00a0..7274a490e 100644 --- a/src/main/java/noppes/npcs/CustomNpcs.java +++ b/src/main/java/noppes/npcs/CustomNpcs.java @@ -64,7 +64,6 @@ import nikedemos.markovnames.generators.MarkovSlavic; import nikedemos.markovnames.generators.MarkovSpanish; import nikedemos.markovnames.generators.MarkovWelsh; import noppes.npcs.compat.PixelmonHelper; -import noppes.npcs.config.ConfigClient; import noppes.npcs.config.ConfigMain; import noppes.npcs.config.LoadConfiguration; import noppes.npcs.config.legacy.LegacyConfig; @@ -120,9 +119,6 @@ import noppes.npcs.entity.old.EntityNpcNagaMale; import noppes.npcs.entity.old.EntityNpcSkeleton; import noppes.npcs.scripted.NpcAPI; import somehussar.janino.AdvancedClassFilter; -import tconstruct.client.tabs.InventoryTabCustomNpc; -import tconstruct.client.tabs.InventoryTabVanilla; -import tconstruct.client.tabs.TabRegistry; import java.io.File; import java.util.HashSet; @@ -347,15 +343,10 @@ public class CustomNpcs { @EventHandler public void loadComplete(FMLLoadCompleteEvent ev) { - if (ev.getSide().isClient()) { - if (ConfigClient.InventoryGuiEnabled) { - MinecraftForge.EVENT_BUS.register(new TabRegistry()); - if (TabRegistry.getTabList().isEmpty()) { - TabRegistry.registerTab(new InventoryTabVanilla()); - } - TabRegistry.registerTab(new InventoryTabCustomNpc()); - } - } + // Runs after every other mod has loaded. Kept on the proxy: the client side registers + // inventory tabs, and naming those types here would drag client-only GUI classes into + // a class the server loads. + proxy.loadComplete(); proxy.buildPackageIndex(); // Load built-in animations on the client so they're available for ability preview. diff --git a/src/main/java/noppes/npcs/client/ClientProxy.java b/src/main/java/noppes/npcs/client/ClientProxy.java index b1d1127ba..ca39262d7 100644 --- a/src/main/java/noppes/npcs/client/ClientProxy.java +++ b/src/main/java/noppes/npcs/client/ClientProxy.java @@ -854,6 +854,19 @@ public class ClientProxy extends CommonProxy { return Minecraft.getMinecraft().currentScreen != null; } + @Override + public void loadComplete() { + // Deferred from load() so TConstruct has registered its own tabs first - registering + // ours before it left the vanilla tab duplicated. + if (ConfigClient.InventoryGuiEnabled) { + MinecraftForge.EVENT_BUS.register(new TabRegistry()); + if (TabRegistry.getTabList().isEmpty()) { + TabRegistry.registerTab(new InventoryTabVanilla()); + } + TabRegistry.registerTab(new InventoryTabCustomNpc()); + } + } + public void buildPackageIndex() { try { PackageFinder.init(Thread.currentThread().getContextClassLoader());