diff options
author | Anthony Hilyard <anthony.hilyard@gmail.com> | 2022-06-22 18:07:55 -0700 |
---|---|---|
committer | Anthony Hilyard <anthony.hilyard@gmail.com> | 2022-06-22 18:07:55 -0700 |
commit | 427f975d78b64ec4433e8e0542729feb0e618608 (patch) | |
tree | ec86c4767903f1bc1721485e9440b9004ad3043b /src/main/java | |
parent | ee81f0ac1cb848609a755a875f5df0f5d51fa881 (diff) | |
download | Iceberg-427f975d78b64ec4433e8e0542729feb0e618608.tar.gz Iceberg-427f975d78b64ec4433e8e0542729feb0e618608.tar.bz2 Iceberg-427f975d78b64ec4433e8e0542729feb0e618608.zip |
Added support for Configured to IcebergConfig.
Diffstat (limited to 'src/main/java')
4 files changed, 327 insertions, 1 deletions
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 |