aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Hilyard <anthony.hilyard@gmail.com>2022-01-13 15:13:04 -0800
committerAnthony Hilyard <anthony.hilyard@gmail.com>2022-01-13 15:13:04 -0800
commit7a3df325b5bb294c2836082f58b719c70792ed61 (patch)
tree9d7596152c590f0be111141173702661d2309d48
parentbd85cc8ebd856605b458555a967647987b09945e (diff)
downloadIceberg-7a3df325b5bb294c2836082f58b719c70792ed61.tar.gz
Iceberg-7a3df325b5bb294c2836082f58b719c70792ed61.tar.bz2
Iceberg-7a3df325b5bb294c2836082f58b719c70792ed61.zip
Added subconfig capability to Forge's config system.
-rw-r--r--CHANGELOG.md136
-rw-r--r--gradle.properties2
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/mixin/ForgeConfigSpecMixin.java160
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/util/DynamicSubconfig.java138
-rw-r--r--src/main/resources/iceberg.mixins.json5
5 files changed, 438 insertions, 3 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..4ab1705
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,136 @@
+# Changelog
+
+### 1.0.39
+- Fixed an issue in Forge's configuration system that prevented dynamic subconfigs from working properly.
+
+### 1.0.38
+- Added support for tooltip components that use tooltip component generation event.
+
+### 1.0.37
+- Reverted first change from 1.0.35, as it was causing conflicts with other mod's tooltips.
+
+### 1.0.36
+- Fixed a crash issue with modded tooltip components that are not properly added to tooltip component factory.
+
+### 1.0.35
+- Fixed an issue that could cause dependent client-side mods to crash when run on a dedicated server.
+- Fixed various warnings in latest.log file.
+- Fixed bug causing incorrect tooltip background alpha.
+
+### 1.0.34
+- Improved item color detection for mods that do not properly implement item name colors.
+
+### 1.0.33
+- Improved extended tooltip events to better support multiple simultaneous tooltip rendering.
+- Fixed bug in Minecraft's text color handling to fully support alpha values.
+
+### 1.0.32
+- Fixed a crash bug caused by invalid color codes in item names.
+- Improved NBT selector to recognize tags in lists. ("&id=minecraft:sharpness" works for anything enchanted with Sharpness, for example)
+- Bumped required Forge version.
+
+### 1.0.31
+- Fixed a rare issue that could prevent the game from loading.
+
+### 1.0.30
+- Added support for ItemEdit item name colors.
+- Fixed tooltip rect calculation issues.
+- Added constrained tooltip component gathering helper.
+
+### 1.0.29
+- Overhauled tooltip handling to support 1.18 tooltip components.
+- First Forge 1.18 release.
+
+### 1.0.28
+- Added support for color-code specified item name colors.
+
+### 1.0.27
+- Fixed a bug with dynamic resource packs that prevented dynamic resources from properly overriding.
+- Added minimum width constrain option for tooltip rendering.
+
+### 1.0.26
+- Added NBT selector.
+- Added selector syntax validator.
+
+### 1.0.25
+- Added dynamic resource pack helper.
+- First Fabric 1.18 release.
+
+### 1.0.24
+- Rewrote client-side item pickup event so Iceberg is no longer required on servers (for that event).
+
+### 1.0.23
+- Fixed an issue with tooltip events causing inaccurate tooltip bounding box for tooltips near the edge of the screen.
+
+### 1.0.22
+- Consolidated configuration item selector logic for dependent mods, so new selectors can be added without requiring mod updates.
+
+### 1.0.21
+- Fixed a crash bug caused by an incompatibility with Architectury.
+
+### 1.0.20
+- Added rendertick event, added color results for color event.
+
+### 1.0.19
+- Fixed a crash bug when rendering custom gradients.
+
+### 1.0.18
+- Network protocol rewrite.
+- Fixed final warning.
+
+### 1.0.17
+- Fixed jar versioning for Mod Menu (Fabric).
+
+### 1.0.16
+- Fixed a crash bug due to missing fonts on tooltips.
+- First Fabric 1.17 release.
+
+### 1.0.15
+- Added StringRecomposer helper.
+
+### 1.0.14
+- Readded a post-tooltip rendering event, since RenderTooltipEvent.PostText was removed from Forge.
+
+### 1.0.13
+- Fixed an access issue on the custom ItemRenderer class.
+
+### 1.0.12
+- Fixed a mod compatibility issue for mods that interacted with advancements. (Such as Clickable Advancements)
+- First Forge 1.17 release.
+
+### 1.0.11
+- Fixed a rare null-pointer exception when calculating tooltips.
+
+### 1.0.10
+- Added extended tooltip rendering events to better facilitate tooltip customization.
+
+### 1.0.9
+- Added GuiHelper class with generic rendering helper methods.
+- Added Color easing helper function to Easing class.
+
+### 1.0.8
+- Fixed a bug that was preventing auto-registered sounds from working in multiplayer.
+
+### 1.0.7
+- Added helper entity registry methods.
+
+### 1.0.6
+- Added renderer support for auto registration system.
+
+### 1.0.5
+- Added network protocol and new event for remote pre-item pickup events.
+
+### 1.0.4
+- Added new helper method to render item tooltips without vanilla positioning restrictions.
+
+### 1.0.3
+- Added helper functions to auto registration class for easy registration of entities and sounds.
+
+### 1.0.2
+- Added a simple automatic registration utility class.
+
+### 1.0.1
+- Added tooltip helper.
+
+### 1.0.0
+- Initial release. \ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 0c29540..3e4c4b9 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.38
+version=1.0.39
mcVersion=1.18.1
forgeVersion=39.0.9
diff --git a/src/main/java/com/anthonyhilyard/iceberg/mixin/ForgeConfigSpecMixin.java b/src/main/java/com/anthonyhilyard/iceberg/mixin/ForgeConfigSpecMixin.java
new file mode 100644
index 0000000..288af26
--- /dev/null
+++ b/src/main/java/com/anthonyhilyard/iceberg/mixin/ForgeConfigSpecMixin.java
@@ -0,0 +1,160 @@
+package com.anthonyhilyard.iceberg.mixin;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+import com.anthonyhilyard.iceberg.util.DynamicSubconfig;
+import com.electronwill.nightconfig.core.CommentedConfig;
+import com.electronwill.nightconfig.core.UnmodifiableConfig;
+import com.electronwill.nightconfig.core.ConfigSpec.CorrectionAction;
+import com.electronwill.nightconfig.core.ConfigSpec.CorrectionListener;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Overwrite;
+import org.spongepowered.asm.mixin.Shadow;
+
+import net.minecraftforge.common.ForgeConfigSpec;
+import net.minecraftforge.common.ForgeConfigSpec.ValueSpec;
+
+
+@Mixin(value = ForgeConfigSpec.class, remap = false)
+public class ForgeConfigSpecMixin
+{
+ @Shadow(remap = false)
+ private Map<List<String>, String> levelComments;
+
+ @Shadow(remap = false)
+ private boolean stringsMatchIgnoringNewlines(@Nullable Object obj1, @Nullable Object obj2) { return false; }
+
+ /**
+ * @author iceberg
+ * @reason Overwrite the correct method to fix subconfigs not being handled properly.
+ */
+ @Overwrite(remap = false)
+ private int correct(UnmodifiableConfig spec, CommentedConfig config, LinkedList<String> parentPath, List<String> parentPathUnmodifiable, CorrectionListener listener, CorrectionListener commentListener, boolean dryRun)
+ {
+ int count = 0;
+
+ Map<String, Object> specMap = spec.valueMap();
+ Map<String, Object> configMap = config.valueMap();
+
+ for (Map.Entry<String, Object> specEntry : specMap.entrySet())
+ {
+ final String key = specEntry.getKey();
+ Object specValue = specEntry.getValue();
+ final Object configValue = configMap.get(key);
+ final CorrectionAction action = configValue == null ? CorrectionAction.ADD : CorrectionAction.REPLACE;
+
+ parentPath.addLast(key);
+
+ String subConfigComment = null;
+
+ // If this value is a config, use that as the spec value to support subconfigs.
+ if (specValue instanceof ValueSpec valueSpec && valueSpec.getDefault() instanceof UnmodifiableConfig)
+ {
+ subConfigComment = valueSpec.getComment();
+ specValue = valueSpec.getDefault();
+ }
+
+ if (specValue instanceof UnmodifiableConfig)
+ {
+ if (configValue instanceof CommentedConfig)
+ {
+ count += correct((UnmodifiableConfig)specValue, (CommentedConfig)configValue, parentPath, parentPathUnmodifiable, listener, commentListener, dryRun);
+ if (count > 0 && dryRun)
+ {
+ return count;
+ }
+ }
+ else if (dryRun)
+ {
+ return 1;
+ }
+ else
+ {
+ CommentedConfig newValue = config.createSubConfig();
+ configMap.put(key, newValue);
+ listener.onCorrect(action, parentPathUnmodifiable, configValue, newValue);
+ count++;
+ count += correct((UnmodifiableConfig)specValue, newValue, parentPath, parentPathUnmodifiable, listener, commentListener, dryRun);
+ }
+
+ String newComment = subConfigComment == null ? levelComments.get(parentPath) : subConfigComment;
+ String oldComment = config.getComment(key);
+ if (!stringsMatchIgnoringNewlines(oldComment, newComment))
+ {
+ if (commentListener != null)
+ {
+ commentListener.onCorrect(action, parentPathUnmodifiable, oldComment, newComment);
+ }
+
+ if (dryRun)
+ {
+ return 1;
+ }
+
+ config.setComment(key, newComment);
+ }
+ }
+ else
+ {
+ ValueSpec valueSpec = (ValueSpec)specValue;
+ if (!valueSpec.test(configValue))
+ {
+ if (dryRun)
+ {
+ return 1;
+ }
+
+ Object newValue = valueSpec.correct(configValue);
+ configMap.put(key, newValue);
+ listener.onCorrect(action, parentPathUnmodifiable, configValue, newValue);
+ count++;
+ }
+ String oldComment = config.getComment(key);
+ if (!stringsMatchIgnoringNewlines(oldComment, valueSpec.getComment()))
+ {
+ if (commentListener != null)
+ {
+ commentListener.onCorrect(action, parentPathUnmodifiable, oldComment, valueSpec.getComment());
+ }
+
+ if (dryRun)
+ {
+ return 1;
+ }
+
+ config.setComment(key, valueSpec.getComment());
+ }
+ }
+
+ parentPath.removeLast();
+ }
+
+ // Second step: removes the unspecified values
+ for (Iterator<Map.Entry<String, Object>> ittr = configMap.entrySet().iterator(); ittr.hasNext();)
+ {
+ Map.Entry<String, Object> entry = ittr.next();
+
+ // If the spec is a dynamic subconfig, don't bother checking the spec since that's the point.
+ if (!(spec instanceof DynamicSubconfig) && !specMap.containsKey(entry.getKey()))
+ {
+ if (dryRun)
+ {
+ return 1;
+ }
+
+ ittr.remove();
+ parentPath.addLast(entry.getKey());
+ listener.onCorrect(CorrectionAction.REMOVE, parentPathUnmodifiable, entry.getValue(), null);
+ parentPath.removeLast();
+ count++;
+ }
+ }
+ return count;
+ }
+}
diff --git a/src/main/java/com/anthonyhilyard/iceberg/util/DynamicSubconfig.java b/src/main/java/com/anthonyhilyard/iceberg/util/DynamicSubconfig.java
new file mode 100644
index 0000000..3ed17f3
--- /dev/null
+++ b/src/main/java/com/anthonyhilyard/iceberg/util/DynamicSubconfig.java
@@ -0,0 +1,138 @@
+package com.anthonyhilyard.iceberg.util;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Supplier;
+
+import com.electronwill.nightconfig.core.AbstractCommentedConfig;
+import com.electronwill.nightconfig.core.ConfigFormat;
+import com.electronwill.nightconfig.core.UnmodifiableCommentedConfig;
+import com.electronwill.nightconfig.core.UnmodifiableConfig;
+
+/**
+ * An exact copy of SimpleCommentedConfig, but this class is specifically meant for subconfigs.
+ * That being said--the class of a config is checked during config validation, and subconfigs are allowed
+ * extra leniency in config keys.
+ */
+final public class DynamicSubconfig extends AbstractCommentedConfig
+{
+ private final ConfigFormat<?> configFormat;
+
+ /**
+ * Creates a Subconfig with the specified format.
+ *
+ * @param configFormat the config's format
+ */
+ DynamicSubconfig(ConfigFormat<?> configFormat, boolean concurrent)
+ {
+ super(concurrent ? new ConcurrentHashMap<>() : new HashMap<>());
+ this.configFormat = configFormat;
+ }
+
+ /**
+ * Creates a Subconfig with the specified data and format. The map is used as it is and
+ * isn't copied.
+ */
+ DynamicSubconfig(Map<String, Object> valueMap, ConfigFormat<?> configFormat)
+ {
+ super(valueMap);
+ this.configFormat = configFormat;
+ }
+
+ /**
+ * Creates a Subconfig with the specified backing map supplier and format.
+ *
+ * @param mapCreator the supplier for backing maps
+ * @param configFormat the config's format
+ */
+ DynamicSubconfig(Supplier<Map<String, Object>> mapCreator, ConfigFormat<?> configFormat)
+ {
+ super(mapCreator);
+ this.configFormat = configFormat;
+ }
+
+ /**
+ * Creates a Subconfig by copying a config and with the specified format.
+ *
+ * @param toCopy the config to copy
+ * @param configFormat the config's format
+ */
+ DynamicSubconfig(UnmodifiableConfig toCopy, ConfigFormat<?> configFormat,
+ boolean concurrent)
+ {
+ super(toCopy, concurrent);
+ this.configFormat = configFormat;
+ }
+
+ /**
+ * Creates a Subconfig by copying a config, with the specified backing map creator and format.
+ *
+ * @param toCopy the config to copy
+ * @param mapCreator the supplier for backing maps
+ * @param configFormat the config's format
+ */
+ public DynamicSubconfig(UnmodifiableConfig toCopy, Supplier<Map<String, Object>> mapCreator,
+ ConfigFormat<?> configFormat)
+ {
+ super(toCopy, mapCreator);
+ this.configFormat = configFormat;
+ }
+
+ /**
+ * Creates a Subconfig by copying a config and with the specified format.
+ *
+ * @param toCopy the config to copy
+ * @param configFormat the config's format
+ */
+ DynamicSubconfig(UnmodifiableCommentedConfig toCopy, ConfigFormat<?> configFormat,
+ boolean concurrent)
+ {
+ super(toCopy, concurrent);
+ this.configFormat = configFormat;
+ }
+
+ /**
+ * Creates a Subconfig by copying a config, with the specified backing map creator and format.
+ *
+ * @param toCopy the config to copy
+ * @param mapCreator the supplier for backing maps
+ * @param configFormat the config's format
+ */
+ public DynamicSubconfig(UnmodifiableCommentedConfig toCopy, Supplier<Map<String, Object>> mapCreator,
+ ConfigFormat<?> configFormat)
+ {
+ super(toCopy, mapCreator);
+ this.configFormat = configFormat;
+ }
+
+ @Override
+ public ConfigFormat<?> configFormat()
+ {
+ return configFormat;
+ }
+
+ @Override
+ public DynamicSubconfig createSubConfig()
+ {
+ return new DynamicSubconfig(mapCreator, configFormat);
+ }
+
+ @Override
+ public AbstractCommentedConfig clone()
+ {
+ return new DynamicSubconfig(this, mapCreator, configFormat);
+ }
+
+ /**
+ * Creates a new Subconfig with the content of the given config. The returned config will have
+ * the same format as the copied config.
+ *
+ * @param config the config to copy
+ * @return a copy of the config
+ */
+ static DynamicSubconfig copy(UnmodifiableConfig config)
+ {
+ return new DynamicSubconfig(config, config.configFormat(), false);
+ }
+} \ No newline at end of file
diff --git a/src/main/resources/iceberg.mixins.json b/src/main/resources/iceberg.mixins.json
index 6ee1aca..f167048 100644
--- a/src/main/resources/iceberg.mixins.json
+++ b/src/main/resources/iceberg.mixins.json
@@ -1,11 +1,12 @@
{
"required": true,
"package": "com.anthonyhilyard.iceberg.mixin",
- "compatibilityLevel": "JAVA_16",
+ "compatibilityLevel": "JAVA_17",
"refmap": "iceberg.refmap.json",
"mixins": [
"EntityMixin",
- "PlayerAdvancementsMixin"
+ "PlayerAdvancementsMixin",
+ "ForgeConfigSpecMixin"
],
"client": [
"ScreenMixin",