From 761a841b2c33b647b88dfd7990930ae29a6e9f44 Mon Sep 17 00:00:00 2001 From: candle Date: Thu, 25 Sep 2025 23:19:30 -0400 Subject: [PATCH] updating --- build.gradle | 2 + src/main/java/io/lampnet/ccccc/Ccccc.java | 36 ++++++++ .../ccccc/compat/AutoHudBotaniaCompat.java | 85 ++++++++++++++++++ .../java/io/lampnet/ccccc/config/Tweak.java | 25 +++++- .../lampnet/ccccc/mixin/CccccMixinPlugin.java | 39 ++++++++ .../client/PalettedPermutationsMixin.java | 71 +++++++++++++++ .../forgeskyboxes/FabricSkyBoxesClient.class | Bin 0 -> 5463 bytes .../forgeskyboxes/ForgeSkyboxesMixin.java | 20 +++++ src/main/resources/ccccc.mixins.json | 4 +- 9 files changed, 280 insertions(+), 2 deletions(-) create mode 100644 src/main/java/io/lampnet/ccccc/compat/AutoHudBotaniaCompat.java create mode 100644 src/main/java/io/lampnet/ccccc/mixin/client/PalettedPermutationsMixin.java create mode 100644 src/main/java/io/lampnet/ccccc/mixin/forgeskyboxes/FabricSkyBoxesClient.class create mode 100644 src/main/java/io/lampnet/ccccc/mixin/forgeskyboxes/ForgeSkyboxesMixin.java diff --git a/build.gradle b/build.gradle index c1a1061..9e979e8 100644 --- a/build.gradle +++ b/build.gradle @@ -161,6 +161,8 @@ dependencies { runtimeOnly fg.deobf("blank:tetracelium-1.20.1-1.3.1") runtimeOnly fg.deobf("blank:supplementaries-1.20-3.1.36") compileOnly fg.deobf("vazkii.botania:Botania:1.20.1-450-FORGE:api") + runtimeOnly fg.deobf("blank:autohud-8.7+1.20.1-forge") + runtimeOnly fg.deobf("blank:forgeskyboxes-0.0.2-1.20.2-new") // Compile-only hints for Registrate types used in mixin signatures compileOnly fg.deobf("com.tterrag.registrate:Registrate:MC1.20-1.3.11") // Example mod dependency using a mod jar from ./libs with a flat dir repository diff --git a/src/main/java/io/lampnet/ccccc/Ccccc.java b/src/main/java/io/lampnet/ccccc/Ccccc.java index 62387f5..7c31a25 100644 --- a/src/main/java/io/lampnet/ccccc/Ccccc.java +++ b/src/main/java/io/lampnet/ccccc/Ccccc.java @@ -52,6 +52,42 @@ public class Ccccc { @SubscribeEvent public static void onClientSetup(FMLClientSetupEvent event) { LOGGER.debug("Client setup complete for {} (user: {})", MODID, Minecraft.getInstance().getUser().getName()); + + // Initialize AutoHUD compatibility for Botania if both mods are present and enabled + event.enqueueWork(() -> { + initializeAutoHudBotaniaCompat(); + }); + } + + private static void initializeAutoHudBotaniaCompat() { + try { + // Check if config allows AutoHUD-Botania compatibility + if (!Config.isEnabled(io.lampnet.ccccc.config.Tweak.COMPAT_AUTOHUD_BOTANIA)) { + return; + } + + // Check if both AutoHUD and Botania are loaded + if (!isModLoaded("autohud") || !isModLoaded("botania")) { + return; + } + + // Initialize the compatibility + io.lampnet.ccccc.compat.AutoHudBotaniaCompat compat = new io.lampnet.ccccc.compat.AutoHudBotaniaCompat(); + compat.init(); + + LOGGER.info("AutoHUD-Botania compatibility initialized successfully"); + + } catch (Exception e) { + LOGGER.error("Failed to initialize AutoHUD-Botania compatibility: {}", e.getMessage()); + } + } + + private static boolean isModLoaded(String modId) { + try { + return net.minecraftforge.fml.ModList.get().isLoaded(modId); + } catch (Exception e) { + return false; + } } } } diff --git a/src/main/java/io/lampnet/ccccc/compat/AutoHudBotaniaCompat.java b/src/main/java/io/lampnet/ccccc/compat/AutoHudBotaniaCompat.java new file mode 100644 index 0000000..d793d85 --- /dev/null +++ b/src/main/java/io/lampnet/ccccc/compat/AutoHudBotaniaCompat.java @@ -0,0 +1,85 @@ +package io.lampnet.ccccc.compat; + +/** + * AutoHUD compatibility provider for Botania + * Uses reflection to integrate with AutoHUD's component system like the experience bar + */ +public class AutoHudBotaniaCompat { + + public String modId() { + return "botania"; + } + + /** + * Initialize AutoHUD compatibility for Botania's mana bar + * This follows AutoHUD's API pattern but uses reflection due to compile-time dependencies + */ + public void init() { + try { + // Create a component for Botania's mana bar that behaves like the experience bar + // This will be controlled by AutoHud.targetStatusBars like other status bar elements + Class componentClass = Class.forName("mod.crend.autohud.component.Component"); + Class autoHudClass = Class.forName("mod.crend.autohud.AutoHud"); + Class componentsClass = Class.forName("mod.crend.autohud.component.Components"); + + // Get the Component.builder method + java.lang.reflect.Method builderMethod = componentClass.getMethod("builder", String.class, String.class); + Object builder = builderMethod.invoke(null, "botania", "mana"); + + // Chain builder methods: isTargeted(() -> AutoHud.targetStatusBars) + java.lang.reflect.Field targetStatusBarsField = autoHudClass.getField("targetStatusBars"); + java.util.function.Supplier targetSupplier = () -> { + try { + return targetStatusBarsField.getBoolean(null); + } catch (Exception e) { + return true; // Fallback to showing + } + }; + + Class builderClass = builder.getClass(); + java.lang.reflect.Method isTargetedMethod = builderClass.getMethod("isTargeted", java.util.function.Supplier.class); + builder = isTargetedMethod.invoke(builder, targetSupplier); + + // Add config (use experience config since mana bar is similar) + java.lang.reflect.Method configMethod = autoHudClass.getMethod("config"); + Object config = configMethod.invoke(null); + java.lang.reflect.Method experienceMethod = config.getClass().getMethod("experience"); + Object experienceConfig = experienceMethod.invoke(config); + + java.lang.reflect.Method configBuilderMethod = builderClass.getMethod("config", Object.class); + builder = configBuilderMethod.invoke(builder, experienceConfig); + + // Mark as in main HUD + java.lang.reflect.Method inMainHudMethod = builderClass.getMethod("inMainHud"); + builder = inMainHudMethod.invoke(builder); + + // Set state to always show when player has Botania items (simplified) + java.util.function.Function stateFunction = player -> true; // Simplified - always show + java.lang.reflect.Method stateMethod = builderClass.getMethod("state", java.util.function.Function.class); + builder = stateMethod.invoke(builder, stateFunction); + + // Build the component + java.lang.reflect.Method buildMethod = builderClass.getMethod("build"); + Object manaBarComponent = buildMethod.invoke(builder); + + // Add to Experience component stack + java.lang.reflect.Field experienceField = componentsClass.getField("Experience"); + Object experienceComponent = experienceField.get(null); + java.lang.reflect.Method addStackComponentMethod = experienceComponent.getClass().getMethod("addStackComponent", Object.class); + addStackComponentMethod.invoke(experienceComponent, manaBarComponent); + + System.out.println("Botania AutoHUD compatibility initialized successfully"); + + } catch (Exception e) { + System.err.println("Failed to initialize Botania AutoHUD compatibility: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * Tick state - simplified since we're using the experience component as base + */ + public void tickState(Object player) { + // Component synchronization is handled automatically by AutoHUD's component system + } +} diff --git a/src/main/java/io/lampnet/ccccc/config/Tweak.java b/src/main/java/io/lampnet/ccccc/config/Tweak.java index 7c4ac38..7183bf1 100644 --- a/src/main/java/io/lampnet/ccccc/config/Tweak.java +++ b/src/main/java/io/lampnet/ccccc/config/Tweak.java @@ -4,6 +4,21 @@ import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.loading.LoadingModList; public enum Tweak { +// PREVENT_PALLETE_LOG_SPAM( +// "prevent_pallet_log_spam", +// TweakCategory.CLIENT, +// TweakGroup.NONE, +// true, +// "Palette permutations no longer fail on mods that aren't installed" +// ), + FIX_FORGESKYBOXES( + "fix_forgeskyboxes", + TweakCategory.BUGFIX, + TweakGroup.NONE, + true, + "Fix Forge Skyboxes not loading", + "forgeskyboxes" + ), MIXIN_RESPITEFUL_FLUIDS( "fix_respiteful_fluids_registration", TweakCategory.BUGFIX, @@ -344,7 +359,7 @@ public enum Tweak { TweakGroup.NONE, true, "Tetra Structures generate in mountainous biomes", - "tetra" + "tetra", "tectonic" ), TETRA_ENSCORCELLATION_COMPAT( "compat_tetra_ensorcellation", @@ -369,6 +384,14 @@ public enum Tweak { true, "Supplementaries Hat Stand can wear Simple Hats", "supplementaries", "simplehats" + ), + COMPAT_AUTOHUD_BOTANIA( + "compat_autohud_botania", + TweakCategory.COMPATIBILITY, + TweakGroup.NONE, + true, + "AutoHUD registers Botania bars", + "autohud", "botania" ) ; diff --git a/src/main/java/io/lampnet/ccccc/mixin/CccccMixinPlugin.java b/src/main/java/io/lampnet/ccccc/mixin/CccccMixinPlugin.java index 4a7ed1e..a31330c 100644 --- a/src/main/java/io/lampnet/ccccc/mixin/CccccMixinPlugin.java +++ b/src/main/java/io/lampnet/ccccc/mixin/CccccMixinPlugin.java @@ -8,14 +8,19 @@ import java.util.Set; import io.lampnet.ccccc.Config; import io.lampnet.ccccc.config.Tweak; +import com.mojang.logging.LogUtils; +import org.slf4j.Logger; public final class CccccMixinPlugin implements IMixinConfigPlugin { + private static final Logger LOGGER = LogUtils.getLogger(); private static final String RESPITEFUL_FLUIDS_RESOURCE = "plus/dragons/respiteful/entries/RespitefulFluids.class"; private static final String TETRACELIUM_RESOURCE = "se/mickelus/tetracelium/TetraceliumMod.class"; + private static final String BOTANIA_RESOURCE = "vazkii/botania/api/BotaniaAPI.class"; private static final String JEI_MARKER_RESOURCE = "mezz/jei/forge/JustEnoughItems.class"; private static final String SUPPLEMENTARIES_RESOURCE = "net/mehvahdjukaar/supplementaries/Supplementaries.class"; private static final String SIMPLEHATS_RESOURCE = "fonnymunkey/simplehats/SimpleHats.class"; + private static final String FORGESKYBOXES_RESOURCE = "com/foopy/forgeskyboxes/FabricSkyBoxesClient.class"; @Override public void onLoad(final String mixinPackage) { @@ -31,6 +36,9 @@ public final class CccccMixinPlugin implements IMixinConfigPlugin { final String respitefulMixin = "io.lampnet.ccccc.mixin.respiteful.RespitefulFluidsMixin"; final String tetraceliumBotaniaMixin = "io.lampnet.ccccc.mixin.tetracelium.TetraceliumBotaniaMixin"; final String supplementariesHatsMixin = "io.lampnet.ccccc.mixin.supplementaries.SupplementariesHatsMixin"; + + final String palettedPermutationsMixin = "io.lampnet.ccccc.mixin.client.PalettedPermutationsMixin"; + final String forgeskyboxesMixin = "io.lampnet.ccccc.mixin.forgeskyboxes.ForgeSkyboxesMixin"; if (respitefulMixin.equals(mixinClassName)) { boolean allowRespitefulByConfig = isRespitefulMixinEnabledSafe(); @@ -49,6 +57,18 @@ public final class CccccMixinPlugin implements IMixinConfigPlugin { final boolean resourcesPresent = areAllResourcesPresent(SUPPLEMENTARIES_RESOURCE, SIMPLEHATS_RESOURCE); return allowSupplementariesHatsByConfig && resourcesPresent; } + + + + if (palettedPermutationsMixin.equals(mixinClassName)) { + boolean enabledByConfig = isPaletteLogSpamFixEnabledSafe(); + return enabledByConfig; + } + + if (forgeskyboxesMixin.equals(mixinClassName)) { + boolean enabledByConfig = isForgeSkyboxesMixinEnabledSafe(); + return enabledByConfig; + } return true; } @@ -116,6 +136,25 @@ public final class CccccMixinPlugin implements IMixinConfigPlugin { return true; } } + + + + private static boolean isPaletteLogSpamFixEnabledSafe() { + try { + // return Config.isEnabled(Tweak.PREVENT_PALLETE_LOG_SPAM); + return false; + } catch (final Throwable throwable) { + return true; + } + } + + private static boolean isForgeSkyboxesMixinEnabledSafe() { + try { + return Config.isEnabled(Tweak.FIX_FORGESKYBOXES); + } catch (final Throwable throwable) { + return true; + } + } } diff --git a/src/main/java/io/lampnet/ccccc/mixin/client/PalettedPermutationsMixin.java b/src/main/java/io/lampnet/ccccc/mixin/client/PalettedPermutationsMixin.java new file mode 100644 index 0000000..06647fb --- /dev/null +++ b/src/main/java/io/lampnet/ccccc/mixin/client/PalettedPermutationsMixin.java @@ -0,0 +1,71 @@ +package io.lampnet.ccccc.mixin.client; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraftforge.fml.ModList; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + + +/** + * Mixin to intercept PalettedPermutations and prevent loading palette images + * from mods that aren't installed, which causes console log spam. + */ +@Mixin(value = net.minecraft.client.renderer.texture.atlas.sources.PalettedPermutations.class) +public class PalettedPermutationsMixin { + + + + /** + * Intercept the method that processes individual palette images using SRG name + * This method is called during palette processing where the actual error occurs + * Only affects palette-related resources from uninstalled mods + */ + @Inject(method = "m_266592_", at = @At("HEAD"), cancellable = true, require = 0, remap = false) + private static void preventPaletteProcessingFromUninstalledMods_srg(ResourceManager resourceManager, ResourceLocation paletteLocation, CallbackInfoReturnable cir) { + + if (paletteLocation == null) { + return; + } + + final String namespace = paletteLocation.getNamespace(); + final String path = paletteLocation.getPath(); + + // Only intercept palette-related resources (more specific check) + if (!path.contains("trims/color_palettes/")) { + return; + } + + // Skip check for minecraft namespace - always allow vanilla resources + if ("minecraft".equals(namespace)) { + return; + } + + // Check if the mod is actually loaded + if (!isModLoadedSafe(namespace)) { + // Mod is not installed, return null to prevent error spam + // This prevents the FileNotFoundException but allows other resource processing to continue + cir.setReturnValue(null); + return; + } + } + + + + /** + * Safe method to check if a mod is loaded without throwing exceptions + */ + private static boolean isModLoadedSafe(final String modId) { + try { + final ModList modList = ModList.get(); + if (modList != null && modId != null && !modId.isEmpty()) { + return modList.isLoaded(modId); + } + } catch (final Throwable ignored) { + // If we can't determine mod status, allow loading to prevent breaking existing functionality + } + return true; + } +} diff --git a/src/main/java/io/lampnet/ccccc/mixin/forgeskyboxes/FabricSkyBoxesClient.class b/src/main/java/io/lampnet/ccccc/mixin/forgeskyboxes/FabricSkyBoxesClient.class new file mode 100644 index 0000000000000000000000000000000000000000..8caa70da1c0e026d4105c75291a94ddbd2c1ff19 GIT binary patch literal 5463 zcmbVQ_kR=T8UMb|NK3lp|PbUYb zGu=(P_el5NiJ`_on*1+KI8k0_pbc!;^P4J z;=cl05@tpjHO=f4|E-jko0u9g&uBTNPaU!JM0{eZTR!%rbZGcqRU@VJ zkBn;xuC5SRUyi;_k_y}rH8fkv=!TZC)KS~nM;Xne74Dre4JBqKy98EFs_DEYu&P84 zfu2elCQM^gPc2l`S!_I{8JeZ0d z&W-i=MtTK8(IQvewx~;2EovoU|Di+S0f7xsqCiozYGO=N(q<|}5_!FIT#52YvlywG zp8lhKkwXGIqRa3D1^82%?Mfp!nwqb=Wf1Feiyu{Z2I0{sVM<&&Fs;P~idahJm};n0 z+lM=-Z_{G)uVwe!uql8>Jd>uopcB|hwU=Xj5KqUg(v%i~K-yH3Jq}=l*n;K&m$wRR zu8=K~T1KNU7ColgV+6HASGuw2jWBl2mGW#MXIBvI*zU(RbO@|qFa*}p9tRqRZYraC zT2tg6B;0|!0wmnY6fa54t*$59#&f1oi%vpoF}n{8w$IXXW_psD-Bi~7i`lsAUhJ#G z9_**bZL^Q+u1 zK}2wO0M$4mu)9K(q&ci@88ayZbvK__-lA^k7;9TQ!-5$T*hh1gFTx2-e*i~uj8%jY z*5fx)LdnQ`7+BQq-V8Yb8w2^#wQc2B)%`4?_ZV@gpa@ z`|lkdJb5fEu&ta)mX^|UtTk*Zz1pZ|Sz2;$EEe;{;9#w3Ttk61+YoG2{(Mc?)PkXH-s%A!#DjSMAswQmHn)1P91T)12fv4sx zzC;V^T3kuzt&}iItjs6B_LpwgTbkD^Tl4MgQPb(TZp#YsTv!2Qky}#(7P%TVk?gS*hF**Z zC5B!?4861-4~8J5Nlj%;VwrFzx57;4G-V%N$%Ygj3LhOD?mix8HMx$A4C2*z$d6ay zVVRjJY2<5J*X=Q#hP7Q^xLB=O=9r$ccDoi^Q$f5*7Vi^yGsmn-WzMZ`b2GzR86g(e zh>^2ZBf-3GW@Wu5USjXu1Y) zA5pFu>WJ)^;#3eHzz6*Z;6t1?a+)1>-mpN`1ZE2V962X)iX0a5R)W1^ zz`OH;L3y9Uqf*{uY@VgsR+J#80_lqdvV1tp39eEc3o0ls7z(_FH1*;00nEq|z?T`` zxxHPwqkBQ(DHSw2W@%Z~ay62=6=XUUd=?i1IERazaf!L&$v~iQ3DhlxlA;WG;-Ck= zfG^6q=5coFO4fVwXgd#nz1m1V6;D{2X87=gz>Tg;8l3e8_eCwfEYMgQ5I)^+S`$iQ zOto1jGg;Gcj*nkueaH-N@7USi-a)q=oZoD`@45L zcO)3U%d?eJ-v#!RZtqOX&N0_{f0Y)_(on#i2Y7)4r2;E~YCx+1b9q$DIl&Xyezh{Q zDB$G2$>x!dHkW(~kY~iwXnVz?*iz`8pWc#_OCr1UpadQP5@j_$n$L`AmbVg$nh7;Mq;e)Dg|`@t7#t>g z(rPZJu?Gg?PCa$cQ0oWshOK9`Aw8#)dNd79<527cUz+ez_PK6UXbf1znKTt;1J<199xMFXE6 zDp!USHaZmYMJB>SMuq(9t0uEH+0{A^-7Kf!U;mD|Qw%fvg9`iijhsi6syIRg8 zI*WT|a6CGVXSL2ioyMrVw6I~lI#Rz84^bf@r+iPbEA*QT&gogaWft$6 z#UtnN{&V>73_d=K&(2`_37m^V7MEeuy8@!WeGAkMR=;1#t58>>A-4iHLQyh$_Zfx17T-X7F2i{R6K>jY7^2 z_rQlZE6pGQdfeH$!R4RZc^!BDBc=1J8UBPnQ+_r6$sKMXo$Q9Ih`BYq*7F*|O}Lpc l`4`_;VI}^}YaMwdG<-RR?>}6S;mMPE3>g^S-OKRu{{v_;kTn1R literal 0 HcmV?d00001 diff --git a/src/main/java/io/lampnet/ccccc/mixin/forgeskyboxes/ForgeSkyboxesMixin.java b/src/main/java/io/lampnet/ccccc/mixin/forgeskyboxes/ForgeSkyboxesMixin.java new file mode 100644 index 0000000..b53ffd0 --- /dev/null +++ b/src/main/java/io/lampnet/ccccc/mixin/forgeskyboxes/ForgeSkyboxesMixin.java @@ -0,0 +1,20 @@ +package io.lampnet.ccccc.mixin.forgeskyboxes; + +import net.minecraft.client.Minecraft; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Pseudo +@Mixin(targets = "com.foopy.forgeskyboxes.FabricSkyBoxesClient", remap = false) +public class ForgeSkyboxesMixin { + + @Redirect(method = "onInitializeClient", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;m_91391_()Ljava/util/concurrent/CompletableFuture;"), + remap = false) + private java.util.concurrent.CompletableFuture ccccc$removeResourcePackReload(Minecraft minecraft) { + // Do nothing - removing the resource pack reload call + return java.util.concurrent.CompletableFuture.completedFuture(null); + } +} diff --git a/src/main/resources/ccccc.mixins.json b/src/main/resources/ccccc.mixins.json index 9ea4c46..8af4432 100644 --- a/src/main/resources/ccccc.mixins.json +++ b/src/main/resources/ccccc.mixins.json @@ -8,9 +8,11 @@ "mixins": [ "respiteful.RespitefulFluidsMixin", "tetracelium.TetraceliumBotaniaMixin", - "supplementaries.SupplementariesHatsMixin" + "supplementaries.SupplementariesHatsMixin", + "forgeskyboxes.ForgeSkyboxesMixin" ], "client": [ + "client.PalettedPermutationsMixin" ], "injectors": { "defaultRequire": 1