aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshedaniel <daniel@shedaniel.me>2024-09-24 11:36:20 +0800
committershedaniel <daniel@shedaniel.me>2024-09-24 11:36:20 +0800
commit0f3e25a5c940f88f2abfa1f860be113a8a3d0c3d (patch)
tree2182190a219f54363c78d732eccf28ae70ccfac7
parent9856139ad309ab833defb92ccfedaf48b9bde64e (diff)
parentadf5fd11cb45fdcb5ffed90571d68bb406f36f19 (diff)
downloadRoughlyEnoughItems-0f3e25a5c940f88f2abfa1f860be113a8a3d0c3d.tar.gz
RoughlyEnoughItems-0f3e25a5c940f88f2abfa1f860be113a8a3d0c3d.tar.bz2
RoughlyEnoughItems-0f3e25a5c940f88f2abfa1f860be113a8a3d0c3d.zip
Merge branch '9.x-1.19' into 12.x-1.20
# Conflicts: # runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/configure/PanelBoundariesConfiguration.java # runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/TooltipPreviewer.java # runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryHighlighter.java
-rw-r--r--api/build.gradle6
-rwxr-xr-xbuild.gradle2
-rw-r--r--default-plugin/build.gradle8
-rw-r--r--fabric/build.gradle10
-rw-r--r--forge/build.gradle16
-rw-r--r--forge/src/main/java/me/shedaniel/rei/plugin/client/forge/DefaultClientPluginImpl.java8
-rwxr-xr-xgradle/wrapper/gradle-wrapper.properties2
-rw-r--r--runtime/build.gradle8
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java2
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigCategories.java1
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigGroups.java7
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigOptions.java23
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/ComparableValue.java70
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/OptionValueEntry.java2
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/configure/PanelBoundariesConfiguration.java2
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/preview/TooltipPreviewer.java2
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryHighlighter.java21
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListWidget.java2
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/search/collapsed/CollapsedEntriesCache.java5
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/cs_cz.json3
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/de_de.json55
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/en_au.json179
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/en_ca.json179
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/en_gb.json179
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/en_nz.json179
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/en_ud.json179
-rwxr-xr-xruntime/src/main/resources/assets/roughlyenoughitems/lang/en_us.json8
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/eo_uy.json5
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/es_es.json121
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/fr_fr.json13
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/he_il.json4
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/it_it.json340
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/ja_jp.json260
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/ko_kr.json300
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/lol_us.json171
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/lzh.json256
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/nn_no.json32
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/pl_pl.json63
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/pt_br.json1
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/ru_ru.json60
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/tr_tr.json90
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/uk_ua.json3
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/vi_vn.json382
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/zh_cn.json72
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/zh_tw.json76
45 files changed, 2184 insertions, 1223 deletions
diff --git a/api/build.gradle b/api/build.gradle
index 44b099077..b559795c5 100644
--- a/api/build.gradle
+++ b/api/build.gradle
@@ -13,7 +13,7 @@ architectury {
}
remapJar {
- classifier "raw"
+ archiveClassifier = "raw"
}
task fakeJar(type: Jar, dependsOn: remapJar) {
@@ -21,7 +21,7 @@ task fakeJar(type: Jar, dependsOn: remapJar) {
from(rootProject.file("fake/fabric.mod.json")) {
into ""
}
- classifier null
+ archiveClassifier = null
}
task fakeForgeJar(type: Jar, dependsOn: jar) {
@@ -35,7 +35,7 @@ task fakeForgeJar(type: Jar, dependsOn: jar) {
into "me/shedaniel/rei/forge"
}
}
- classifier "fake-forge"
+ archiveClassifier = "fake-forge"
}
artifacts {
diff --git a/build.gradle b/build.gradle
index 37c68cc53..bd9487c04 100755
--- a/build.gradle
+++ b/build.gradle
@@ -1,6 +1,6 @@
plugins {
id("architectury-plugin") version("3.4-SNAPSHOT")
- id("dev.architectury.loom") version("0.12.0-SNAPSHOT") apply false
+ id("dev.architectury.loom") version("1.7-SNAPSHOT") apply false
id("org.cadixdev.licenser") version("0.6.1")
id("me.shedaniel.unified-publishing") version("0.1.+")
id("maven-publish")
diff --git a/default-plugin/build.gradle b/default-plugin/build.gradle
index c47536992..ab4c56b45 100644
--- a/default-plugin/build.gradle
+++ b/default-plugin/build.gradle
@@ -8,7 +8,7 @@ dependencies {
modCompileOnly("net.fabricmc:fabric-loader:${project.fabricloader_version}")
modApi("me.shedaniel.cloth:cloth-config:${cloth_config_version}")
modApi("dev.architectury:architectury:${architectury_version}")
- compileClasspath(project(path: ":api", configuration: "namedElements"))
+ compileOnly(project(path: ":api", configuration: "namedElements"))
}
architectury {
@@ -16,7 +16,7 @@ architectury {
}
remapJar {
- classifier "raw"
+ archiveClassifier = "raw"
}
task fakeJar(type: Jar, dependsOn: remapJar) {
@@ -24,7 +24,7 @@ task fakeJar(type: Jar, dependsOn: remapJar) {
from(rootProject.file("fake/fabric.mod.json")) {
into ""
}
- classifier null
+ archiveClassifier = null
}
task fakeForgeJar(type: Jar, dependsOn: jar) {
@@ -38,7 +38,7 @@ task fakeForgeJar(type: Jar, dependsOn: jar) {
into "me/shedaniel/rei/forge"
}
}
- classifier "fake-forge"
+ archiveClassifier = "fake-forge"
}
artifacts {
diff --git a/fabric/build.gradle b/fabric/build.gradle
index 20abfcba1..a979d9829 100644
--- a/fabric/build.gradle
+++ b/fabric/build.gradle
@@ -46,13 +46,13 @@ dependencies {
shadowJar {
configurations = [project.configurations.shadowCommon]
- classifier "dev-shadow"
+ archiveClassifier = "dev-shadow"
}
remapJar {
input.set shadowJar.archiveFile
dependsOn shadowJar
- classifier null
+ archiveClassifier = null
}
task renameJarForPublication(type: Zip, dependsOn: remapJar) {
@@ -66,7 +66,7 @@ task renameJarForPublication(type: Zip, dependsOn: remapJar) {
assemble.dependsOn renameJarForPublication
jar {
- classifier "dev"
+ archiveClassifier = "dev"
}
java {
@@ -106,6 +106,10 @@ publishing {
builtBy remapSourcesJarTask
classifier "sources"
}
+
+ // Hack to inherit the dependencies without inheriting the artifacts
+ publication.setArtifacts(publication.artifacts)
+ from components.java
}
}
}
diff --git a/forge/build.gradle b/forge/build.gradle
index b2ca8e075..fae774db0 100644
--- a/forge/build.gradle
+++ b/forge/build.gradle
@@ -133,13 +133,13 @@ def modRuntime(str) {
shadowJar {
configurations = [project.configurations.shadowCommon]
- classifier "dev-shadow"
+ archiveClassifier = "dev-shadow"
}
remapJar {
input.set shadowJar.archiveFile
dependsOn shadowJar
- classifier null
+ archiveClassifier = null
}
task renameJarForPublication(type: Zip, dependsOn: remapJar) {
@@ -153,7 +153,7 @@ task renameJarForPublication(type: Zip, dependsOn: remapJar) {
assemble.dependsOn renameJarForPublication
jar {
- classifier "dev"
+ archiveClassifier = "dev"
}
java {
@@ -171,7 +171,7 @@ sourcesJar {
}
task serverOnlyJar(type: Jar, dependsOn: [remapJar]) {
- classifier "server-only"
+ archiveClassifier = "server-only"
from(zipTree(remapJar.archiveFile.get().asFile)) {
exclude "META-INF/mods.toml", "mezz/**", "me/shedaniel/rei/forge/RoughlyEnoughItemsForge.class", "me/shedaniel/rei/forge/JEIStub.class"
}
@@ -197,12 +197,12 @@ publishing {
["api", "default-plugin"].forEach { projectName ->
def remapSrg = tasks.create("remapSrgJarFor$projectName", net.fabricmc.loom.task.RemapJarTask) {
inputFile = project(":" + projectName).tasks.jar.archiveFile
- classifier "srg-remapped-$projectName"
+ archiveClassifier = "srg-remapped-$projectName"
targetNamespace = "srg"
}
def remapSrgSourcesJar = tasks.create("remapSrgSourcesFor$projectName", net.fabricmc.loom.task.RemapSourcesJarTask) {
inputFile = project(":" + projectName).tasks.sourcesJar.archiveFile
- classifier "srg-remapped-$projectName-sources"
+ archiveClassifier = "srg-remapped-$projectName-sources"
targetNamespace = "srg"
}
create(projectName + "Forge", MavenPublication.class) { publication ->
@@ -215,6 +215,10 @@ publishing {
builtBy remapSrgSourcesJar
classifier "sources"
}
+
+ // Hack to inherit the dependencies without inheriting the artifacts
+ publication.setArtifacts(publication.artifacts)
+ from components.java
}
}
}
diff --git a/forge/src/main/java/me/shedaniel/rei/plugin/client/forge/DefaultClientPluginImpl.java b/forge/src/main/java/me/shedaniel/rei/plugin/client/forge/DefaultClientPluginImpl.java
index 64ce38b62..8c389d3e8 100644
--- a/forge/src/main/java/me/shedaniel/rei/plugin/client/forge/DefaultClientPluginImpl.java
+++ b/forge/src/main/java/me/shedaniel/rei/plugin/client/forge/DefaultClientPluginImpl.java
@@ -59,9 +59,9 @@ public class DefaultClientPluginImpl extends DefaultClientPlugin {
Set<Potion> potions = Sets.newLinkedHashSet();
for (Ingredient container : PotionBrewing.ALLOWED_CONTAINERS) {
for (PotionBrewing.Mix<Potion> mix : PotionBrewing.POTION_MIXES) {
- Holder.Reference<Potion> from = mix.f_43532_;
+ Holder.Reference<Potion> from = mix.from;
Ingredient ingredient = mix.ingredient;
- Holder.Reference<Potion> to = mix.f_43534_;
+ Holder.Reference<Potion> to = mix.to;
Ingredient base = Ingredient.of(Arrays.stream(container.getItems())
.map(ItemStack::copy)
.map(stack -> PotionUtils.setPotion(stack, from.get())));
@@ -76,9 +76,9 @@ public class DefaultClientPluginImpl extends DefaultClientPlugin {
}
for (Potion potion : potions) {
for (PotionBrewing.Mix<Item> mix : PotionBrewing.CONTAINER_MIXES) {
- Holder.Reference<Item> from = mix.f_43532_;
+ Holder.Reference<Item> from = mix.from;
Ingredient ingredient = mix.ingredient;
- Holder.Reference<Item> to = mix.f_43534_;
+ Holder.Reference<Item> to = mix.to;
Ingredient base = Ingredient.of(PotionUtils.setPotion(new ItemStack(from.get()), potion));
ItemStack output = PotionUtils.setPotion(new ItemStack(to.get()), potion);
clientPlugin.registerBrewingRecipe(base, ingredient, output);
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 8f6579526..0b2225055 100755
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip
diff --git a/runtime/build.gradle b/runtime/build.gradle
index ef54168cc..547ffb9e3 100644
--- a/runtime/build.gradle
+++ b/runtime/build.gradle
@@ -12,8 +12,8 @@ dependencies {
modCompileOnly("net.fabricmc:fabric-loader:${project.fabricloader_version}")
modApi("me.shedaniel.cloth:cloth-config:${cloth_config_version}")
modApi("dev.architectury:architectury:${architectury_version}")
- compileClasspath(annotationProcessor("org.projectlombok:lombok:1.18.22"))
- compileClasspath(project(path: ":api", configuration: "namedElements"))
+ compileOnly(annotationProcessor("org.projectlombok:lombok:1.18.22"))
+ compileOnly(project(path: ":api", configuration: "namedElements"))
testImplementation(project(path: ":api", configuration: "namedElements"))
testImplementation("org.junit.jupiter:junit-jupiter:5.8.2")
}
@@ -23,7 +23,7 @@ test {
}
remapJar {
- classifier "raw"
+ archiveClassifier = "raw"
}
task fakeJar(type: Jar, dependsOn: remapJar) {
@@ -31,7 +31,7 @@ task fakeJar(type: Jar, dependsOn: remapJar) {
from(rootProject.file("fake/fabric.mod.json")) {
into ""
}
- classifier null
+ archiveClassifier = null
}
artifacts {
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java
index 7840fa6cd..41e91b7c9 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java
@@ -658,6 +658,8 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData {
@Comment("Declares whether subsets is enabled.")
public boolean isSubsetsEnabled = false;
public boolean allowInventoryHighlighting = true;
+ public double inventoryHighlightingDarkenOpacity = 0.85;
+ public double inventoryHighlightingOpacity = 1.0;
public ItemCheatingMode itemCheatingMode = ItemCheatingMode.REI_LIKE;
}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigCategories.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigCategories.java
index 40e94ae10..0749f11a8 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigCategories.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigCategories.java
@@ -51,6 +51,7 @@ public interface AllREIConfigCategories {
OptionCategory ACCESSIBILITY = make("accessibility")
.add(ACCESSIBILITY_DISPLAY)
.add(ACCESSIBILITY_WIDGETS)
+ .add(ACCESSIBILITY_INVENTORY_SEARCH)
.add(ACCESSIBILITY_FEATURES);
OptionCategory FILTERING = make("filtering")
.add(FILTERING_FILTERING)
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigGroups.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigGroups.java
index b206fd6e5..474132b8e 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigGroups.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigGroups.java
@@ -68,10 +68,13 @@ public interface AllREIConfigGroups {
OptionGroup ACCESSIBILITY_WIDGETS = make("accessibility.widgets")
.add(SCROLLBAR_VISIBILITY)
.add(CLICKABLE_RECIPE_ARROWS);
+ OptionGroup ACCESSIBILITY_INVENTORY_SEARCH = make("accessibility.inventory_search")
+ .add(INVENTORY_SEARCH_MODE)
+ .add(INVENTORY_SEARCH_DARKEN_OPACITY)
+ .add(INVENTORY_SEARCH_OPACITY);
OptionGroup ACCESSIBILITY_FEATURES = make("accessibility.features")
.add(VANILLA_RECIPE_BOOK)
- .add(STATUS_EFFECTS_LOCATION)
- .add(INVENTORY_SEARCH);
+ .add(STATUS_EFFECTS_LOCATION);
OptionGroup FILTERING_FILTERING = make("filtering.filtering")
.add(CATEGORIES)
.add(CUSTOMIZED_FILTERING);
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigOptions.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigOptions.java
index 97119df2e..30a673e38 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigOptions.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/AllREIConfigOptions.java
@@ -60,6 +60,15 @@ public interface AllREIConfigOptions {
translatable("config.rei.options." + id + ".desc"), bind, save);
}
+ static ComparableValue<Double>[] doubleRange(double start, double end, double step) {
+ int length = (int) Math.ceil((end - start) / step + 1);
+ ComparableValue<Double>[] result = new ComparableValue[length];
+ for (int i = 0; i < length; i++) {
+ result[i] = ComparableValue.ofDouble(Math.min(start + i * step, end));
+ }
+ return result;
+ }
+
CompositeOption<AppearanceTheme> THEME = make("appearance.theme", i -> i.appearance.theme, (i, v) -> i.appearance.theme = v)
.enumOptions();
CompositeOption<RecipeBorderType> RECIPE_BORDER = make("appearance.recipe_border", i -> i.appearance.recipeBorder, (i, v) -> i.appearance.recipeBorder = v)
@@ -140,12 +149,18 @@ public interface AllREIConfigOptions {
.ofBoolean(translatable("config.rei.value.accessibility.scrollbar_visibility.when_scrolling"), translatable("config.rei.value.accessibility.scrollbar_visibility.always"));
CompositeOption<Boolean> CLICKABLE_RECIPE_ARROWS = make("accessibility.clickable_recipe_arrows", i -> i.advanced.miscellaneous.clickableRecipeArrows, (i, v) -> i.advanced.miscellaneous.clickableRecipeArrows = v)
.enabledDisabled();
+ CompositeOption<Boolean> INVENTORY_SEARCH_MODE = make("accessibility.inventory_search_mode", i -> i.functionality.allowInventoryHighlighting, (i, v) -> i.functionality.allowInventoryHighlighting = v)
+ .enabledDisabled();
+ CompositeOption<ComparableValue<Double>> INVENTORY_SEARCH_DARKEN_OPACITY = make("accessibility.inventory_search_darken_opacity", i -> ComparableValue.ofDouble(i.functionality.inventoryHighlightingDarkenOpacity), (i, v) -> i.functionality.inventoryHighlightingDarkenOpacity = v.value())
+ .entry(OptionValueEntry.options(doubleRange(0.0, 1.0, 0.05))
+ .overrideText(d -> literal("%.0f%%".formatted(d.value() * 100))));
+ CompositeOption<ComparableValue<Double>> INVENTORY_SEARCH_OPACITY = make("accessibility.inventory_search_opacity", i -> ComparableValue.ofDouble(i.functionality.inventoryHighlightingOpacity), (i, v) -> i.functionality.inventoryHighlightingOpacity = v.value())
+ .entry(OptionValueEntry.options(doubleRange(0.0, 1.0, 0.05))
+ .overrideText(d -> literal("%.0f%%".formatted(d.value() * 100))));
CompositeOption<Boolean> VANILLA_RECIPE_BOOK = make("accessibility.vanilla_recipe_book", i -> !i.functionality.disableRecipeBook, (i, v) -> i.functionality.disableRecipeBook = !v)
.enabledDisabled();
CompositeOption<Boolean> STATUS_EFFECTS_LOCATION = make("accessibility.status_effects_location", i -> i.functionality.leftSideMobEffects, (i, v) -> i.functionality.leftSideMobEffects = v)
.ofBoolean(translatable("config.rei.value.accessibility.status_effects_location.right"), translatable("config.rei.value.accessibility.status_effects_location.left"));
- CompositeOption<Boolean> INVENTORY_SEARCH = make("accessibility.inventory_search", i -> i.functionality.allowInventoryHighlighting, (i, v) -> i.functionality.allowInventoryHighlighting = v)
- .enabledDisabled();
CompositeOption<ConfigureCategoriesScreen> CATEGORIES = make("filtering.categories", i -> {
return new ConfigureCategoriesScreen(
new HashMap<>(i.getFilteringQuickCraftCategories()),
@@ -182,7 +197,9 @@ public interface AllREIConfigOptions {
.ofBoolean(translatable("config.rei.value.list.display_mode.paginated"), translatable("config.rei.value.list.display_mode.scrolled"));
CompositeOption<EntryPanelOrderingConfig> ORDERING = make("list.ordering", i -> i.advanced.layout.entryPanelOrdering, (i, v) -> i.advanced.layout.entryPanelOrdering = v)
.enumOptions();
- CompositeOption<Double> ZOOM = make("list.zoom", i -> i.advanced.accessibility.entrySize, (i, v) -> i.advanced.accessibility.entrySize = v);
+ CompositeOption<ComparableValue<Double>> ZOOM = make("list.zoom", i -> ComparableValue.ofDouble(i.advanced.accessibility.entrySize), (i, v) -> i.advanced.accessibility.entrySize = v.value())
+ .entry(OptionValueEntry.options(doubleRange(0.25, 4.0, 0.25))
+ .overrideText(d -> literal("%.0f%%".formatted(d.value() * 100))));
CompositeOption<Boolean> FOCUS_MODE = make("list.focus_mode", i -> i.appearance.isFocusModeZoomed, (i, v) -> i.appearance.isFocusModeZoomed = v)
.ofBoolean(translatable("config.rei.value.list.focus_mode.highlighted"), translatable("config.rei.value.list.focus_mode.zoomed"));
CompositeOption<CollapsibleConfigManager.CollapsibleConfigObject> COLLAPSIBLE_ENTRIES = make("list.collapsible_entries", i -> {
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/ComparableValue.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/ComparableValue.java
new file mode 100644
index 000000000..d3cea57a3
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/ComparableValue.java
@@ -0,0 +1,70 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.impl.client.gui.config.options;
+
+import org.jetbrains.annotations.ApiStatus;
+
+import java.util.Objects;
+import java.util.function.BiPredicate;
+
+@ApiStatus.Internal
+public final class ComparableValue<T> {
+ private final T value;
+ private final BiPredicate<T, Object> equals;
+
+ private ComparableValue(T value, BiPredicate<T, Object> equals) {
+ this.value = value;
+ this.equals = equals;
+ }
+
+ public static <T> ComparableValue<T> of(T value, BiPredicate<T, Object> equals) {
+ return new ComparableValue<>(value, equals);
+ }
+
+ public static ComparableValue<Float> ofFloat(float value) {
+ return of(value, (a, b) -> b instanceof Float f && Math.abs(a - f) <= 0.001F);
+ }
+
+ public static ComparableValue<Double> ofDouble(double value) {
+ return of(value, (a, b) -> b instanceof Double d && Math.abs(a - d) <= 0.001D);
+ }
+
+ public T value() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof ComparableValue) {
+ return equals.test(value, ((ComparableValue<?>) obj).value);
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashCode() {