mirror of
https://github.com/Creators-of-Create/Create.git
synced 2025-02-27 20:34:43 +01:00
lost in the depths
- add a search box to config screens - add a new screen that gives easier access to other mod's configs - add a couple more config annotations
This commit is contained in:
parent
ca02ac038f
commit
370c813287
15 changed files with 702 additions and 169 deletions
|
@ -1,5 +1,7 @@
|
||||||
package com.simibubi.create.foundation.config;
|
package com.simibubi.create.foundation.config;
|
||||||
|
|
||||||
|
import com.simibubi.create.foundation.config.ui.ConfigAnnotations;
|
||||||
|
|
||||||
public class CClient extends ConfigBase {
|
public class CClient extends ConfigBase {
|
||||||
|
|
||||||
public ConfigGroup client = group(0, "client",
|
public ConfigGroup client = group(0, "client",
|
||||||
|
@ -42,11 +44,11 @@ public class CClient extends ConfigBase {
|
||||||
"Offset the overlay from goggle- and hover- information by this many pixels on the Y axis; Use /create overlay");
|
"Offset the overlay from goggle- and hover- information by this many pixels on the Y axis; Use /create overlay");
|
||||||
public ConfigBool overlayCustomColor = b(false, "customColorsOverlay", "Enable this to use your custom colors for the Goggle- and Hover- Overlay");
|
public ConfigBool overlayCustomColor = b(false, "customColorsOverlay", "Enable this to use your custom colors for the Goggle- and Hover- Overlay");
|
||||||
public ConfigInt overlayBackgroundColor = i(0xf0_100010, Integer.MIN_VALUE, Integer.MAX_VALUE, "customBackgroundOverlay",
|
public ConfigInt overlayBackgroundColor = i(0xf0_100010, Integer.MIN_VALUE, Integer.MAX_VALUE, "customBackgroundOverlay",
|
||||||
"The custom background color to use for the Goggle- and Hover- Overlays, if enabled", "[in Hex: #AaRrGgBb]", "[@cui:IntDisplay:#]");
|
"The custom background color to use for the Goggle- and Hover- Overlays, if enabled", "[in Hex: #AaRrGgBb]", ConfigAnnotations.IntDisplay.HEX.asComment());
|
||||||
public ConfigInt overlayBorderColorTop = i(0x50_5000ff, Integer.MIN_VALUE, Integer.MAX_VALUE, "customBorderTopOverlay",
|
public ConfigInt overlayBorderColorTop = i(0x50_5000ff, Integer.MIN_VALUE, Integer.MAX_VALUE, "customBorderTopOverlay",
|
||||||
"The custom top color of the border gradient to use for the Goggle- and Hover- Overlays, if enabled", "[in Hex: #AaRrGgBb]", "[@cui:IntDisplay:#]");
|
"The custom top color of the border gradient to use for the Goggle- and Hover- Overlays, if enabled", "[in Hex: #AaRrGgBb]", ConfigAnnotations.IntDisplay.HEX.asComment());
|
||||||
public ConfigInt overlayBorderColorBot = i(0x50_28007f, Integer.MIN_VALUE, Integer.MAX_VALUE, "customBorderBotOverlay",
|
public ConfigInt overlayBorderColorBot = i(0x50_28007f, Integer.MIN_VALUE, Integer.MAX_VALUE, "customBorderBotOverlay",
|
||||||
"The custom bot color of the border gradient to use for the Goggle- and Hover- Overlays, if enabled", "[in Hex: #AaRrGgBb]", "[@cui:IntDisplay:#]");
|
"The custom bot color of the border gradient to use for the Goggle- and Hover- Overlays, if enabled", "[in Hex: #AaRrGgBb]", ConfigAnnotations.IntDisplay.HEX.asComment());
|
||||||
|
|
||||||
//placement assist group
|
//placement assist group
|
||||||
public ConfigGroup placementAssist = group(1, "placementAssist", "Settings for the Placement Assist");
|
public ConfigGroup placementAssist = group(1, "placementAssist", "Settings for the Placement Assist");
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
package com.simibubi.create.foundation.config;
|
package com.simibubi.create.foundation.config;
|
||||||
|
|
||||||
|
import com.simibubi.create.foundation.config.ui.ConfigAnnotations;
|
||||||
|
|
||||||
public class CKinetics extends ConfigBase {
|
public class CKinetics extends ConfigBase {
|
||||||
|
|
||||||
public ConfigBool disableStress = b(false, "disableStress", Comments.disableStress);
|
public ConfigBool disableStress = b(false, "disableStress", Comments.disableStress);
|
||||||
public ConfigInt maxBeltLength = i(20, 5, "maxBeltLength", Comments.maxBeltLength);
|
public ConfigInt maxBeltLength = i(20, 5, "maxBeltLength", Comments.maxBeltLength);
|
||||||
public ConfigInt crushingDamage = i(4, 0, "crushingDamage", Comments.crushingDamage);
|
public ConfigInt crushingDamage = i(4, 0, "crushingDamage", Comments.crushingDamage);
|
||||||
public ConfigInt maxMotorSpeed = i(256, 64, "maxMotorSpeed", Comments.rpm, Comments.maxMotorSpeed);
|
public ConfigInt maxMotorSpeed = i(256, 64, "maxMotorSpeed", Comments.rpm, Comments.maxMotorSpeed, ConfigAnnotations.RequiresRestart.BOTH.asComment());
|
||||||
public ConfigInt waterWheelBaseSpeed = i(4, 1, "waterWheelBaseSpeed", Comments.rpm, Comments.waterWheelBaseSpeed);
|
public ConfigInt waterWheelBaseSpeed = i(4, 1, "waterWheelBaseSpeed", Comments.rpm, Comments.waterWheelBaseSpeed);
|
||||||
public ConfigInt waterWheelFlowSpeed = i(4, 1, "waterWheelFlowSpeed", Comments.rpm, Comments.waterWheelFlowSpeed);
|
public ConfigInt waterWheelFlowSpeed = i(4, 1, "waterWheelFlowSpeed", Comments.rpm, Comments.waterWheelFlowSpeed);
|
||||||
public ConfigInt furnaceEngineSpeed = i(16, 1, "furnaceEngineSpeed", Comments.rpm, Comments.furnaceEngineSpeed);
|
public ConfigInt furnaceEngineSpeed = i(16, 1, "furnaceEngineSpeed", Comments.rpm, Comments.furnaceEngineSpeed);
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package com.simibubi.create.foundation.config.ui;
|
package com.simibubi.create.foundation.config.ui;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
@ -26,43 +29,65 @@ import net.minecraftforge.fml.config.ModConfig;
|
||||||
|
|
||||||
public class BaseConfigScreen extends ConfigScreen {
|
public class BaseConfigScreen extends ConfigScreen {
|
||||||
|
|
||||||
private static final DelegatedStencilElement.ElementRenderer DISABLED_RENDERER = (ms, width, height, alpha) -> UIRenderHelper.angledGradient(ms, 0, 0, height / 2, height, width, Theme.p(Theme.Key.BUTTON_DISABLE));
|
public static final DelegatedStencilElement.ElementRenderer DISABLED_RENDERER = (ms, width, height, alpha) -> UIRenderHelper.angledGradient(ms, 0, 0, height / 2, height, width, Theme.p(Theme.Key.BUTTON_DISABLE));
|
||||||
|
private static final Map<String, UnaryOperator<BaseConfigScreen>> defaults = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
defaults.put("create", (base) -> base
|
||||||
|
.withTitles("Client Settings", "World Generation Settings", "Gameplay Settings")
|
||||||
|
.withSpecs(AllConfigs.CLIENT.specification, AllConfigs.COMMON.specification, AllConfigs.SERVER.specification)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If you are a Create Addon dev and want to change the config labels,
|
||||||
|
* add a default action here.
|
||||||
|
*
|
||||||
|
* Make sure you call either {@link #withSpecs(ForgeConfigSpec, ForgeConfigSpec, ForgeConfigSpec)}
|
||||||
|
* or {@link #searchForSpecsInModContainer()}
|
||||||
|
*
|
||||||
|
* @param modID the modID of your addon/mod
|
||||||
|
*/
|
||||||
|
public static void setDefaultActionFor(String modID, UnaryOperator<BaseConfigScreen> transform) {
|
||||||
|
if (modID.equalsIgnoreCase("create"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
defaults.put(modID, transform);
|
||||||
|
}
|
||||||
|
|
||||||
public static BaseConfigScreen forCreate(Screen parent) {
|
public static BaseConfigScreen forCreate(Screen parent) {
|
||||||
return new BaseConfigScreen(parent)
|
return new BaseConfigScreen(parent);
|
||||||
.withTitles("Client Settings", "World Generation Settings", "Gameplay Settings")
|
|
||||||
.withSpecs(AllConfigs.CLIENT.specification, AllConfigs.COMMON.specification, AllConfigs.SERVER.specification);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BoxWidget clientConfigWidget;
|
BoxWidget clientConfigWidget;
|
||||||
BoxWidget commonConfigWidget;
|
BoxWidget commonConfigWidget;
|
||||||
BoxWidget serverConfigWidget;
|
BoxWidget serverConfigWidget;
|
||||||
BoxWidget goBack;
|
BoxWidget goBack;
|
||||||
|
BoxWidget others;
|
||||||
BoxWidget title;
|
BoxWidget title;
|
||||||
|
|
||||||
ForgeConfigSpec clientSpec;
|
ForgeConfigSpec clientSpec;
|
||||||
ForgeConfigSpec commonSpec;
|
ForgeConfigSpec commonSpec;
|
||||||
ForgeConfigSpec serverSpec;
|
ForgeConfigSpec serverSpec;
|
||||||
String clientTile = "CLIENT CONFIG";
|
String clientTile = "Client Config";
|
||||||
String commonTile = "COMMON CONFIG";
|
String commonTile = "Common Config";
|
||||||
String serverTile = "SERVER CONFIG";
|
String serverTile = "Server Config";
|
||||||
String modID = Create.ID;
|
String modID;
|
||||||
protected boolean returnOnClose;
|
protected boolean returnOnClose;
|
||||||
|
|
||||||
/**
|
|
||||||
* If you are a Create Addon dev and want to make use of the same GUI
|
|
||||||
* for your mod's config, use this Constructor to create a entry point
|
|
||||||
*
|
|
||||||
* @param parent the previously opened screen
|
|
||||||
* @param modID the modID of your addon/mod
|
|
||||||
*/
|
|
||||||
public BaseConfigScreen(Screen parent, @Nonnull String modID) {
|
public BaseConfigScreen(Screen parent, @Nonnull String modID) {
|
||||||
this(parent);
|
super(parent);
|
||||||
this.modID = modID;
|
this.modID = modID;
|
||||||
|
|
||||||
|
if (defaults.containsKey(modID))
|
||||||
|
defaults.get(modID).apply(this);
|
||||||
|
else {
|
||||||
|
this.searchForSpecsInModContainer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private BaseConfigScreen(Screen parent) {
|
private BaseConfigScreen(Screen parent) {
|
||||||
super(parent);
|
this(parent, Create.ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -70,22 +95,26 @@ public class BaseConfigScreen extends ConfigScreen {
|
||||||
* please use {@link #withSpecs(ForgeConfigSpec, ForgeConfigSpec, ForgeConfigSpec)} instead
|
* please use {@link #withSpecs(ForgeConfigSpec, ForgeConfigSpec, ForgeConfigSpec)} instead
|
||||||
*/
|
*/
|
||||||
public BaseConfigScreen searchForSpecsInModContainer() {
|
public BaseConfigScreen searchForSpecsInModContainer() {
|
||||||
|
if (!ConfigHelper.hasAnyConfig(this.modID)){
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
clientSpec = ConfigHelper.findConfigSpecFor(ModConfig.Type.CLIENT, this.modID);
|
clientSpec = ConfigHelper.findConfigSpecFor(ModConfig.Type.CLIENT, this.modID);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Create.LOGGER.warn("Unable to find ClientConfigSpec for mod: " + this.modID);
|
Create.LOGGER.debug("Unable to find ClientConfigSpec for mod: " + this.modID);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
commonSpec = ConfigHelper.findConfigSpecFor(ModConfig.Type.COMMON, this.modID);
|
commonSpec = ConfigHelper.findConfigSpecFor(ModConfig.Type.COMMON, this.modID);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Create.LOGGER.warn("Unable to find CommonConfigSpec for mod: " + this.modID, e);
|
Create.LOGGER.debug("Unable to find CommonConfigSpec for mod: " + this.modID);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
serverSpec = ConfigHelper.findConfigSpecFor(ModConfig.Type.SERVER, this.modID);
|
serverSpec = ConfigHelper.findConfigSpecFor(ModConfig.Type.SERVER, this.modID);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Create.LOGGER.warn("Unable to find ServerConfigSpec for mod: " + this.modID, e);
|
Create.LOGGER.debug("Unable to find ServerConfigSpec for mod: " + this.modID);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
@ -191,6 +220,13 @@ public class BaseConfigScreen extends ConfigScreen {
|
||||||
goBack.getToolTip()
|
goBack.getToolTip()
|
||||||
.add(new StringTextComponent("Go Back"));
|
.add(new StringTextComponent("Go Back"));
|
||||||
widgets.add(goBack);
|
widgets.add(goBack);
|
||||||
|
|
||||||
|
TextStencilElement othersText = new TextStencilElement(minecraft.font, new StringTextComponent("Access Configs of other Mods")).centered(true, true);
|
||||||
|
others = new BoxWidget(width / 2 - 100, height / 2 - 15 + 90, 200, 16).showingElement(othersText);
|
||||||
|
othersText.withElementRenderer(BoxWidget.gradientFactory.apply(others));
|
||||||
|
others.withCallback(() -> linkTo(new ConfigModListScreen(this)));
|
||||||
|
widgets.add(others);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
package com.simibubi.create.foundation.config.ui;
|
||||||
|
|
||||||
|
public class ConfigAnnotations {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the way the Integer value is display.
|
||||||
|
*/
|
||||||
|
public enum IntDisplay implements ConfigAnnotation {
|
||||||
|
HEX("#"),
|
||||||
|
ZERO_X("0x"),
|
||||||
|
ZERO_B("0b");
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
IntDisplay(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "IntDisplay";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates to the player that changing this value will require a restart to take full effect
|
||||||
|
*/
|
||||||
|
public enum RequiresRestart implements ConfigAnnotation {
|
||||||
|
CLIENT("client"),
|
||||||
|
SERVER("server"),
|
||||||
|
BOTH("both");
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
RequiresRestart(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "RequiresReload";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates to the player that changing this value will require them to relog to take full effect
|
||||||
|
*/
|
||||||
|
public enum RequiresRelog implements ConfigAnnotation {
|
||||||
|
TRUE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "RequiresRelog";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changing a value that is annotated with Execute will cause the player to run the given command automatically.
|
||||||
|
*/
|
||||||
|
public static class Execute implements ConfigAnnotation {
|
||||||
|
|
||||||
|
private final String command;
|
||||||
|
|
||||||
|
public static Execute run(String command) {
|
||||||
|
return new Execute(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Execute(String command) {
|
||||||
|
this.command = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Execute";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValue() {
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ConfigAnnotation {
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
default String getValue() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
default String asComment() {
|
||||||
|
String comment = "[@cui:" + getName();
|
||||||
|
String value = getValue();
|
||||||
|
if (value != null) {
|
||||||
|
comment = comment + ":" + value;
|
||||||
|
}
|
||||||
|
comment = comment + "]";
|
||||||
|
return comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,18 +2,25 @@ package com.simibubi.create.foundation.config.ui;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import com.google.common.cache.CacheBuilder;
|
import com.google.common.cache.CacheBuilder;
|
||||||
import com.google.common.cache.CacheLoader;
|
import com.google.common.cache.CacheLoader;
|
||||||
import com.google.common.cache.LoadingCache;
|
import com.google.common.cache.LoadingCache;
|
||||||
import com.simibubi.create.Create;
|
import com.simibubi.create.Create;
|
||||||
import com.simibubi.create.foundation.config.AllConfigs;
|
import com.simibubi.create.foundation.config.AllConfigs;
|
||||||
|
import com.simibubi.create.foundation.utility.Pair;
|
||||||
|
|
||||||
import net.minecraftforge.common.ForgeConfigSpec;
|
import net.minecraftforge.common.ForgeConfigSpec;
|
||||||
import net.minecraftforge.fml.ModContainer;
|
import net.minecraftforge.fml.ModContainer;
|
||||||
|
@ -23,6 +30,10 @@ import net.minecraftforge.fml.config.ModConfig;
|
||||||
|
|
||||||
public class ConfigHelper {
|
public class ConfigHelper {
|
||||||
|
|
||||||
|
public static final Pattern unitPattern = Pattern.compile("\\[(in .*)]");
|
||||||
|
public static final Pattern annotationPattern = Pattern.compile("\\[@cui:([^:]*)(?::(.*))?]");
|
||||||
|
|
||||||
|
public static final Map<String, ConfigChange> changes = new HashMap<>();
|
||||||
private static final LoadingCache<String, EnumMap<ModConfig.Type, ModConfig>> configCache = CacheBuilder.newBuilder().expireAfterAccess(5, TimeUnit.MINUTES).build(
|
private static final LoadingCache<String, EnumMap<ModConfig.Type, ModConfig>> configCache = CacheBuilder.newBuilder().expireAfterAccess(5, TimeUnit.MINUTES).build(
|
||||||
new CacheLoader<String, EnumMap<ModConfig.Type, ModConfig>>() {
|
new CacheLoader<String, EnumMap<ModConfig.Type, ModConfig>>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -54,6 +65,11 @@ public class ConfigHelper {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean hasAnyConfig(String modID) {
|
||||||
|
EnumMap<ModConfig.Type, ModConfig> map = configCache.getUnchecked(modID);
|
||||||
|
return map.entrySet().size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
//Directly set a value
|
//Directly set a value
|
||||||
public static <T> void setConfigValue(ConfigPath path, String value) throws InvalidValueException {
|
public static <T> void setConfigValue(ConfigPath path, String value) throws InvalidValueException {
|
||||||
ForgeConfigSpec spec = findConfigSpecFor(path.getType(), path.getModID());
|
ForgeConfigSpec spec = findConfigSpecFor(path.getType(), path.getModID());
|
||||||
|
@ -68,18 +84,51 @@ public class ConfigHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add a value to the current UI's changes list
|
//Add a value to the current UI's changes list
|
||||||
public static <T> void setValue(String path, ForgeConfigSpec.ConfigValue<T> configValue, T value) {
|
public static <T> void setValue(String path, ForgeConfigSpec.ConfigValue<T> configValue, T value, @Nullable Map<String, String> annotations) {
|
||||||
if (value.equals(configValue.get())) {
|
if (value.equals(configValue.get())) {
|
||||||
ConfigScreen.changes.remove(path);
|
changes.remove(path);
|
||||||
} else {
|
} else {
|
||||||
ConfigScreen.changes.put(path, value);
|
changes.put(path, annotations == null ? new ConfigChange(value) : new ConfigChange(value, annotations));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Get a value from the current UI's changes list or the config value, if its unchanged
|
//Get a value from the current UI's changes list or the config value, if its unchanged
|
||||||
public static <T> T getValue(String path, ForgeConfigSpec.ConfigValue<T> configValue) {
|
public static <T> T getValue(String path, ForgeConfigSpec.ConfigValue<T> configValue) {
|
||||||
//noinspection unchecked
|
ConfigChange configChange = changes.get(path);
|
||||||
return (T) ConfigScreen.changes.getOrDefault(path, configValue.get());
|
if (configChange != null)
|
||||||
|
//noinspection unchecked
|
||||||
|
return (T) configChange.value;
|
||||||
|
else
|
||||||
|
return configValue.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Pair<String, Map<String, String>> readMetadataFromComment(List<String> commentLines) {
|
||||||
|
AtomicReference<String> unit = new AtomicReference<>();
|
||||||
|
Map<String, String> annotations = new HashMap<>();
|
||||||
|
|
||||||
|
commentLines.removeIf(line -> {
|
||||||
|
if (line.trim().isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matcher matcher = annotationPattern.matcher(line);
|
||||||
|
if (matcher.matches()) {
|
||||||
|
String annotation = matcher.group(1);
|
||||||
|
String aValue = matcher.group(2);
|
||||||
|
annotations.putIfAbsent(annotation, aValue);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
matcher = unitPattern.matcher(line);
|
||||||
|
if (matcher.matches()) {
|
||||||
|
unit.set(matcher.group(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
return Pair.of(unit.get(), annotations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ConfigPath {
|
public static class ConfigPath {
|
||||||
|
@ -138,5 +187,20 @@ public class ConfigHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ConfigChange {
|
||||||
|
Object value;
|
||||||
|
Map<String, String> annotations;
|
||||||
|
|
||||||
|
ConfigChange(Object value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigChange(Object value, Map<String, String> annotations) {
|
||||||
|
this(value);
|
||||||
|
this.annotations = new HashMap<>();
|
||||||
|
this.annotations.putAll(annotations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class InvalidValueException extends Exception {}
|
public static class InvalidValueException extends Exception {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,156 @@
|
||||||
|
package com.simibubi.create.foundation.config.ui;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
|
import com.simibubi.create.foundation.gui.AllIcons;
|
||||||
|
import com.simibubi.create.foundation.gui.DelegatedStencilElement;
|
||||||
|
import com.simibubi.create.foundation.gui.ScreenOpener;
|
||||||
|
import com.simibubi.create.foundation.gui.Theme;
|
||||||
|
import com.simibubi.create.foundation.gui.widgets.BoxWidget;
|
||||||
|
import com.simibubi.create.foundation.item.TooltipHelper;
|
||||||
|
|
||||||
|
import net.minecraft.client.gui.screen.Screen;
|
||||||
|
import net.minecraft.util.text.StringTextComponent;
|
||||||
|
import net.minecraft.util.text.TextFormatting;
|
||||||
|
import net.minecraftforge.fml.ModList;
|
||||||
|
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
|
||||||
|
|
||||||
|
public class ConfigModListScreen extends ConfigScreen {
|
||||||
|
|
||||||
|
ConfigScreenList list;
|
||||||
|
HintableTextFieldWidget search;
|
||||||
|
BoxWidget goBack;
|
||||||
|
List<ModEntry> allEntries;
|
||||||
|
|
||||||
|
public ConfigModListScreen(Screen parent) {
|
||||||
|
super(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
list.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init() {
|
||||||
|
widgets.clear();
|
||||||
|
super.init();
|
||||||
|
|
||||||
|
int listWidth = Math.min(width - 80, 300);
|
||||||
|
|
||||||
|
list = new ConfigScreenList(minecraft, listWidth, height - 60, 15, height - 45, 40);
|
||||||
|
list.setLeftPos(this.width / 2 - list.getWidth() / 2);
|
||||||
|
children.add(list);
|
||||||
|
|
||||||
|
allEntries = new ArrayList<>();
|
||||||
|
ModList.get().getMods().stream().map(ModInfo::getModId).forEach(id -> allEntries.add(new ModEntry(id, this)));
|
||||||
|
allEntries.sort((e1, e2) -> {
|
||||||
|
int empty = (e2.button.active ? 1 : 0) - (e1.button.active ? 1 : 0);
|
||||||
|
if (empty != 0)
|
||||||
|
return empty;
|
||||||
|
|
||||||
|
return e1.id.compareToIgnoreCase(e2.id);
|
||||||
|
});
|
||||||
|
list.children().clear();
|
||||||
|
list.children().addAll(allEntries);
|
||||||
|
|
||||||
|
goBack = new BoxWidget(width / 2 - listWidth / 2 - 30, height / 2 + 65, 20, 20).withPadding(2, 2)
|
||||||
|
.withCallback(this::onClose);
|
||||||
|
goBack.showingElement(AllIcons.I_CONFIG_BACK.asStencil()
|
||||||
|
.withElementRenderer(BoxWidget.gradientFactory.apply(goBack)));
|
||||||
|
goBack.getToolTip()
|
||||||
|
.add(new StringTextComponent("Go Back"));
|
||||||
|
widgets.add(goBack);
|
||||||
|
|
||||||
|
search = new HintableTextFieldWidget(font, width / 2 - listWidth / 2, height - 35, listWidth, 20);
|
||||||
|
search.setResponder(this::updateFilter);
|
||||||
|
search.setHint("Search..");
|
||||||
|
search.moveCursorToStart();
|
||||||
|
widgets.add(search);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void renderWindow(MatrixStack ms, int mouseX, int mouseY, float partialTicks) {
|
||||||
|
|
||||||
|
list.render(ms, mouseX, mouseY, partialTicks);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClose() {
|
||||||
|
super.onClose();
|
||||||
|
ScreenOpener.open(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateFilter(String search) {
|
||||||
|
list.children().clear();
|
||||||
|
allEntries
|
||||||
|
.stream()
|
||||||
|
.filter(modEntry -> modEntry.id.contains(search.toLowerCase(Locale.ROOT)))
|
||||||
|
.forEach(list.children()::add);
|
||||||
|
|
||||||
|
list.setScrollAmount(list.getScrollAmount());
|
||||||
|
if (list.children().size() > 0) {
|
||||||
|
this.search.setTextColor(Theme.i(Theme.Key.TEXT));
|
||||||
|
} else {
|
||||||
|
this.search.setTextColor(Theme.i(Theme.Key.BUTTON_FAIL));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ModEntry extends ConfigScreenList.LabeledEntry {
|
||||||
|
|
||||||
|
protected BoxWidget button;
|
||||||
|
protected String id;
|
||||||
|
|
||||||
|
public ModEntry(String id, Screen parent) {
|
||||||
|
super(toHumanReadable(id));
|
||||||
|
this.id = id;
|
||||||
|
|
||||||
|
button = new BoxWidget(0, 0, 35, 16)
|
||||||
|
.showingElement(AllIcons.I_CONFIG_OPEN.asStencil().at(10, 0));
|
||||||
|
button.modifyElement(e -> ((DelegatedStencilElement) e).withElementRenderer(BoxWidget.gradientFactory.apply(button)));
|
||||||
|
|
||||||
|
if (ConfigHelper.hasAnyConfig(id)) {
|
||||||
|
button.withCallback(() -> ScreenOpener.open(new BaseConfigScreen(parent, id)));
|
||||||
|
} else {
|
||||||
|
button.active = false;
|
||||||
|
button.updateColorsFromState();
|
||||||
|
button.modifyElement(e -> ((DelegatedStencilElement) e).withElementRenderer(BaseConfigScreen.DISABLED_RENDERER));
|
||||||
|
labelTooltip.add(new StringTextComponent(toHumanReadable(id)));
|
||||||
|
labelTooltip.addAll(TooltipHelper.cutTextComponent(new StringTextComponent("This Mod does not have any configs registered or is not using Forge's config system"), TextFormatting.GRAY, TextFormatting.GRAY));
|
||||||
|
}
|
||||||
|
|
||||||
|
listeners.add(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
button.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(MatrixStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean p_230432_9_, float partialTicks) {
|
||||||
|
super.render(ms, index, y, x, width, height, mouseX, mouseY, p_230432_9_, partialTicks);
|
||||||
|
|
||||||
|
button.x = x + width - 108;
|
||||||
|
button.y = y + 10;
|
||||||
|
button.setHeight(height - 20);
|
||||||
|
button.render(ms, mouseX, mouseY, partialTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getLabelWidth(int totalWidth) {
|
||||||
|
return (int) (totalWidth * labelWidthMult) + 30;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,11 +39,9 @@ public abstract class ConfigScreen extends AbstractSimiScreen {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* zelo's list for configUI
|
* TO DO
|
||||||
*
|
*
|
||||||
* reduce number of packets sent to the server when saving a bunch of values
|
* reduce number of packets sent to the server when saving a bunch of values
|
||||||
* maybe replace java's awt color with something mutable
|
|
||||||
* find out why framebuffer blending is incorrect
|
|
||||||
*
|
*
|
||||||
* FIXME
|
* FIXME
|
||||||
*
|
*
|
||||||
|
@ -54,7 +52,6 @@ public abstract class ConfigScreen extends AbstractSimiScreen {
|
||||||
public static final Map<String, TriConsumer<Screen, MatrixStack, Float>> backgrounds = new HashMap<>();
|
public static final Map<String, TriConsumer<Screen, MatrixStack, Float>> backgrounds = new HashMap<>();
|
||||||
public static final PhysicalFloat cogSpin = PhysicalFloat.create().withLimit(10f).withDrag(0.3).addForce(new Force.Static(.2f));
|
public static final PhysicalFloat cogSpin = PhysicalFloat.create().withLimit(10f).withDrag(0.3).addForce(new Force.Static(.2f));
|
||||||
public static final BlockState cogwheelState = AllBlocks.LARGE_COGWHEEL.getDefaultState().setValue(CogWheelBlock.AXIS, Direction.Axis.Y);
|
public static final BlockState cogwheelState = AllBlocks.LARGE_COGWHEEL.getDefaultState().setValue(CogWheelBlock.AXIS, Direction.Axis.Y);
|
||||||
public static final Map<String, Object> changes = new HashMap<>();
|
|
||||||
public static String modID = null;
|
public static String modID = null;
|
||||||
protected final Screen parent;
|
protected final Screen parent;
|
||||||
|
|
||||||
|
@ -147,7 +144,7 @@ public abstract class ConfigScreen extends AbstractSimiScreen {
|
||||||
public static String toHumanReadable(String key) {
|
public static String toHumanReadable(String key) {
|
||||||
String s = key.replaceAll("_", " ");
|
String s = key.replaceAll("_", " ");
|
||||||
s = Arrays.stream(StringUtils.splitByCharacterTypeCamelCase(s)).map(StringUtils::capitalize).collect(Collectors.joining(" "));
|
s = Arrays.stream(StringUtils.splitByCharacterTypeCamelCase(s)).map(StringUtils::capitalize).collect(Collectors.joining(" "));
|
||||||
s = s.replaceAll("\\s\\s+", " ");
|
s = StringUtils.normalizeSpace(s);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
package com.simibubi.create.foundation.config.ui;
|
package com.simibubi.create.foundation.config.ui;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.lwjgl.opengl.GL11;
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
|
@ -12,6 +16,7 @@ import com.simibubi.create.foundation.gui.TextStencilElement;
|
||||||
import com.simibubi.create.foundation.gui.Theme;
|
import com.simibubi.create.foundation.gui.Theme;
|
||||||
import com.simibubi.create.foundation.gui.UIRenderHelper;
|
import com.simibubi.create.foundation.gui.UIRenderHelper;
|
||||||
import com.simibubi.create.foundation.utility.Color;
|
import com.simibubi.create.foundation.utility.Color;
|
||||||
|
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
|
||||||
|
|
||||||
import net.minecraft.client.MainWindow;
|
import net.minecraft.client.MainWindow;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
@ -28,8 +33,6 @@ public class ConfigScreenList extends ExtendedList<ConfigScreenList.Entry> {
|
||||||
|
|
||||||
public static TextFieldWidget currentText;
|
public static TextFieldWidget currentText;
|
||||||
|
|
||||||
public boolean isForServer = false;
|
|
||||||
|
|
||||||
public ConfigScreenList(Minecraft client, int width, int height, int top, int bottom, int elementHeight) {
|
public ConfigScreenList(Minecraft client, int width, int height, int top, int bottom, int elementHeight) {
|
||||||
super(client, width, height, top, bottom, elementHeight);
|
super(client, width, height, top, bottom, elementHeight);
|
||||||
setRenderBackground(false);
|
setRenderBackground(false);
|
||||||
|
@ -77,13 +80,41 @@ public class ConfigScreenList extends ExtendedList<ConfigScreenList.Entry> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tick() {
|
public void tick() {
|
||||||
for(int i = 0; i < getItemCount(); ++i) {
|
/*for(int i = 0; i < getItemCount(); ++i) {
|
||||||
int top = this.getRowTop(i);
|
int top = this.getRowTop(i);
|
||||||
int bot = top + itemHeight;
|
int bot = top + itemHeight;
|
||||||
if (bot >= this.y0 && top <= this.y1)
|
if (bot >= this.y0 && top <= this.y1)
|
||||||
this.getEntry(i).tick();
|
this.getEntry(i).tick();
|
||||||
|
}*/
|
||||||
|
children().forEach(Entry::tick);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean search(String query) {
|
||||||
|
if (query == null || query.isEmpty()) {
|
||||||
|
setScrollAmount(0);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String q = query.toLowerCase(Locale.ROOT);
|
||||||
|
Optional<Entry> first = children().stream().filter(entry -> {
|
||||||
|
if (entry.path == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
String[] split = entry.path.split("\\.");
|
||||||
|
String key = split[split.length - 1].toLowerCase(Locale.ROOT);
|
||||||
|
return key.contains(q);
|
||||||
|
}).findFirst();
|
||||||
|
|
||||||
|
if (!first.isPresent()) {
|
||||||
|
setScrollAmount(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry e = first.get();
|
||||||
|
e.annotations.put("highlight", "(:");
|
||||||
|
centerScrollOn(e);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bumpCog(float force) {
|
public void bumpCog(float force) {
|
||||||
|
@ -92,9 +123,12 @@ public class ConfigScreenList extends ExtendedList<ConfigScreenList.Entry> {
|
||||||
|
|
||||||
public static abstract class Entry extends ExtendedList.AbstractListEntry<Entry> {
|
public static abstract class Entry extends ExtendedList.AbstractListEntry<Entry> {
|
||||||
protected List<IGuiEventListener> listeners;
|
protected List<IGuiEventListener> listeners;
|
||||||
|
protected Map<String, String> annotations;
|
||||||
|
protected String path;
|
||||||
|
|
||||||
protected Entry() {
|
protected Entry() {
|
||||||
listeners = new ArrayList<>();
|
listeners = new ArrayList<>();
|
||||||
|
annotations = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -119,6 +153,13 @@ public class ConfigScreenList extends ExtendedList<ConfigScreenList.Entry> {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setEditable(boolean b) {}
|
protected void setEditable(boolean b) {}
|
||||||
|
|
||||||
|
protected boolean isCurrentValueChanged() {
|
||||||
|
if (path == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ConfigHelper.changes.containsKey(path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class LabeledEntry extends Entry {
|
public static class LabeledEntry extends Entry {
|
||||||
|
@ -128,6 +169,8 @@ public class ConfigScreenList extends ExtendedList<ConfigScreenList.Entry> {
|
||||||
protected TextStencilElement label;
|
protected TextStencilElement label;
|
||||||
protected List<ITextComponent> labelTooltip;
|
protected List<ITextComponent> labelTooltip;
|
||||||
protected String unit = null;
|
protected String unit = null;
|
||||||
|
protected LerpedFloat differenceAnimation = LerpedFloat.linear().startWithValue(0);
|
||||||
|
protected LerpedFloat highlightAnimation = LerpedFloat.linear().startWithValue(0);
|
||||||
|
|
||||||
public LabeledEntry(String label) {
|
public LabeledEntry(String label) {
|
||||||
this.label = new TextStencilElement(Minecraft.getInstance().font, label);
|
this.label = new TextStencilElement(Minecraft.getInstance().font, label);
|
||||||
|
@ -135,8 +178,41 @@ public class ConfigScreenList extends ExtendedList<ConfigScreenList.Entry> {
|
||||||
labelTooltip = new ArrayList<>();
|
labelTooltip = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LabeledEntry(String label, String path) {
|
||||||
|
this(label);
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
differenceAnimation.tickChaser();
|
||||||
|
highlightAnimation.tickChaser();
|
||||||
|
super.tick();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(MatrixStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean p_230432_9_, float partialTicks) {
|
public void render(MatrixStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean p_230432_9_, float partialTicks) {
|
||||||
|
if (isCurrentValueChanged()) {
|
||||||
|
if (differenceAnimation.getChaseTarget() != 1)
|
||||||
|
differenceAnimation.chase(1, .5f, LerpedFloat.Chaser.EXP);
|
||||||
|
} else {
|
||||||
|
if (differenceAnimation.getChaseTarget() != 0)
|
||||||
|
differenceAnimation.chase(0, .6f, LerpedFloat.Chaser.EXP);
|
||||||
|
}
|
||||||
|
|
||||||
|
float animation = differenceAnimation.getValue(partialTicks);
|
||||||
|
if (animation > .1f) {
|
||||||
|
int offset = (int) (30 * (1 - animation));
|
||||||
|
|
||||||
|
if (annotations.containsKey(ConfigAnnotations.RequiresRestart.CLIENT.getName())) {
|
||||||
|
UIRenderHelper.streak(ms, 180, x + width + 10 + offset, y + height / 2, height - 6, 110, new Color(0x50_601010));
|
||||||
|
} else if (annotations.containsKey(ConfigAnnotations.RequiresRelog.TRUE.getName())) {
|
||||||
|
UIRenderHelper.streak(ms, 180, x + width + 10 + offset, y + height / 2, height - 6, 110, new Color(0x40_eefb17));
|
||||||
|
}
|
||||||
|
|
||||||
|
UIRenderHelper.breadcrumbArrow(ms, x - 10 - offset, y + 6, 0, -20, 24, -18, new Color(0x70_ffffff), Color.TRANSPARENT_BLACK);
|
||||||
|
}
|
||||||
|
|
||||||
UIRenderHelper.streak(ms, 0, x - 10, y + height / 2, height - 6, width / 8 * 7, 0xdd_000000);
|
UIRenderHelper.streak(ms, 0, x - 10, y + height / 2, height - 6, width / 8 * 7, 0xdd_000000);
|
||||||
UIRenderHelper.streak(ms, 180, x + (int) (width * 1.35f) + 10, y + height / 2, height - 6, width / 8 * 7, 0xdd_000000);
|
UIRenderHelper.streak(ms, 180, x + (int) (width * 1.35f) + 10, y + height / 2, height - 6, width / 8 * 7, 0xdd_000000);
|
||||||
IFormattableTextComponent component = label.getComponent();
|
IFormattableTextComponent component = label.getComponent();
|
||||||
|
@ -152,6 +228,20 @@ public class ConfigScreenList extends ExtendedList<ConfigScreenList.Entry> {
|
||||||
label.at(x + 10, y + height / 2 - 4, 0).render(ms);
|
label.at(x + 10, y + height / 2 - 4, 0).render(ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (annotations.containsKey("highlight")) {
|
||||||
|
highlightAnimation.startWithValue(1).chase(0, 0.1f, LerpedFloat.Chaser.LINEAR);
|
||||||
|
annotations.remove("highlight");
|
||||||
|
}
|
||||||
|
|
||||||
|
animation = highlightAnimation.getValue(partialTicks);
|
||||||
|
if (animation > .01f) {
|
||||||
|
Color highlight = new Color(0xa0_ffffff).scaleAlpha(animation);
|
||||||
|
UIRenderHelper.streak(ms, 0, x - 10, y + height / 2, height - 6, 5, highlight);
|
||||||
|
UIRenderHelper.streak(ms, 180, x + width, y + height / 2, height - 6, 5, highlight);
|
||||||
|
UIRenderHelper.streak(ms, 90, x + width / 2 - 5, y + 3, width + 10, 5, highlight);
|
||||||
|
UIRenderHelper.streak(ms, -90, x + width / 2 - 5, y + height - 3, width + 10, 5, highlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (mouseX > x && mouseX < x + getLabelWidth(width) && mouseY > y + 5 && mouseY < y + height - 5) {
|
if (mouseX > x && mouseX < x + getLabelWidth(width) && mouseY > y + 5 && mouseY < y + height - 5) {
|
||||||
List<ITextComponent> tooltip = getLabelTooltip();
|
List<ITextComponent> tooltip = getLabelTooltip();
|
||||||
|
|
|
@ -1,20 +1,11 @@
|
||||||
package com.simibubi.create.foundation.config.ui;
|
package com.simibubi.create.foundation.config.ui;
|
||||||
|
|
||||||
import org.lwjgl.glfw.GLFW;
|
|
||||||
|
|
||||||
import net.minecraft.client.gui.FontRenderer;
|
import net.minecraft.client.gui.FontRenderer;
|
||||||
import net.minecraft.client.gui.widget.TextFieldWidget;
|
|
||||||
import net.minecraft.util.text.StringTextComponent;
|
|
||||||
|
|
||||||
public class ConfigTextField extends TextFieldWidget {
|
public class ConfigTextField extends HintableTextFieldWidget {
|
||||||
|
|
||||||
protected FontRenderer font;
|
public ConfigTextField(FontRenderer font, int x, int y, int width, int height) {
|
||||||
protected String unit;
|
super(font, x, y, width, height);
|
||||||
|
|
||||||
public ConfigTextField(FontRenderer font, int x, int y, int width, int height, String unit) {
|
|
||||||
super(font, x, y, width, height, StringTextComponent.EMPTY);
|
|
||||||
this.font = font;
|
|
||||||
this.unit = unit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -33,29 +24,4 @@ public class ConfigTextField extends TextFieldWidget {
|
||||||
|
|
||||||
ConfigScreenList.currentText = this;
|
ConfigScreenList.currentText = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean keyPressed(int p_231046_1_, int p_231046_2_, int p_231046_3_) {
|
|
||||||
//prevent input of hex-keys from exiting the current config screen, in case they match the inventory key
|
|
||||||
boolean ret = false;
|
|
||||||
|
|
||||||
switch (p_231046_1_) {
|
|
||||||
case GLFW.GLFW_KEY_A:
|
|
||||||
case GLFW.GLFW_KEY_B:
|
|
||||||
case GLFW.GLFW_KEY_C:
|
|
||||||
case GLFW.GLFW_KEY_D:
|
|
||||||
case GLFW.GLFW_KEY_E:
|
|
||||||
case GLFW.GLFW_KEY_F:
|
|
||||||
ret = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
|
|
||||||
return super.keyPressed(p_231046_1_, p_231046_2_, p_231046_3_);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
package com.simibubi.create.foundation.config.ui;
|
||||||
|
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
|
import com.simibubi.create.foundation.gui.Theme;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.FontRenderer;
|
||||||
|
import net.minecraft.client.gui.widget.TextFieldWidget;
|
||||||
|
import net.minecraft.client.util.InputMappings;
|
||||||
|
import net.minecraft.util.text.StringTextComponent;
|
||||||
|
|
||||||
|
public class HintableTextFieldWidget extends TextFieldWidget {
|
||||||
|
|
||||||
|
protected FontRenderer font;
|
||||||
|
protected String hint;
|
||||||
|
|
||||||
|
public HintableTextFieldWidget(FontRenderer font, int x, int y, int width, int height) {
|
||||||
|
super(font, x, y, width, height, StringTextComponent.EMPTY);
|
||||||
|
this.font = font;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHint(String hint) {
|
||||||
|
this.hint = hint;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderButton(MatrixStack ms, int mouseX, int mouseY, float partialTicks) {
|
||||||
|
super.renderButton(ms, mouseX, mouseY, partialTicks);
|
||||||
|
|
||||||
|
if (hint == null || hint.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!getValue().isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
font.draw(ms, hint, x + 5, this.y + (this.height - 8) / 2, Theme.c(Theme.Key.TEXT).scaleAlpha(.75f).getRGB());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClicked(double x, double y, int button) {
|
||||||
|
if (!isMouseOver(x, y))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (button == GLFW.GLFW_MOUSE_BUTTON_RIGHT) {
|
||||||
|
setValue("");
|
||||||
|
return true;
|
||||||
|
} else
|
||||||
|
return super.mouseClicked(x, y, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyPressed(int code, int p_keyPressed_2_, int p_keyPressed_3_) {
|
||||||
|
InputMappings.Input mouseKey = InputMappings.getKey(code, p_keyPressed_2_);
|
||||||
|
if (Minecraft.getInstance().options.keyInventory.isActiveAndMatches(mouseKey)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.keyPressed(code, p_keyPressed_2_, p_keyPressed_3_);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,14 @@
|
||||||
package com.simibubi.create.foundation.config.ui;
|
package com.simibubi.create.foundation.config.ui;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
@ -33,6 +38,7 @@ import com.simibubi.create.foundation.item.TooltipHelper;
|
||||||
import com.simibubi.create.foundation.networking.AllPackets;
|
import com.simibubi.create.foundation.networking.AllPackets;
|
||||||
import com.simibubi.create.foundation.utility.Color;
|
import com.simibubi.create.foundation.utility.Color;
|
||||||
import com.simibubi.create.foundation.utility.Couple;
|
import com.simibubi.create.foundation.utility.Couple;
|
||||||
|
import com.simibubi.create.foundation.utility.Pair;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.IGuiEventListener;
|
import net.minecraft.client.gui.IGuiEventListener;
|
||||||
|
@ -55,13 +61,15 @@ public class SubMenuConfigScreen extends ConfigScreen {
|
||||||
protected BoxWidget discardChanges;
|
protected BoxWidget discardChanges;
|
||||||
protected BoxWidget goBack;
|
protected BoxWidget goBack;
|
||||||
protected BoxWidget serverLocked;
|
protected BoxWidget serverLocked;
|
||||||
|
protected HintableTextFieldWidget search;
|
||||||
protected int listWidth;
|
protected int listWidth;
|
||||||
protected String title;
|
protected String title;
|
||||||
|
protected Set<String> highlights = new HashSet<>();
|
||||||
|
|
||||||
public static SubMenuConfigScreen find(ConfigHelper.ConfigPath path) {
|
public static SubMenuConfigScreen find(ConfigHelper.ConfigPath path) {
|
||||||
ForgeConfigSpec spec = ConfigHelper.findConfigSpecFor(path.getType(), path.getModID());
|
ForgeConfigSpec spec = ConfigHelper.findConfigSpecFor(path.getType(), path.getModID());
|
||||||
UnmodifiableConfig values = spec.getValues();
|
UnmodifiableConfig values = spec.getValues();
|
||||||
BaseConfigScreen base = new BaseConfigScreen(null, path.getModID()).searchForSpecsInModContainer();
|
BaseConfigScreen base = new BaseConfigScreen(null, path.getModID());
|
||||||
SubMenuConfigScreen screen = new SubMenuConfigScreen(base, "root", path.getType(), spec, values);
|
SubMenuConfigScreen screen = new SubMenuConfigScreen(base, "root", path.getType(), spec, values);
|
||||||
List<String> remainingPath = Lists.newArrayList(path.getPath());
|
List<String> remainingPath = Lists.newArrayList(path.getPath());
|
||||||
|
|
||||||
|
@ -75,6 +83,7 @@ public class SubMenuConfigScreen extends ConfigScreen {
|
||||||
|
|
||||||
if (!(obj instanceof AbstractConfig)) {
|
if (!(obj instanceof AbstractConfig)) {
|
||||||
//highlight entry
|
//highlight entry
|
||||||
|
screen.highlights.add(path.getPath()[path.getPath().length - 1]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +116,7 @@ public class SubMenuConfigScreen extends ConfigScreen {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void clearChanges() {
|
protected void clearChanges() {
|
||||||
changes.clear();
|
ConfigHelper.changes.clear();
|
||||||
list.children()
|
list.children()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(e -> e instanceof ValueEntry)
|
.filter(e -> e instanceof ValueEntry)
|
||||||
|
@ -116,11 +125,18 @@ public class SubMenuConfigScreen extends ConfigScreen {
|
||||||
|
|
||||||
protected void saveChanges() {
|
protected void saveChanges() {
|
||||||
UnmodifiableConfig values = spec.getValues();
|
UnmodifiableConfig values = spec.getValues();
|
||||||
changes.forEach((path, value) -> {
|
ConfigHelper.changes.forEach((path, change) -> {
|
||||||
ForgeConfigSpec.ConfigValue configValue = values.get(path);
|
ForgeConfigSpec.ConfigValue configValue = values.get(path);
|
||||||
configValue.set(value);
|
configValue.set(change.value);
|
||||||
|
|
||||||
if (type == ModConfig.Type.SERVER) {
|
if (type == ModConfig.Type.SERVER) {
|
||||||
AllPackets.channel.sendToServer(new CConfigureConfigPacket<>(ConfigScreen.modID, path, value));
|
AllPackets.channel.sendToServer(new CConfigureConfigPacket<>(ConfigScreen.modID, path, change.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
String command = change.annotations.get("Execute");
|
||||||
|
if (Minecraft.getInstance().player != null && command != null && command.startsWith("/")) {
|
||||||
|
Minecraft.getInstance().player.chat(command);
|
||||||
|
//AllPackets.channel.sendToServer(new CChatMessagePacket(command));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
clearChanges();
|
clearChanges();
|
||||||
|
@ -133,8 +149,10 @@ public class SubMenuConfigScreen extends ConfigScreen {
|
||||||
} else if (obj instanceof ForgeConfigSpec.ConfigValue<?>) {
|
} else if (obj instanceof ForgeConfigSpec.ConfigValue<?>) {
|
||||||
ForgeConfigSpec.ConfigValue configValue = (ForgeConfigSpec.ConfigValue<?>) obj;
|
ForgeConfigSpec.ConfigValue configValue = (ForgeConfigSpec.ConfigValue<?>) obj;
|
||||||
ForgeConfigSpec.ValueSpec valueSpec = spec.getRaw((List<String>) configValue.getPath());
|
ForgeConfigSpec.ValueSpec valueSpec = spec.getRaw((List<String>) configValue.getPath());
|
||||||
|
List<String> comments = new ArrayList<>(Arrays.asList(valueSpec.getComment().split("\n")));
|
||||||
|
Pair<String, Map<String, String>> metadata = ConfigHelper.readMetadataFromComment(comments);
|
||||||
|
|
||||||
ConfigHelper.setValue(String.join(".", configValue.getPath()), configValue, valueSpec.getDefault());
|
ConfigHelper.setValue(String.join(".", configValue.getPath()), configValue, valueSpec.getDefault(), metadata.getSecond());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -181,17 +199,18 @@ public class SubMenuConfigScreen extends ConfigScreen {
|
||||||
saveChanges = new BoxWidget(listL - 30, yCenter - 25, 20, 20)
|
saveChanges = new BoxWidget(listL - 30, yCenter - 25, 20, 20)
|
||||||
.withPadding(2, 2)
|
.withPadding(2, 2)
|
||||||
.withCallback((x, y) -> {
|
.withCallback((x, y) -> {
|
||||||
if (changes.isEmpty())
|
if (ConfigHelper.changes.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
new ConfirmationScreen()
|
ConfirmationScreen confirm = new ConfirmationScreen()
|
||||||
.centered()
|
.centered()
|
||||||
.withText(ITextProperties.of("Saving " + changes.size() + " changed value" + (changes.size() != 1 ? "s" : "") + ""))
|
.withText(ITextProperties.of("Saving " + ConfigHelper.changes.size() + " changed value" + (ConfigHelper.changes.size() != 1 ? "s" : "") + ""))
|
||||||
.withAction(success -> {
|
.withAction(success -> {
|
||||||
if (success)
|
if (success)
|
||||||
saveChanges();
|
saveChanges();
|
||||||
})
|
});
|
||||||
.open(this);
|
|
||||||
|
addAnnotationsToConfirm(confirm).open(this);
|
||||||
});
|
});
|
||||||
saveChanges.showingElement(AllIcons.I_CONFIG_SAVE.asStencil().withElementRenderer(BoxWidget.gradientFactory.apply(saveChanges)));
|
saveChanges.showingElement(AllIcons.I_CONFIG_SAVE.asStencil().withElementRenderer(BoxWidget.gradientFactory.apply(saveChanges)));
|
||||||
saveChanges.getToolTip().add(new StringTextComponent("Save Changes"));
|
saveChanges.getToolTip().add(new StringTextComponent("Save Changes"));
|
||||||
|
@ -200,12 +219,12 @@ public class SubMenuConfigScreen extends ConfigScreen {
|
||||||
discardChanges = new BoxWidget(listL - 30, yCenter + 5, 20, 20)
|
discardChanges = new BoxWidget(listL - 30, yCenter + 5, 20, 20)
|
||||||
.withPadding(2, 2)
|
.withPadding(2, 2)
|
||||||
.withCallback((x, y) -> {
|
.withCallback((x, y) -> {
|
||||||
if (changes.isEmpty())
|
if (ConfigHelper.changes.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
new ConfirmationScreen()
|
new ConfirmationScreen()
|
||||||
.centered()
|
.centered()
|
||||||
.withText(ITextProperties.of("Discarding " + changes.size() + " unsaved change" + (changes.size() != 1 ? "s" : "") + ""))
|
.withText(ITextProperties.of("Discarding " + ConfigHelper.changes.size() + " unsaved change" + (ConfigHelper.changes.size() != 1 ? "s" : "") + ""))
|
||||||
.withAction(success -> {
|
.withAction(success -> {
|
||||||
if (success)
|
if (success)
|
||||||
clearChanges();
|
clearChanges();
|
||||||
|
@ -227,16 +246,23 @@ public class SubMenuConfigScreen extends ConfigScreen {
|
||||||
widgets.add(discardChanges);
|
widgets.add(discardChanges);
|
||||||
widgets.add(goBack);
|
widgets.add(goBack);
|
||||||
|
|
||||||
list = new ConfigScreenList(minecraft, listWidth, height - 60, 45, height - 15, 40);
|
list = new ConfigScreenList(minecraft, listWidth, height - 80, 35, height - 45, 40);
|
||||||
list.setLeftPos(this.width / 2 - list.getWidth() / 2);
|
list.setLeftPos(this.width / 2 - list.getWidth() / 2);
|
||||||
|
|
||||||
children.add(list);
|
children.add(list);
|
||||||
|
|
||||||
|
search = new ConfigTextField(font, width / 2 - listWidth / 2, height - 35, listWidth, 20);
|
||||||
|
search.setResponder(this::updateFilter);
|
||||||
|
search.setHint("Search..");
|
||||||
|
search.moveCursorToStart();
|
||||||
|
widgets.add(search);
|
||||||
|
|
||||||
configGroup.valueMap().forEach((key, obj) -> {
|
configGroup.valueMap().forEach((key, obj) -> {
|
||||||
String humanKey = toHumanReadable(key);
|
String humanKey = toHumanReadable(key);
|
||||||
|
|
||||||
if (obj instanceof AbstractConfig) {
|
if (obj instanceof AbstractConfig) {
|
||||||
SubMenuEntry entry = new SubMenuEntry(this, humanKey, spec, (UnmodifiableConfig) obj);
|
SubMenuEntry entry = new SubMenuEntry(this, humanKey, spec, (UnmodifiableConfig) obj);
|
||||||
|
entry.path = key;
|
||||||
list.children().add(entry);
|
list.children().add(entry);
|
||||||
if (configGroup.valueMap()
|
if (configGroup.valueMap()
|
||||||
.size() == 1)
|
.size() == 1)
|
||||||
|
@ -247,23 +273,23 @@ public class SubMenuConfigScreen extends ConfigScreen {
|
||||||
ForgeConfigSpec.ConfigValue<?> configValue = (ForgeConfigSpec.ConfigValue<?>) obj;
|
ForgeConfigSpec.ConfigValue<?> configValue = (ForgeConfigSpec.ConfigValue<?>) obj;
|
||||||
ForgeConfigSpec.ValueSpec valueSpec = spec.getRaw(configValue.getPath());
|
ForgeConfigSpec.ValueSpec valueSpec = spec.getRaw(configValue.getPath());
|
||||||
Object value = configValue.get();
|
Object value = configValue.get();
|
||||||
|
ConfigScreenList.Entry entry = null;
|
||||||
|
|
||||||
if (value instanceof Boolean) {
|
if (value instanceof Boolean) {
|
||||||
BooleanEntry entry = new BooleanEntry(humanKey, (ForgeConfigSpec.ConfigValue<Boolean>) configValue, valueSpec);
|
entry = new BooleanEntry(humanKey, (ForgeConfigSpec.ConfigValue<Boolean>) configValue, valueSpec);
|
||||||
list.children().add(entry);
|
|
||||||
} else if (value instanceof Enum) {
|
} else if (value instanceof Enum) {
|
||||||
EnumEntry entry = new EnumEntry(humanKey, (ForgeConfigSpec.ConfigValue<Enum<?>>) configValue, valueSpec);
|
entry = new EnumEntry(humanKey, (ForgeConfigSpec.ConfigValue<Enum<?>>) configValue, valueSpec);
|
||||||
list.children().add(entry);
|
|
||||||
} else if (value instanceof Number) {
|
} else if (value instanceof Number) {
|
||||||
NumberEntry<? extends Number> entry = NumberEntry.create(value, humanKey, configValue, valueSpec);
|
entry = NumberEntry.create(value, humanKey, configValue, valueSpec);
|
||||||
if (entry != null) {
|
|
||||||
list.children().add(entry);
|
|
||||||
} else {
|
|
||||||
list.children().add(new ConfigScreenList.LabeledEntry("n-" + obj.getClass().getSimpleName() + " " + humanKey + " : " + value));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
list.children().add(new ConfigScreenList.LabeledEntry(humanKey + " : " + value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (entry == null)
|
||||||
|
entry = new LabeledEntry("Impl missing - " + configValue.get().getClass().getSimpleName() + " " + humanKey + " : " + value);
|
||||||
|
|
||||||
|
if (highlights.contains(key))
|
||||||
|
entry.annotations.put("highlight", ":)");
|
||||||
|
|
||||||
|
list.children().add(entry);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -281,13 +307,14 @@ public class SubMenuConfigScreen extends ConfigScreen {
|
||||||
return group;
|
return group;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
list.search(highlights.stream().findFirst().orElse(""));
|
||||||
|
|
||||||
//extras for server configs
|
//extras for server configs
|
||||||
if (type != ModConfig.Type.SERVER)
|
if (type != ModConfig.Type.SERVER)
|
||||||
return;
|
return;
|
||||||
if (minecraft.hasSingleplayerServer())
|
if (minecraft.hasSingleplayerServer())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
list.isForServer = true;
|
|
||||||
boolean canEdit = minecraft != null && minecraft.player != null && minecraft.player.hasPermissions(2);
|
boolean canEdit = minecraft != null && minecraft.player != null && minecraft.player.hasPermissions(2);
|
||||||
|
|
||||||
Couple<Color> red = Theme.p(Theme.Key.BUTTON_FAIL);
|
Couple<Color> red = Theme.p(Theme.Key.BUTTON_FAIL);
|
||||||
|
@ -355,6 +382,12 @@ public class SubMenuConfigScreen extends ConfigScreen {
|
||||||
if (super.keyPressed(code, p_keyPressed_2_, p_keyPressed_3_))
|
if (super.keyPressed(code, p_keyPressed_2_, p_keyPressed_3_))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (Screen.hasControlDown()) {
|
||||||
|
if (code == GLFW.GLFW_KEY_F) {
|
||||||
|
search.setFocus(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (code == GLFW.GLFW_KEY_BACKSPACE) {
|
if (code == GLFW.GLFW_KEY_BACKSPACE) {
|
||||||
attemptBackstep();
|
attemptBackstep();
|
||||||
}
|
}
|
||||||
|
@ -362,8 +395,16 @@ public class SubMenuConfigScreen extends ConfigScreen {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateFilter(String search) {
|
||||||
|
if (list.search(search)) {
|
||||||
|
this.search.setTextColor(Theme.i(Theme.Key.TEXT));
|
||||||
|
} else {
|
||||||
|
this.search.setTextColor(Theme.i(Theme.Key.BUTTON_FAIL));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void attemptBackstep() {
|
private void attemptBackstep() {
|
||||||
if (changes.isEmpty() || !(parent instanceof BaseConfigScreen)) {
|
if (ConfigHelper.changes.isEmpty() || !(parent instanceof BaseConfigScreen)) {
|
||||||
ScreenOpener.open(parent);
|
ScreenOpener.open(parent);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -373,7 +414,7 @@ public class SubMenuConfigScreen extends ConfigScreen {
|
||||||
return;
|
return;
|
||||||
if (success == Response.Confirm)
|
if (success == Response.Confirm)
|
||||||
saveChanges();
|
saveChanges();
|
||||||
changes.clear();
|
ConfigHelper.changes.clear();
|
||||||
ScreenOpener.open(parent);
|
ScreenOpener.open(parent);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -382,7 +423,7 @@ public class SubMenuConfigScreen extends ConfigScreen {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClose() {
|
public void onClose() {
|
||||||
if (changes.isEmpty()) {
|
if (ConfigHelper.changes.isEmpty()) {
|
||||||
super.onClose();
|
super.onClose();
|
||||||
ScreenOpener.open(parent);
|
ScreenOpener.open(parent);
|
||||||
return;
|
return;
|
||||||
|
@ -393,7 +434,7 @@ public class SubMenuConfigScreen extends ConfigScreen {
|
||||||
return;
|
return;
|
||||||
if (success == Response.Confirm)
|
if (success == Response.Confirm)
|
||||||
saveChanges();
|
saveChanges();
|
||||||
changes.clear();
|
ConfigHelper.changes.clear();
|
||||||
super.onClose();
|
super.onClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -401,11 +442,37 @@ public class SubMenuConfigScreen extends ConfigScreen {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showLeavingPrompt(Consumer<ConfirmationScreen.Response> action) {
|
public void showLeavingPrompt(Consumer<ConfirmationScreen.Response> action) {
|
||||||
new ConfirmationScreen().centered()
|
ConfirmationScreen screen = new ConfirmationScreen()
|
||||||
.addText(ITextProperties.of("Leaving with " + changes.size() + " unsaved change"
|
.centered()
|
||||||
+ (changes.size() != 1 ? "s" : "") + " for this config"))
|
|
||||||
.withThreeActions(action)
|
.withThreeActions(action)
|
||||||
.open(this);
|
.addText(ITextProperties.of("Leaving with " + ConfigHelper.changes.size() + " unsaved change"
|
||||||
|
+ (ConfigHelper.changes.size() != 1 ? "s" : "") + " for this config"));
|
||||||
|
|
||||||
|
addAnnotationsToConfirm(screen).open(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConfirmationScreen addAnnotationsToConfirm(ConfirmationScreen screen) {
|
||||||
|
AtomicBoolean relog = new AtomicBoolean(false);
|
||||||
|
AtomicBoolean restart = new AtomicBoolean(false);
|
||||||
|
ConfigHelper.changes.values().forEach(change -> {
|
||||||
|
if (change.annotations.containsKey(ConfigAnnotations.RequiresRelog.TRUE.getName()))
|
||||||
|
relog.set(true);
|
||||||
|
|
||||||
|
if (change.annotations.containsKey(ConfigAnnotations.RequiresRestart.CLIENT.getName()))
|
||||||
|
restart.set(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (relog.get()) {
|
||||||
|
screen.addText(ITextProperties.of(" "));
|
||||||
|
screen.addText(ITextProperties.of("At least one changed value will require you to relog to take full effect"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (restart.get()) {
|
||||||
|
screen.addText(ITextProperties.of(" "));
|
||||||
|
screen.addText(ITextProperties.of("At least one changed value will require you to restart your game to take full effect"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return screen;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.simibubi.create.foundation.config.ui.entries;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
|
import com.simibubi.create.foundation.config.ui.ConfigScreen;
|
||||||
import com.simibubi.create.foundation.gui.AllIcons;
|
import com.simibubi.create.foundation.gui.AllIcons;
|
||||||
import com.simibubi.create.foundation.gui.BoxElement;
|
import com.simibubi.create.foundation.gui.BoxElement;
|
||||||
import com.simibubi.create.foundation.gui.DelegatedStencilElement;
|
import com.simibubi.create.foundation.gui.DelegatedStencilElement;
|
||||||
|
@ -103,10 +104,6 @@ public class EnumEntry extends ValueEntry<Enum<?>> {
|
||||||
@Override
|
@Override
|
||||||
public void onValueChange(Enum<?> newValue) {
|
public void onValueChange(Enum<?> newValue) {
|
||||||
super.onValueChange(newValue);
|
super.onValueChange(newValue);
|
||||||
valueText.withText(newValue.name()
|
valueText.withText(ConfigScreen.toHumanReadable(newValue.name().toLowerCase(Locale.ROOT)));
|
||||||
.substring(0, 1)
|
|
||||||
+ newValue.name()
|
|
||||||
.substring(1)
|
|
||||||
.toLowerCase(Locale.ROOT));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ public abstract class NumberEntry<T extends Number> extends ValueEntry<T> {
|
||||||
|
|
||||||
public NumberEntry(String label, ForgeConfigSpec.ConfigValue<T> value, ForgeConfigSpec.ValueSpec spec) {
|
public NumberEntry(String label, ForgeConfigSpec.ConfigValue<T> value, ForgeConfigSpec.ValueSpec spec) {
|
||||||
super(label, value, spec);
|
super(label, value, spec);
|
||||||
textField = new ConfigTextField(Minecraft.getInstance().font, 0, 0, 200, 20, unit);
|
textField = new ConfigTextField(Minecraft.getInstance().font, 0, 0, 200, 20);
|
||||||
if (this instanceof IntegerEntry && annotations.containsKey("IntDisplay")) {
|
if (this instanceof IntegerEntry && annotations.containsKey("IntDisplay")) {
|
||||||
String intDisplay = annotations.get("IntDisplay");
|
String intDisplay = annotations.get("IntDisplay");
|
||||||
int intValue = (Integer) getValue();
|
int intValue = (Integer) getValue();
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
package com.simibubi.create.foundation.config.ui.entries;
|
package com.simibubi.create.foundation.config.ui.entries;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
|
||||||
|
|
||||||
import com.google.common.base.Predicates;
|
import com.google.common.base.Predicates;
|
||||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
|
import com.simibubi.create.foundation.config.ui.ConfigAnnotations;
|
||||||
import com.simibubi.create.foundation.config.ui.ConfigHelper;
|
import com.simibubi.create.foundation.config.ui.ConfigHelper;
|
||||||
import com.simibubi.create.foundation.config.ui.ConfigScreen;
|
import com.simibubi.create.foundation.config.ui.ConfigScreen;
|
||||||
import com.simibubi.create.foundation.config.ui.ConfigScreenList;
|
import com.simibubi.create.foundation.config.ui.ConfigScreenList;
|
||||||
|
@ -21,25 +18,20 @@ import com.simibubi.create.foundation.gui.AllIcons;
|
||||||
import com.simibubi.create.foundation.gui.DelegatedStencilElement;
|
import com.simibubi.create.foundation.gui.DelegatedStencilElement;
|
||||||
import com.simibubi.create.foundation.gui.widgets.BoxWidget;
|
import com.simibubi.create.foundation.gui.widgets.BoxWidget;
|
||||||
import com.simibubi.create.foundation.item.TooltipHelper;
|
import com.simibubi.create.foundation.item.TooltipHelper;
|
||||||
|
import com.simibubi.create.foundation.utility.Pair;
|
||||||
|
|
||||||
import net.minecraft.util.text.IFormattableTextComponent;
|
|
||||||
import net.minecraft.util.text.StringTextComponent;
|
import net.minecraft.util.text.StringTextComponent;
|
||||||
import net.minecraft.util.text.TextFormatting;
|
import net.minecraft.util.text.TextFormatting;
|
||||||
import net.minecraftforge.common.ForgeConfigSpec;
|
import net.minecraftforge.common.ForgeConfigSpec;
|
||||||
|
|
||||||
public class ValueEntry<T> extends ConfigScreenList.LabeledEntry {
|
public class ValueEntry<T> extends ConfigScreenList.LabeledEntry {
|
||||||
|
|
||||||
protected static final IFormattableTextComponent modComponent = new StringTextComponent("* ").withStyle(TextFormatting.BOLD, TextFormatting.DARK_BLUE).append(StringTextComponent.EMPTY.plainCopy().withStyle(TextFormatting.RESET));
|
|
||||||
protected static final int resetWidth = 28;//including 6px offset on either side
|
protected static final int resetWidth = 28;//including 6px offset on either side
|
||||||
public static final Pattern unitPattern = Pattern.compile("\\[(in .*)]");
|
|
||||||
public static final Pattern annotationPattern = Pattern.compile("\\[@cui:([^:]*)(?::(.*))?]");
|
|
||||||
|
|
||||||
protected ForgeConfigSpec.ConfigValue<T> value;
|
protected ForgeConfigSpec.ConfigValue<T> value;
|
||||||
protected ForgeConfigSpec.ValueSpec spec;
|
protected ForgeConfigSpec.ValueSpec spec;
|
||||||
protected Map<String, String> annotations;
|
|
||||||
protected BoxWidget resetButton;
|
protected BoxWidget resetButton;
|
||||||
protected boolean editable = true;
|
protected boolean editable = true;
|
||||||
protected String path;
|
|
||||||
|
|
||||||
public ValueEntry(String label, ForgeConfigSpec.ConfigValue<T> value, ForgeConfigSpec.ValueSpec spec) {
|
public ValueEntry(String label, ForgeConfigSpec.ConfigValue<T> value, ForgeConfigSpec.ValueSpec spec) {
|
||||||
super(label);
|
super(label);
|
||||||
|
@ -57,50 +49,36 @@ public class ValueEntry<T> extends ConfigScreenList.LabeledEntry {
|
||||||
|
|
||||||
listeners.add(resetButton);
|
listeners.add(resetButton);
|
||||||
|
|
||||||
annotations = new HashMap<>();
|
|
||||||
List<String> path = value.getPath();
|
List<String> path = value.getPath();
|
||||||
labelTooltip.add(new StringTextComponent(label).withStyle(TextFormatting.WHITE));
|
labelTooltip.add(new StringTextComponent(label).withStyle(TextFormatting.WHITE));
|
||||||
String comment = spec.getComment();
|
String comment = spec.getComment();
|
||||||
if (comment == null || comment.isEmpty())
|
if (comment == null || comment.isEmpty())
|
||||||
return;
|
return;
|
||||||
String[] commentLines = comment.split("\n");
|
|
||||||
//find unit in the comment
|
|
||||||
for (int i = 0; i < commentLines.length; i++) {
|
|
||||||
if (commentLines[i].isEmpty()) {
|
|
||||||
commentLines = ArrayUtils.remove(commentLines, i);
|
|
||||||
i--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matcher matcher = annotationPattern.matcher(commentLines[i]);
|
List<String> commentLines = new ArrayList<>(Arrays.asList(comment.split("\n")));
|
||||||
if (matcher.matches()) {
|
|
||||||
String annotation = matcher.group(1);
|
|
||||||
String aValue = matcher.group(2);
|
|
||||||
annotations.putIfAbsent(annotation, aValue);
|
|
||||||
|
|
||||||
commentLines = ArrayUtils.remove(commentLines, i);
|
|
||||||
i--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
matcher = unitPattern.matcher(commentLines[i]);
|
|
||||||
if (matcher.matches()) {
|
|
||||||
String u = matcher.group(1);
|
|
||||||
if (u.equals("in Revolutions per Minute"))
|
|
||||||
u = "in RPM";
|
|
||||||
if (u.equals("in Stress Units"))
|
|
||||||
u = "in SU";
|
|
||||||
unit = u;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Pair<String, Map<String, String>> metadata = ConfigHelper.readMetadataFromComment(commentLines);
|
||||||
|
if (metadata.getFirst() != null) {
|
||||||
|
unit = metadata.getFirst();
|
||||||
|
}
|
||||||
|
if (metadata.getSecond() != null && !metadata.getSecond().isEmpty()) {
|
||||||
|
annotations.putAll(metadata.getSecond());
|
||||||
}
|
}
|
||||||
// add comment to tooltip
|
// add comment to tooltip
|
||||||
labelTooltip.addAll(Arrays.stream(commentLines)
|
labelTooltip.addAll(commentLines.stream()
|
||||||
.filter(Predicates.not(s -> s.startsWith("Range")))
|
.filter(Predicates.not(s -> s.startsWith("Range")))
|
||||||
.map(StringTextComponent::new)
|
.map(StringTextComponent::new)
|
||||||
.flatMap(stc -> TooltipHelper.cutTextComponent(stc, TextFormatting.GRAY, TextFormatting.GRAY)
|
.flatMap(stc -> TooltipHelper.cutTextComponent(stc, TextFormatting.GRAY, TextFormatting.GRAY)
|
||||||
.stream())
|
.stream())
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
|
|
||||||
|
if (annotations.containsKey(ConfigAnnotations.RequiresRelog.TRUE.getName()))
|
||||||
|
labelTooltip.addAll(TooltipHelper.cutTextComponent(new StringTextComponent("Changing this value will require a _relog_ to take full effect"), TextFormatting.GRAY, TextFormatting.GOLD));
|
||||||
|
|
||||||
|
if (annotations.containsKey(ConfigAnnotations.RequiresRestart.CLIENT.getName()))
|
||||||
|
labelTooltip.addAll(TooltipHelper.cutTextComponent(new StringTextComponent("Changing this value will require a _restart_ to take full effect"), TextFormatting.GRAY, TextFormatting.RED));
|
||||||
|
|
||||||
labelTooltip.add(new StringTextComponent(ConfigScreen.modID + ":" + path.get(path.size() - 1)).withStyle(TextFormatting.DARK_GRAY));
|
labelTooltip.add(new StringTextComponent(ConfigScreen.modID + ":" + path.get(path.size() - 1)).withStyle(TextFormatting.DARK_GRAY));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,15 +97,7 @@ public class ValueEntry<T> extends ConfigScreenList.LabeledEntry {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(MatrixStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean p_230432_9_, float partialTicks) {
|
public void render(MatrixStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean p_230432_9_, float partialTicks) {
|
||||||
if (isCurrentValueChanged()) {
|
super.render(ms, index, y, x, width, height, mouseX, mouseY, p_230432_9_, partialTicks);
|
||||||
IFormattableTextComponent original = label.getComponent();
|
|
||||||
IFormattableTextComponent changed = modComponent.plainCopy().append(original);
|
|
||||||
label.withText(changed);
|
|
||||||
super.render(ms, index, y, x, width, height, mouseX, mouseY, p_230432_9_, partialTicks);
|
|
||||||
label.withText(original);
|
|
||||||
} else {
|
|
||||||
super.render(ms, index, y, x, width, height, mouseX, mouseY, p_230432_9_, partialTicks);
|
|
||||||
}
|
|
||||||
|
|
||||||
resetButton.x = x + width - resetWidth + 6;
|
resetButton.x = x + width - resetWidth + 6;
|
||||||
resetButton.y = y + 10;
|
resetButton.y = y + 10;
|
||||||
|
@ -140,7 +110,7 @@ public class ValueEntry<T> extends ConfigScreenList.LabeledEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setValue(@Nonnull T value) {
|
public void setValue(@Nonnull T value) {
|
||||||
ConfigHelper.setValue(path, this.value, value);
|
ConfigHelper.setValue(path, this.value, value, annotations);
|
||||||
onValueChange(value);
|
onValueChange(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,10 +119,6 @@ public class ValueEntry<T> extends ConfigScreenList.LabeledEntry {
|
||||||
return ConfigHelper.getValue(path, this.value);
|
return ConfigHelper.getValue(path, this.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isCurrentValueChanged() {
|
|
||||||
return ConfigScreen.changes.containsKey(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isCurrentValueDefault() {
|
protected boolean isCurrentValueDefault() {
|
||||||
return spec.getDefault().equals(getValue());
|
return spec.getDefault().equals(getValue());
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,6 +102,22 @@ public class UIRenderHelper {
|
||||||
ms.popPose();
|
ms.popPose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void streak(MatrixStack ms, float angle, int x, int y, int breadth, int length, Color c) {
|
||||||
|
Color color = c.copy().setImmutable();
|
||||||
|
int c1 = color.scaleAlpha(0.625f).getRGB();
|
||||||
|
int c2 = color.scaleAlpha(0.5f).getRGB();
|
||||||
|
int c3 = color.scaleAlpha(0.0625f).getRGB();
|
||||||
|
int c4 = color.scaleAlpha(0f).getRGB();
|
||||||
|
|
||||||
|
ms.pushPose();
|
||||||
|
ms.translate(x, y, 0);
|
||||||
|
ms.mulPose(Vector3f.ZP.rotationDegrees(angle - 90));
|
||||||
|
|
||||||
|
streak(ms, breadth / 2, length, c1, c2, c3, c4);
|
||||||
|
|
||||||
|
ms.popPose();
|
||||||
|
}
|
||||||
|
|
||||||
private static void streak(MatrixStack ms, int width, int height, int c1, int c2, int c3, int c4) {
|
private static void streak(MatrixStack ms, int width, int height, int c1, int c2, int c3, int c4) {
|
||||||
double split1 = .5;
|
double split1 = .5;
|
||||||
double split2 = .75;
|
double split2 = .75;
|
||||||
|
|
Loading…
Add table
Reference in a new issue