diff options
author | Anthony Hilyard <anthony.hilyard@gmail.com> | 2022-09-26 00:29:41 -0700 |
---|---|---|
committer | Anthony Hilyard <anthony.hilyard@gmail.com> | 2022-09-26 00:29:41 -0700 |
commit | cda06cf996cb8a0df2340b14b2a43d5a2a6ab13a (patch) | |
tree | 10b53d9f4f94e7b37253ee635c7942ce5360f656 /src/main/java/com | |
parent | 6d01463c32ea14f48ce273e9daf753905f101946 (diff) | |
download | Iceberg-cda06cf996cb8a0df2340b14b2a43d5a2a6ab13a.tar.gz Iceberg-cda06cf996cb8a0df2340b14b2a43d5a2a6ab13a.tar.bz2 Iceberg-cda06cf996cb8a0df2340b14b2a43d5a2a6ab13a.zip |
Added support for Configured 2.x.
Diffstat (limited to 'src/main/java/com')
7 files changed, 418 insertions, 299 deletions
diff --git a/src/main/java/com/anthonyhilyard/iceberg/compat/configured/IcebergConfigPlugin.java b/src/main/java/com/anthonyhilyard/iceberg/compat/configured/IcebergConfigPlugin.java new file mode 100644 index 0000000..7f230de --- /dev/null +++ b/src/main/java/com/anthonyhilyard/iceberg/compat/configured/IcebergConfigPlugin.java @@ -0,0 +1,199 @@ +package com.anthonyhilyard.iceberg.compat.configured; + +import com.anthonyhilyard.iceberg.config.IcebergConfigSpec; +import com.electronwill.nightconfig.core.AbstractConfig; +import com.electronwill.nightconfig.core.CommentedConfig; +import com.electronwill.nightconfig.core.UnmodifiableConfig; +import com.electronwill.nightconfig.core.file.CommentedFileConfig; +import com.google.common.collect.ImmutableList; +import com.mojang.datafixers.util.Pair; +import com.mrcrayfish.configured.Configured; +import com.mrcrayfish.configured.api.ConfigType; +import com.mrcrayfish.configured.api.IConfigEntry; +import com.mrcrayfish.configured.api.IConfigValue; +import com.mrcrayfish.configured.api.IModConfig; +import com.mrcrayfish.configured.impl.forge.ForgeListValue; +import com.mrcrayfish.configured.impl.forge.ForgeValue; +import com.mrcrayfish.configured.util.ConfigHelper; +import net.minecraft.Util; +import net.minecraftforge.common.ForgeConfigSpec; +import net.minecraftforge.fml.config.ModConfig; +import net.minecraftforge.fml.event.config.ModConfigEvent; + +import java.nio.file.Path; +import java.util.EnumMap; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.apache.commons.compress.utils.Lists; + +public class IcebergConfigPlugin implements IModConfig +{ + protected static final EnumMap<ModConfig.Type, ConfigType> TYPE_RESOLVER = Util.make(new EnumMap<>(ModConfig.Type.class), (map) -> { + map.put(ModConfig.Type.CLIENT, ConfigType.CLIENT); + map.put(ModConfig.Type.COMMON, ConfigType.UNIVERSAL); + map.put(ModConfig.Type.SERVER, ConfigType.WORLD_SYNC); + }); + + protected final ModConfig config; + protected final List<IcebergValueEntry> allConfigValues; + + public IcebergConfigPlugin(ModConfig config) + { + this.config = config; + this.allConfigValues = getAllConfigValues(config); + } + + @Override + public void update(IConfigEntry entry) + { + Set<IConfigValue<?>> changedValues = ConfigHelper.getChangedValues(entry); + if (!changedValues.isEmpty()) + { + CommentedConfig newConfig = CommentedConfig.copy(this.config.getConfigData()); + changedValues.forEach(value -> + { + if (value instanceof ForgeValue<?> forge) + { + if (forge instanceof ForgeListValue forgeList) + { + Function<List<?>, List<?>> converter = forgeList.getConverter(); + if (converter != null) + { + newConfig.set(forge.configValue.getPath(), converter.apply(forgeList.get())); + return; + } + } + newConfig.set(forge.configValue.getPath(), value.get()); + } + }); + this.config.getConfigData().putAll(newConfig); + } + + if (this.getType() == ConfigType.WORLD_SYNC) + { + if (!ConfigHelper.isPlayingGame()) + { + // Unload server configs since still in main menu + this.config.getHandler().unload(this.config.getFullPath().getParent(), this.config); + ConfigHelper.setForgeConfigData(this.config, null); + } + } + else if (!changedValues.isEmpty()) + { + Configured.LOGGER.info("Sending config reloading event for {}", this.config.getFileName()); + this.config.getSpec().afterReload(); + ConfigHelper.fireForgeConfigEvent(this.config, new ModConfigEvent.Reloading(this.config)); + } + } + + @Override + public IConfigEntry getRoot() + { + return new IcebergFolderEntry(((IcebergConfigSpec) this.config.getSpec()).getValues(), (IcebergConfigSpec) this.config.getSpec()); + } + + @Override + public ConfigType getType() + { + return TYPE_RESOLVER.get(this.config.getType()); + } + + @Override + public String getFileName() + { + return this.config.getFileName(); + } + + @Override + public String getModId() + { + return this.config.getModId(); + } + + @Override + public void loadWorldConfig(Path path, Consumer<IModConfig> result) + { + final CommentedFileConfig data = this.config.getHandler().reader(path).apply(this.config); + ConfigHelper.setForgeConfigData(this.config, data); + result.accept(this); + } + + @Override + public void stopEditing() + { + // Attempts to unload the server config if player simply just went back + if (this.config != null && this.getType() == ConfigType.WORLD) + { + if (!ConfigHelper.isPlayingGame()) + { + // Unload server configs since still in main menu + this.config.getHandler().unload(this.config.getFullPath().getParent(), this.config); + ConfigHelper.setForgeConfigData(this.config, null); + } + } + } + + @Override + public boolean isChanged() + { + // Block world configs since the path is dynamic + if (ConfigHelper.isWorldConfig(this) && this.config.getConfigData() == null) + { + return false; + } + + // Check if any config value doesn't equal it's default + return this.allConfigValues.stream().anyMatch(entry -> { + return !Objects.equals(entry.value.get(), entry.spec.getDefault()); + }); + } + + @Override + public void restoreDefaults() + { + // Block world configs since the path is dynamic + if (ConfigHelper.isWorldConfig(this) && this.config.getConfigData() == null) + { + return; + } + + // Creates a copy of the config data then pushes all at once to avoid multiple IO ops + CommentedConfig newConfig = CommentedConfig.copy(this.config.getConfigData()); + this.allConfigValues.forEach(entry -> newConfig.set(entry.value.getPath(), entry.spec.getDefault())); + this.config.getConfigData().putAll(newConfig); + + // Finally clear cache of all config values + this.allConfigValues.forEach(pair -> pair.value.clearCache()); + } + + private static List<IcebergValueEntry> getAllConfigValues(ModConfig config) + { + IcebergConfigSpec icebergConfigSpec = (IcebergConfigSpec) config.getSpec(); + List<Pair<ForgeConfigSpec.ConfigValue<?>, ForgeConfigSpec.ValueSpec>> values = Lists.newArrayList(); + gatherValuesFromIcebergConfig(icebergConfigSpec.getValues(), icebergConfigSpec, values); + return ImmutableList.copyOf(values).stream().map(pair -> new IcebergValueEntry(pair.getFirst(), pair.getSecond())).collect(Collectors.toList()); + } + + private static void gatherValuesFromIcebergConfig(UnmodifiableConfig config, IcebergConfigSpec spec, List<Pair<ForgeConfigSpec.ConfigValue<?>, ForgeConfigSpec.ValueSpec>> values) + { + config.valueMap().forEach((key, value) -> + { + if (value instanceof AbstractConfig) + { + gatherValuesFromIcebergConfig((UnmodifiableConfig) value, spec, values); + } + else if (value instanceof ForgeConfigSpec.ConfigValue<?> configValue) + { + ForgeConfigSpec.ValueSpec valueSpec = spec.getRaw(configValue.getPath()); + values.add(Pair.of(configValue, valueSpec)); + } + }); + } + + private record IcebergValueEntry(ForgeConfigSpec.ConfigValue<?> value, ForgeConfigSpec.ValueSpec spec) {} +} diff --git a/src/main/java/com/anthonyhilyard/iceberg/compat/configured/IcebergConfigProvider.java b/src/main/java/com/anthonyhilyard/iceberg/compat/configured/IcebergConfigProvider.java new file mode 100644 index 0000000..6eda2ee --- /dev/null +++ b/src/main/java/com/anthonyhilyard/iceberg/compat/configured/IcebergConfigProvider.java @@ -0,0 +1,45 @@ +package com.anthonyhilyard.iceberg.compat.configured; + +import java.util.EnumMap; +import java.util.HashSet; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import com.anthonyhilyard.iceberg.config.IcebergConfigSpec; +import com.mrcrayfish.configured.api.IConfigProvider; +import com.mrcrayfish.configured.api.IModConfig; + +import net.minecraftforge.fml.ModContainer; +import net.minecraftforge.fml.config.ConfigTracker; +import net.minecraftforge.fml.config.ModConfig; +import net.minecraftforge.fml.util.ObfuscationReflectionHelper; + +public class IcebergConfigProvider implements IConfigProvider +{ + @Override + public Set<IModConfig> getConfigurationsForMod(ModContainer container) + { + // Add Iceberg configurations + Set<IModConfig> configs = new HashSet<>(); + addIcebergConfigsToMap(container, ModConfig.Type.CLIENT, configs::add); + addIcebergConfigsToMap(container, ModConfig.Type.COMMON, configs::add); + addIcebergConfigsToMap(container, ModConfig.Type.SERVER, configs::add); + return configs; + } + + private static void addIcebergConfigsToMap(ModContainer container, ModConfig.Type type, Consumer<IModConfig> consumer) + { + getForgeTrackedConfigs().get(type).stream() + .filter(config -> config.getModId().equals(container.getModId()) && config.getSpec() instanceof IcebergConfigSpec) + .map(IcebergConfigPlugin::new) + .collect(Collectors.toSet()) + .forEach(consumer); + } + + private static EnumMap<ModConfig.Type, Set<ModConfig>> getForgeTrackedConfigs() + { + return ObfuscationReflectionHelper.getPrivateValue(ConfigTracker.class, ConfigTracker.INSTANCE, "configSets"); + } + +} diff --git a/src/main/java/com/anthonyhilyard/iceberg/compat/configured/IcebergFolderEntry.java b/src/main/java/com/anthonyhilyard/iceberg/compat/configured/IcebergFolderEntry.java new file mode 100644 index 0000000..c9d3612 --- /dev/null +++ b/src/main/java/com/anthonyhilyard/iceberg/compat/configured/IcebergFolderEntry.java @@ -0,0 +1,160 @@ +package com.anthonyhilyard.iceberg.compat.configured; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.Nullable; + +import com.anthonyhilyard.iceberg.config.IcebergConfigSpec; +import com.electronwill.nightconfig.core.UnmodifiableConfig; +import com.google.common.collect.ImmutableList; +import com.mrcrayfish.configured.api.IConfigEntry; +import com.mrcrayfish.configured.api.IConfigValue; +import com.mrcrayfish.configured.api.ValueEntry; +import com.mrcrayfish.configured.impl.forge.ForgeEnumValue; +import com.mrcrayfish.configured.impl.forge.ForgeListValue; +import com.mrcrayfish.configured.impl.forge.ForgeValue; + +import net.minecraft.client.resources.language.I18n; +import net.minecraft.network.chat.Component; +import net.minecraftforge.common.ForgeConfigSpec; + +public class IcebergFolderEntry implements IConfigEntry +{ + protected final List<String> path; + protected final UnmodifiableConfig config; + protected final IcebergConfigSpec spec; + private final String customComment; + protected List<IConfigEntry> entries; + + public IcebergFolderEntry(UnmodifiableConfig config, IcebergConfigSpec spec) + { + this(new ArrayList<>(), config, spec); + } + + public IcebergFolderEntry(List<String> path, UnmodifiableConfig config, IcebergConfigSpec spec) + { + this(path, config, spec, null); + } + + public IcebergFolderEntry(List<String> path, UnmodifiableConfig config, IcebergConfigSpec spec, String customComment) + { + this.path = path; + this.config = config; + this.spec = spec; + this.customComment = customComment; + } + + @Override + @SuppressWarnings("unchecked") + public List<IConfigEntry> getChildren() + { + if (this.entries == null) + { + ImmutableList.Builder<IConfigEntry> builder = ImmutableList.builder(); + + this.config.valueMap().forEach((key, value) -> + { + if (value instanceof ForgeConfigSpec.ValueSpec valueSpec && valueSpec.getDefault() instanceof UnmodifiableConfig) + { + value = valueSpec.getDefault(); + } + + if (value instanceof UnmodifiableConfig) + { + List<String> path = new ArrayList<>(this.path); + path.add(key); + builder.add(new IcebergFolderEntry(path, (UnmodifiableConfig) value, this.spec)); + } + else if (value instanceof ForgeConfigSpec.ConfigValue<?> configValue) + { + ForgeConfigSpec.ValueSpec valueSpec = this.spec.getRaw(configValue.getPath()); + if (valueSpec != null) + { + if (configValue.get() instanceof List<?>) + { + builder.add(new ValueEntry(new ForgeListValue((ForgeConfigSpec.ConfigValue<List<?>>) configValue, valueSpec))); + } + else if (configValue.get() instanceof Enum<?>) + { + builder.add(new ValueEntry(new ForgeEnumValue<>((ForgeConfigSpec.EnumValue<?>) configValue, valueSpec))); + } + // Configured doesn't currently support map configuration values, so leave a message for users. + else if (configValue.get() instanceof UnmodifiableConfig) + { + List<String> path = new ArrayList<>(this.path); + path.add(key); + builder.add(new IcebergFolderEntry(path, (UnmodifiableConfig) configValue.get(), this.spec, "This is a map configuration value, which is not currently supported by Configured. To edit this value, please modify the configuration file directly.")); + } + else + { + builder.add(new ValueEntry(new ForgeValue<>(configValue, valueSpec))); + } + } + } + }); + this.entries = builder.build(); + } + return this.entries; + } + + @Override + public boolean isRoot() + { + return this.path.isEmpty(); + } + + @Override + public boolean isLeaf() + { + return false; + } + + @Override + public IConfigValue<?> getValue() + { + return null; + } + + @Override + public String getEntryName() + { + return ForgeValue.lastValue(this.path, "Root"); + } + + @Nullable + @Override + public Component getTooltip() + { + if (customComment != null) + { + return Component.translatable(customComment); + } + else + { + String translationKey = this.getTranslationKey(); + if (translationKey != null) + { + String tooltipKey = translationKey + ".tooltip"; + if (I18n.exists(tooltipKey)) + { + return Component.translatable(tooltipKey); + } + } + String comment = this.spec.getLevelComment(this.path); + if (comment != null) + { + return Component.literal(comment); + } + return null; + } + } + + @Nullable + @Override + public String getTranslationKey() + { + return this.spec.getLevelTranslationKey(this.path); + } + +} diff --git a/src/main/java/com/anthonyhilyard/iceberg/mixin/ConfiguredConfigHelperMixin.java b/src/main/java/com/anthonyhilyard/iceberg/mixin/ConfiguredConfigHelperMixin.java deleted file mode 100644 index 9918740..0000000 --- a/src/main/java/com/anthonyhilyard/iceberg/mixin/ConfiguredConfigHelperMixin.java +++ /dev/null @@ -1,55 +0,0 @@ -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, require = 0) - 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 deleted file mode 100644 index 1d0882a..0000000 --- a/src/main/java/com/anthonyhilyard/iceberg/mixin/ConfiguredModConfigSelectionScreenMixin.java +++ /dev/null @@ -1,216 +0,0 @@ -package com.anthonyhilyard.iceberg.mixin; - -import java.lang.reflect.Field; -import java.util.List; -import java.util.ArrayList; - -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, require = 0) - 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, List.of(), ((IcebergConfigSpec) config.getSpec()).getValues(), dummySpec, (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; - private final List<String> path; - public IcebergFolderEntry(ConfigScreen configScreen, List<String> path, UnmodifiableConfig config, ForgeConfigSpec spec, IcebergConfigSpec icebergSpec) - { - configScreen.super(path, config, spec); - icebergConfigSpec = icebergSpec; - this.spec = spec; - this.configScreen = configScreen; - this.config = config; - this.path = path; - 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) - { - List<String> path = new ArrayList<>(this.path); - path.add(key); - builder.add(new IcebergFolderEntry(configScreen, path, (UnmodifiableConfig) value, spec, icebergConfigSpec)); - } - else if (value instanceof ForgeConfigSpec.ConfigValue<?>) - { - ForgeConfigSpec.ConfigValue<?> configValue = (ForgeConfigSpec.ConfigValue<?>) value; - 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/MixinConfig.java b/src/main/java/com/anthonyhilyard/iceberg/mixin/MixinConfig.java index 566843c..f71f4aa 100644 --- a/src/main/java/com/anthonyhilyard/iceberg/mixin/MixinConfig.java +++ b/src/main/java/com/anthonyhilyard/iceberg/mixin/MixinConfig.java @@ -7,12 +7,11 @@ 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 { + @SuppressWarnings("unused") private LoadingModList loadingModList = null; @Override @@ -24,25 +23,6 @@ public class MixinConfig implements IMixinConfigPlugin @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; } diff --git a/src/main/java/com/anthonyhilyard/iceberg/util/Tooltips.java b/src/main/java/com/anthonyhilyard/iceberg/util/Tooltips.java index 63ec096..6bcb2b0 100644 --- a/src/main/java/com/anthonyhilyard/iceberg/util/Tooltips.java +++ b/src/main/java/com/anthonyhilyard/iceberg/util/Tooltips.java @@ -40,6 +40,7 @@ import net.minecraftforge.common.MinecraftForge; public class Tooltips { + private static final FormattedCharSequence SPACE = FormattedCharSequence.forward(" ", Style.EMPTY); private static ItemRenderer itemRenderer = null; public static class TooltipInfo @@ -56,6 +57,7 @@ public class Tooltips } public int getTooltipWidth() { return tooltipWidth; } + public int getTooltipHeight() { return components.size() > titleLines ? components.size() * 10 + 2 : 8; } public int getTitleLines() { return titleLines; } public Font getFont() { return font; } public List<ClientTooltipComponent> getComponents() { return components; } @@ -64,16 +66,21 @@ public class Tooltips public int getMaxLineWidth() { - int width = 0; + return getMaxLineWidth(0); + } + + public int getMaxLineWidth(int minWidth) + { + int textWidth = minWidth; for (ClientTooltipComponent component : components) { int componentWidth = component.getWidth(font); - if (componentWidth > width) + if (componentWidth > textWidth) { - width = componentWidth; + textWidth = componentWidth; } } - return width; + return textWidth; } } @@ -179,7 +186,7 @@ public class Tooltips for (int componentNumber = 0; componentNumber < info.getComponents().size(); ++componentNumber) { ClientTooltipComponent imageComponent = info.getComponents().get(componentNumber); - imageComponent.renderImage(preEvent.getFont(), rectX, tooltipTop, poseStack, itemRenderer, 400); + imageComponent.renderImage(preEvent.getFont(), rectX, tooltipTop, poseStack, itemRenderer, zLevel); tooltipTop += imageComponent.getHeight() + (componentNumber == 0 ? 2 : 0); } @@ -348,10 +355,9 @@ public class Tooltips List<ClientTooltipComponent> result = new ArrayList<>(components); FormattedCharSequence title = Language.getInstance().getVisualOrder(recomposedLines.get(0)); - FormattedCharSequence space = FormattedCharSequence.forward(" ", Style.EMPTY); while (result.get(0).getWidth(font) < tooltipWidth) { - title = FormattedCharSequence.fromList(List.of(space, title, space)); + title = FormattedCharSequence.fromList(List.of(SPACE, title, SPACE)); if (title == null) { break; |