This commit is contained in:
candle 2025-09-25 23:19:30 -04:00
parent 98067cbba9
commit 761a841b2c
9 changed files with 280 additions and 2 deletions

View File

@ -161,6 +161,8 @@ dependencies {
runtimeOnly fg.deobf("blank:tetracelium-1.20.1-1.3.1") runtimeOnly fg.deobf("blank:tetracelium-1.20.1-1.3.1")
runtimeOnly fg.deobf("blank:supplementaries-1.20-3.1.36") runtimeOnly fg.deobf("blank:supplementaries-1.20-3.1.36")
compileOnly fg.deobf("vazkii.botania:Botania:1.20.1-450-FORGE:api") 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 // Compile-only hints for Registrate types used in mixin signatures
compileOnly fg.deobf("com.tterrag.registrate:Registrate:MC1.20-1.3.11") 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 // Example mod dependency using a mod jar from ./libs with a flat dir repository

View File

@ -52,6 +52,42 @@ public class Ccccc {
@SubscribeEvent @SubscribeEvent
public static void onClientSetup(FMLClientSetupEvent event) { public static void onClientSetup(FMLClientSetupEvent event) {
LOGGER.debug("Client setup complete for {} (user: {})", MODID, Minecraft.getInstance().getUser().getName()); 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;
}
} }
} }
} }

View File

@ -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<Boolean> 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<Object, Boolean> 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
}
}

View File

@ -4,6 +4,21 @@ import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.loading.LoadingModList; import net.minecraftforge.fml.loading.LoadingModList;
public enum Tweak { 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( MIXIN_RESPITEFUL_FLUIDS(
"fix_respiteful_fluids_registration", "fix_respiteful_fluids_registration",
TweakCategory.BUGFIX, TweakCategory.BUGFIX,
@ -344,7 +359,7 @@ public enum Tweak {
TweakGroup.NONE, TweakGroup.NONE,
true, true,
"Tetra Structures generate in mountainous biomes", "Tetra Structures generate in mountainous biomes",
"tetra" "tetra", "tectonic"
), ),
TETRA_ENSCORCELLATION_COMPAT( TETRA_ENSCORCELLATION_COMPAT(
"compat_tetra_ensorcellation", "compat_tetra_ensorcellation",
@ -369,6 +384,14 @@ public enum Tweak {
true, true,
"Supplementaries Hat Stand can wear Simple Hats", "Supplementaries Hat Stand can wear Simple Hats",
"supplementaries", "simplehats" "supplementaries", "simplehats"
),
COMPAT_AUTOHUD_BOTANIA(
"compat_autohud_botania",
TweakCategory.COMPATIBILITY,
TweakGroup.NONE,
true,
"AutoHUD registers Botania bars",
"autohud", "botania"
) )
; ;

View File

@ -8,14 +8,19 @@ import java.util.Set;
import io.lampnet.ccccc.Config; import io.lampnet.ccccc.Config;
import io.lampnet.ccccc.config.Tweak; import io.lampnet.ccccc.config.Tweak;
import com.mojang.logging.LogUtils;
import org.slf4j.Logger;
public final class CccccMixinPlugin implements IMixinConfigPlugin { 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 RESPITEFUL_FLUIDS_RESOURCE = "plus/dragons/respiteful/entries/RespitefulFluids.class";
private static final String TETRACELIUM_RESOURCE = "se/mickelus/tetracelium/TetraceliumMod.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 BOTANIA_RESOURCE = "vazkii/botania/api/BotaniaAPI.class";
private static final String JEI_MARKER_RESOURCE = "mezz/jei/forge/JustEnoughItems.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 SUPPLEMENTARIES_RESOURCE = "net/mehvahdjukaar/supplementaries/Supplementaries.class";
private static final String SIMPLEHATS_RESOURCE = "fonnymunkey/simplehats/SimpleHats.class"; private static final String SIMPLEHATS_RESOURCE = "fonnymunkey/simplehats/SimpleHats.class";
private static final String FORGESKYBOXES_RESOURCE = "com/foopy/forgeskyboxes/FabricSkyBoxesClient.class";
@Override @Override
public void onLoad(final String mixinPackage) { public void onLoad(final String mixinPackage) {
@ -32,6 +37,9 @@ public final class CccccMixinPlugin implements IMixinConfigPlugin {
final String tetraceliumBotaniaMixin = "io.lampnet.ccccc.mixin.tetracelium.TetraceliumBotaniaMixin"; final String tetraceliumBotaniaMixin = "io.lampnet.ccccc.mixin.tetracelium.TetraceliumBotaniaMixin";
final String supplementariesHatsMixin = "io.lampnet.ccccc.mixin.supplementaries.SupplementariesHatsMixin"; 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)) { if (respitefulMixin.equals(mixinClassName)) {
boolean allowRespitefulByConfig = isRespitefulMixinEnabledSafe(); boolean allowRespitefulByConfig = isRespitefulMixinEnabledSafe();
final boolean resourcesPresent = areAllResourcesPresent(RESPITEFUL_FLUIDS_RESOURCE, JEI_MARKER_RESOURCE); final boolean resourcesPresent = areAllResourcesPresent(RESPITEFUL_FLUIDS_RESOURCE, JEI_MARKER_RESOURCE);
@ -50,6 +58,18 @@ public final class CccccMixinPlugin implements IMixinConfigPlugin {
return allowSupplementariesHatsByConfig && resourcesPresent; return allowSupplementariesHatsByConfig && resourcesPresent;
} }
if (palettedPermutationsMixin.equals(mixinClassName)) {
boolean enabledByConfig = isPaletteLogSpamFixEnabledSafe();
return enabledByConfig;
}
if (forgeskyboxesMixin.equals(mixinClassName)) {
boolean enabledByConfig = isForgeSkyboxesMixinEnabledSafe();
return enabledByConfig;
}
return true; return true;
} }
@ -116,6 +136,25 @@ public final class CccccMixinPlugin implements IMixinConfigPlugin {
return true; 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;
}
}
} }

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -8,9 +8,11 @@
"mixins": [ "mixins": [
"respiteful.RespitefulFluidsMixin", "respiteful.RespitefulFluidsMixin",
"tetracelium.TetraceliumBotaniaMixin", "tetracelium.TetraceliumBotaniaMixin",
"supplementaries.SupplementariesHatsMixin" "supplementaries.SupplementariesHatsMixin",
"forgeskyboxes.ForgeSkyboxesMixin"
], ],
"client": [ "client": [
"client.PalettedPermutationsMixin"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1