aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md3
-rw-r--r--build.gradle1
-rw-r--r--gradle.properties2
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/mixin/ConfiguredConfigHelperMixin.java55
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/mixin/ConfiguredModConfigSelectionScreenMixin.java212
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/mixin/MinecraftMixin.java1
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/mixin/MixinConfig.java60
-rw-r--r--src/main/resources/META-INF/mods.toml7
-rw-r--r--src/main/resources/iceberg.mixins.json6
9 files changed, 344 insertions, 3 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f8d735b..0566ee9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,8 @@
# Changelog
+### 1.0.45
+- Added support for Configured configuration menus to IcebergConfig.
+
### 1.0.44
- Fixed incompatibility with some mods causing a crash at startup.
diff --git a/build.gradle b/build.gradle
index bc816f3..73cd42a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -60,6 +60,7 @@ dependencies {
minecraft "net.minecraftforge:forge:${project.mcVersion}-${project.forgeVersion}"
annotationProcessor 'org.spongepowered:mixin:0.8.5:processor'
compileClasspath fg.deobf('curse.maven:configmenusforge-544048:3570070')
+ compileClasspath fg.deobf('curse.maven:configured-457570:3822820')
}
jar {
diff --git a/gradle.properties b/gradle.properties
index b075a86..239dfec 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -6,6 +6,6 @@ org.gradle.daemon=false
name=${rootProject.name}
group=com.anthonyhilyard.${name.toLowerCase()}
author=anthonyhilyard
-version=1.0.44
+version=1.0.45
mcVersion=1.19
forgeVersion=41.0.30 \ No newline at end of file
diff --git a/src/main/java/com/anthonyhilyard/iceberg/mixin/ConfiguredConfigHelperMixin.java b/src/main/java/com/anthonyhilyard/iceberg/mixin/ConfiguredConfigHelperMixin.java
new file mode 100644
index 0000000..682fcb8
--- /dev/null
+++ b/src/main/java/com/anthonyhilyard/iceberg/mixin/ConfiguredConfigHelperMixin.java
@@ -0,0 +1,55 @@
+package com.anthonyhilyard.iceberg.mixin;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.anthonyhilyard.iceberg.config.IcebergConfigSpec;
+import com.electronwill.nightconfig.core.AbstractConfig;
+import com.electronwill.nightconfig.core.UnmodifiableConfig;
+
+
+import org.apache.commons.lang3.tuple.Pair;
+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;
+
+import net.minecraftforge.common.ForgeConfigSpec;
+import net.minecraftforge.fml.config.ModConfig;
+
+
+import com.mrcrayfish.configured.util.ConfigHelper;
+
+
+@Mixin(ConfigHelper.class)
+public class ConfiguredConfigHelperMixin
+{
+ @Inject(method = "gatherAllConfigValues(Lnet/minecraftforge/fml/config/ModConfig;)Ljava/util/List;",
+ at = @At(value = "HEAD"), cancellable = true, remap = false)
+ private static void gatherAllConfigValuesIcebergSupport(ModConfig config, CallbackInfoReturnable<List<?>> info)
+ {
+ if (config.getSpec() instanceof IcebergConfigSpec icebergConfigSpec)
+ {
+ List<Pair<ForgeConfigSpec.ConfigValue<?>, ForgeConfigSpec.ValueSpec>> values = new ArrayList<>();
+ gatherValuesFromIcebergConfig(icebergConfigSpec.getValues(), icebergConfigSpec, values);
+ info.setReturnValue(values);
+ }
+ }
+
+ private static void gatherValuesFromIcebergConfig(UnmodifiableConfig config, IcebergConfigSpec spec, List<Pair<ForgeConfigSpec.ConfigValue<?>, ForgeConfigSpec.ValueSpec>> values)
+ {
+ config.valueMap().forEach((s, o) ->
+ {
+ if (o instanceof AbstractConfig)
+ {
+ gatherValuesFromIcebergConfig((UnmodifiableConfig) o, spec, values);
+ }
+ else if (o instanceof ForgeConfigSpec.ConfigValue<?>)
+ {
+ ForgeConfigSpec.ConfigValue<?> configValue = (ForgeConfigSpec.ConfigValue<?>) o;
+ ForgeConfigSpec.ValueSpec valueSpec = spec.getRaw(configValue.getPath());
+ values.add(Pair.of(configValue, valueSpec));
+ }
+ });
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/anthonyhilyard/iceberg/mixin/ConfiguredModConfigSelectionScreenMixin.java b/src/main/java/com/anthonyhilyard/iceberg/mixin/ConfiguredModConfigSelectionScreenMixin.java
new file mode 100644
index 0000000..a682a00
--- /dev/null
+++ b/src/main/java/com/anthonyhilyard/iceberg/mixin/ConfiguredModConfigSelectionScreenMixin.java
@@ -0,0 +1,212 @@
+package com.anthonyhilyard.iceberg.mixin;
+
+import java.lang.reflect.Field;
+
+import com.anthonyhilyard.iceberg.Loader;
+import com.anthonyhilyard.iceberg.config.IcebergConfigSpec;
+import com.electronwill.nightconfig.core.UnmodifiableConfig;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.mrcrayfish.configured.client.screen.ConfigScreen;
+import com.mrcrayfish.configured.client.screen.ListMenuScreen;
+import com.mrcrayfish.configured.client.screen.ModConfigSelectionScreen;
+import com.mrcrayfish.configured.client.screen.ModConfigSelectionScreen.FileItem;
+import com.mrcrayfish.configured.client.screen.WorldSelectionScreen;
+import com.mrcrayfish.configured.client.screen.ConfigScreen.FolderEntry;
+import com.mrcrayfish.configured.client.screen.ConfigScreen.IEntry;
+import com.mrcrayfish.configured.client.screen.widget.IconButton;
+import com.mrcrayfish.configured.util.ConfigHelper;
+
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+import org.spongepowered.asm.mixin.injection.At;
+
+import net.minecraft.ChatFormatting;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.components.Button;
+import net.minecraft.client.gui.narration.ScreenNarrationCollector;
+import net.minecraft.client.gui.screens.Screen;
+import net.minecraft.network.chat.Component;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraftforge.common.ForgeConfigSpec;
+import net.minecraftforge.fml.ModList;
+import net.minecraftforge.fml.config.ModConfig;
+import net.minecraftforge.fml.unsafe.UnsafeHacks;
+
+@Mixin(FileItem.class)
+public class ConfiguredModConfigSelectionScreenMixin
+{
+ @Shadow(aliases = "this$0", remap = false)
+ @Final
+ ModConfigSelectionScreen this$0;
+
+ @Shadow(remap = false)
+ @Final
+ protected ModConfig config;
+
+ @Shadow(remap = false)
+ @Final
+ protected Component title;
+
+ @Shadow(remap = false)
+ private boolean hasRequiredPermission() { return true; }
+
+ @Inject(method = "createModifyButton", at = @At(value = "HEAD"), remap = false, cancellable = true)
+ private void createModifyButton(ModConfig config, CallbackInfoReturnable<Button> info)
+ {
+ if (config.getSpec() instanceof IcebergConfigSpec)
+ {
+ Minecraft minecraft = Minecraft.getInstance();
+ boolean serverConfig = config.getType() == ModConfig.Type.SERVER && Minecraft.getInstance().level == null;
+ String langKey = serverConfig ? "configured.gui.select_world" : "configured.gui.modify";
+
+ ResourceLocation backgroundTemp = null;
+ try
+ {
+ Field backgroundField = ListMenuScreen.class.getDeclaredField("background");
+ backgroundField.setAccessible(true);
+ backgroundTemp = (ResourceLocation) backgroundField.get(this$0);
+ }
+ catch (Exception e)
+ {
+ Loader.LOGGER.error(ExceptionUtils.getStackTrace(e));
+ }
+
+ final ResourceLocation background = backgroundTemp;
+
+ info.setReturnValue(new IconButton(0, 0, serverConfig ? 44 : 33, 0, serverConfig ? 80 : 60, Component.translatable(langKey), onPress ->
+ {
+ if (ConfigScreen.isPlayingGame() && this.config.getType() == ModConfig.Type.SERVER && (!ConfigHelper.isConfiguredInstalledOnServer() || !this.hasRequiredPermission()))
+ {
+ return;
+ }
+
+ if (serverConfig)
+ {
+ minecraft.setScreen(new WorldSelectionScreen(this$0, background, config, this.title));
+ }
+ else
+ {
+ ModList.get().getModContainerById(config.getModId()).ifPresent(container ->
+ {
+ try
+ {
+ ConfigScreen configScreen = UnsafeHacks.newInstance(ConfigScreen.class);
+
+ Field titleField = Screen.class.getDeclaredField("f_96539_");
+ Field childrenField = Screen.class.getDeclaredField("f_96540_");
+ Field narratablesField = Screen.class.getDeclaredField("f_169368_");
+ Field renderablesField = Screen.class.getDeclaredField("f_169369_");
+ Field narrationStateField = Screen.class.getDeclaredField("f_169375_");
+ Field parentField = configScreen.getClass().getSuperclass().getDeclaredField("parent");
+ Field backgroundField = configScreen.getClass().getSuperclass().getDeclaredField("background");
+ Field itemHeightField = configScreen.getClass().getSuperclass().getDeclaredField("itemHeight");
+ titleField.setAccessible(true);
+ childrenField.setAccessible(true);
+ narratablesField.setAccessible(true);
+ renderablesField.setAccessible(true);
+ narrationStateField.setAccessible(true);
+ parentField.setAccessible(true);
+ backgroundField.setAccessible(true);
+ itemHeightField.setAccessible(true);
+
+ titleField.set(configScreen, Component.literal(container.getModInfo().getDisplayName()));
+ childrenField.set(configScreen, Lists.newArrayList());
+ narratablesField.set(configScreen, Lists.newArrayList());
+ renderablesField.set(configScreen, Lists.newArrayList());
+ narrationStateField.set(configScreen, new ScreenNarrationCollector());
+ parentField.set(configScreen, this$0);
+ backgroundField.set(configScreen, background);
+ itemHeightField.set(configScreen, 24);
+
+ ForgeConfigSpec dummySpec = new ForgeConfigSpec.Builder().build();
+ FieldUtils.writeDeclaredField(configScreen, "folderEntry", new IcebergFolderEntry(configScreen, "Root", ((IcebergConfigSpec) config.getSpec()).getValues(), dummySpec, true, (IcebergConfigSpec) config.getSpec()), true);
+ FieldUtils.writeDeclaredField(configScreen, "config", config, true);
+
+ minecraft.setScreen(configScreen);
+ }
+ catch (Exception e)
+ {
+ Loader.LOGGER.error(ExceptionUtils.getStackTrace(e));
+ }
+ });
+ }
+ }, (button, poseStack, mouseX, mouseY) ->
+ {
+ if (button.isHoveredOrFocused())
+ {
+ if (ConfigScreen.isPlayingGame() && !ConfigHelper.isConfiguredInstalledOnServer())
+ {
+ this$0.renderTooltip(poseStack, minecraft.font.split(Component.translatable("configured.gui.not_installed").withStyle(ChatFormatting.RED), Math.max(this$0.width / 2 - 43, 170)), mouseX, mouseY);
+ }
+ else if (!this.hasRequiredPermission())
+ {
+ this$0.renderTooltip(poseStack, minecraft.font.split(Component.translatable("configured.gui.no_permission").withStyle(ChatFormatting.RED), Math.max(this$0.width / 2 - 43, 170)), mouseX, mouseY);
+ }
+ }
+ }));
+ }
+ }
+
+ public class IcebergFolderEntry extends FolderEntry
+ {
+ private IcebergConfigSpec icebergConfigSpec;
+ private ForgeConfigSpec spec;
+ private ConfigScreen configScreen;
+ private UnmodifiableConfig config;
+ public IcebergFolderEntry(ConfigScreen configScreen, String label, UnmodifiableConfig config, ForgeConfigSpec spec, boolean root, IcebergConfigSpec icebergSpec)
+ {
+ configScreen.super(label, config, spec, root);
+ icebergConfigSpec = icebergSpec;
+ this.spec = spec;
+ this.configScreen = configScreen;
+ this.config = config;
+ init();
+ }
+
+ private void init()
+ {
+ try
+ {
+ Field entriesField = getClass().getSuperclass().getDeclaredField("entries");
+ entriesField.setAccessible(true);
+
+ ImmutableList.Builder<IEntry> builder = ImmutableList.builder();
+ config.valueMap().forEach((key, value) ->
+ {
+ if (value instanceof ForgeConfigSpec.ValueSpec valueSpec && valueSpec.getDefault() instanceof UnmodifiableConfig)
+ {
+ value = valueSpec.getDefault();
+ }
+
+ if (value instanceof UnmodifiableConfig)
+ {
+ builder.add(new IcebergFolderEntry(configScreen, key, (UnmodifiableConfig) value, spec, false, icebergConfigSpec));
+ }
+ else if (value instanceof ForgeConfigSpec.ConfigValue<?>)
+ {
+ ForgeConfigSpec.ConfigValue<?> configValue = (ForgeConfigSpec.ConfigValue<?>) value;
+ Loader.LOGGER.info(configValue.getPath());
+ ForgeConfigSpec.ValueSpec valueSpec = icebergConfigSpec.getRaw(configValue.getPath());
+ if (valueSpec != null)
+ {
+ builder.add(configScreen.new ValueEntry(configValue, valueSpec));
+ }
+ }
+ });
+ entriesField.set(this, builder.build());
+ }
+ catch (Exception e)
+ {
+ Loader.LOGGER.error(ExceptionUtils.getStackTrace(e));
+ return;
+ }
+ }
+
+ }
+}
diff --git a/src/main/java/com/anthonyhilyard/iceberg/mixin/MinecraftMixin.java b/src/main/java/com/anthonyhilyard/iceberg/mixin/MinecraftMixin.java
index 67c63f5..974052b 100644
--- a/src/main/java/com/anthonyhilyard/iceberg/mixin/MinecraftMixin.java
+++ b/src/main/java/com/anthonyhilyard/iceberg/mixin/MinecraftMixin.java
@@ -68,7 +68,6 @@ public class MinecraftMixin
Loader.LOGGER.debug(ExceptionUtils.getStackTrace(e));
}
}
-
}
renderTarget.clear(onOSX);
}
diff --git a/src/main/java/com/anthonyhilyard/iceberg/mixin/MixinConfig.java b/src/main/java/com/anthonyhilyard/iceberg/mixin/MixinConfig.java
new file mode 100644
index 0000000..566843c
--- /dev/null
+++ b/src/main/java/com/anthonyhilyard/iceberg/mixin/MixinConfig.java
@@ -0,0 +1,60 @@
+package com.anthonyhilyard.iceberg.mixin;
+
+import java.util.List;
+import java.util.Set;
+
+import org.objectweb.asm.tree.ClassNode;
+import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
+import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
+
+import net.minecraftforge.fml.loading.FMLLoader;
+import net.minecraftforge.fml.loading.LoadingModList;
+import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
+
+public class MixinConfig implements IMixinConfigPlugin
+{
+ private LoadingModList loadingModList = null;
+
+ @Override
+ public void onLoad(String mixinPackage) { }
+
+ @Override
+ public String getRefMapperConfig() { return null; }
+
+ @Override
+ public boolean shouldApplyMixin(String targetClassName, String mixinClassName)
+ {
+ if (mixinClassName.toLowerCase().contains("configured"))
+ {
+ if (loadingModList == null)
+ {
+ loadingModList = FMLLoader.getLoadingModList();
+ }
+
+ // Check if Config Menus for Forge is available.
+ for (ModInfo modInfo : loadingModList.getMods())
+ {
+ // If configured is present, load the mixin.
+ if (modInfo.getModId().equals("configured"))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) { }
+
+ @Override
+ public List<String> getMixins() { return null; }
+
+ @Override
+ public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { }
+
+ @Override
+ public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { }
+} \ No newline at end of file
diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml
index 5c09d3f..26e401c 100644
--- a/src/main/resources/META-INF/mods.toml
+++ b/src/main/resources/META-INF/mods.toml
@@ -24,4 +24,11 @@ description="A library containing events, helpers, and utilities to make modding
mandatory=true
versionRange="[1.19,)"
ordering="NONE"
+ side="BOTH"
+
+[[dependencies.iceberg]]
+ modId="configured"
+ mandatory=false
+ versionRange="[1.5.3]"
+ ordering="NONE"
side="BOTH" \ No newline at end of file
diff --git a/src/main/resources/iceberg.mixins.json b/src/main/resources/iceberg.mixins.json
index 5100bd0..63db38f 100644
--- a/src/main/resources/iceberg.mixins.json
+++ b/src/main/resources/iceberg.mixins.json
@@ -3,6 +3,8 @@
"package": "com.anthonyhilyard.iceberg.mixin",
"compatibilityLevel": "JAVA_17",
"refmap": "iceberg.refmap.json",
+ "plugin": "com.anthonyhilyard.iceberg.mixin.MixinConfig",
+ "verbose": true,
"mixins": [
"PlayerAdvancementsMixin"
],
@@ -10,7 +12,9 @@
"ScreenMixin",
"ClientPacketListenerMixin",
"TextColorMixin",
- "MinecraftMixin"
+ "MinecraftMixin",
+ "ConfiguredConfigHelperMixin",
+ "ConfiguredModConfigSelectionScreenMixin"
],
"server": [
"MainMixin"