feat: add support for whole numbers
ci/woodpecker/push/docs Pipeline was successful Details
ci/woodpecker/push/jfmod Pipeline was successful Details

This commit is contained in:
Johannes Frohnmeyer 2023-08-22 12:50:11 +02:00
parent e34c0752b9
commit b3e8cc22cf
Signed by: Johannes
GPG Key ID: E76429612C2929F4
6 changed files with 106 additions and 33 deletions

View File

@ -80,7 +80,12 @@ Corresponds to version 4.4.0
- Stricter enforcement of legal entry names: instead of sanitization, unsupported names are logged and ignored
## v11
Corresponds to version 4.5.0
Corresponds to version 4.5.0-4.5.1
- Directory RPOs in subdirectories are respected. Previously, only the innermost directory RPO would be used
- Multiple replacements when resolving fallbacks for directory RPOs are prevented
- Multiple replacements when resolving fallbacks for directory RPOs are prevented
## v12
Corresponds to version 4.6.0
- Support for whole numbers (not integers!)

View File

@ -13,20 +13,26 @@ Every entry can contain the following properties, regardless of its type:
## Numbers
There are two ways to display numbers: input boxes and sliders.
Any number input that provides a minimum and maximum value will be displayed as a slider instead of a box.
Their type is `number` for fractions and `integer` for whole numbers.
### Example:
```json
{
id: "examplePack",
version: 9,
capabilities: ["FileFilter", "DirFilter"],
conf: {
someOption: {
default: 5,
min: 0,
max: 10
}
id: "examplePack",
version: 9,
capabilities: [
"FileFilter",
"DirFilter"
],
conf: {
someOption: {
type: "number",
default: 5,
min: 0,
max: 10
}
}
}
```
### Result:

View File

@ -28,7 +28,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.regex.Pattern;
public class Respackopts implements ModInitializer, SaveHook {
public static final Integer META_VERSION = 11;
public static final Integer META_VERSION = 12;
public static final String FILE_EXTENSION = ".rpo";
public static final Gson GSON = new GsonBuilder()
.registerTypeAdapter(ConfigEnumEntry.class, new EnumEntrySerializer())

View File

@ -56,6 +56,7 @@ public class ConfigBranchSerializer implements JsonSerializer<ConfigBranch>, Jso
}
ConfigEntry<?> entry = switch (type.toLowerCase()) {
case "slider", "number", "numeric" -> context.deserialize(j, ConfigNumericEntry.class);
case "integer", "int", "long", "whole" -> context.<ConfigNumericEntry>deserialize(j, ConfigNumericEntry.class).asInteger();
case "boolean", "toggle" -> context.deserialize(j, ConfigBooleanEntry.class);
case "enum", "select" -> context.deserialize(j, ConfigEnumEntry.class);
default -> throw new JsonSyntaxException("Unknown entry type: " + type);

View File

@ -25,13 +25,13 @@ public class NumericEntrySerializer implements JsonSerializer<ConfigNumericEntry
JsonElement max = o.get("max");
if (min != null) {
if (min.isJsonPrimitive() && min.getAsJsonPrimitive().isNumber()) {
result.min = min.getAsNumber().doubleValue();
result.setMin(min.getAsNumber().doubleValue());
}
else throw new JsonSyntaxException("Expected number as min of numeric entry");
}
if (max != null) {
if (max.isJsonPrimitive() && max.getAsJsonPrimitive().isNumber()) {
result.max = max.getAsNumber().doubleValue();
result.setMax(max.getAsNumber().doubleValue());
}
else throw new JsonSyntaxException("Expected number as max of numeric entry");
}

View File

@ -10,16 +10,44 @@ import io.gitlab.jfronny.respackopts.util.IndentingStringBuilder;
import java.util.Objects;
public class ConfigNumericEntry extends ConfigEntry<Double> implements DNumber {
public Double min = null;
public Double max = null;
private Double min = null;
private Double max = null;
private boolean integer = false;
public ConfigNumericEntry() {
super(Double.class);
setValue(0d);
}
public ConfigNumericEntry asInteger() {
this.integer = true;
if (min != null && (min % 1.0 != 0)) {
this.integer = false;
throw new RuntimeException("Minimum value (" + min + ") is not integer for integer entry");
}
if (max != null && (max % 1.0 != 0)) {
this.integer = false;
throw new RuntimeException("Minimum value (" + max + ") is not integer for integer entry");
}
return this;
}
public void setMin(Double value) {
if (value != null && integer && (value % 1.0 != 0))
throw new RuntimeException("Minimum value (" + value + ") is not integer for integer entry");
this.min = value;
}
public void setMax(Double value) {
if (value != null && integer && (value % 1.0 != 0))
throw new RuntimeException("Maximum value (" + value + ") is not integer for integer entry");
this.max = value;
}
@Override
public Double setDefault(Double value) {
if (integer && (value % 1.0 != 0))
throw new RuntimeException("Default value (" + value + ") is not integer for integer entry");
if ((min != null && value < min) || (max != null && value > max))
throw new RuntimeException("Default value (" + value + ") out of range in number entry definition (" + min + "-" + max + ")");
return super.setDefault(value);
@ -30,26 +58,25 @@ public class ConfigNumericEntry extends ConfigEntry<Double> implements DNumber {
super.sync(source, mode);
ConfigNumericEntry n = (ConfigNumericEntry) source;
if (mode == ConfigSyncMode.RESPACK_LOAD) {
if (n.min != null)
min = n.min;
if (n.max != null)
max = n.max;
min = n.min;
max = n.max;
integer = n.integer;
}
}
@Override
public void appendString(IndentingStringBuilder sb) {
sb.line(getValue() + " (" + getDefault() + ", " + min + "-" + max + ")");
sb.line(getValue() + " (" + getDefault() + ", " + min + "-" + max + (integer ? ", integer" : "") + ")");
}
@Override
public ConfigEntry<Double> clone() {
ConfigNumericEntry ce = new ConfigNumericEntry();
ce.max = max;
ce.min = min;
ce.setMax(max);
ce.setMin(min);
ce.setValue(getValue());
ce.setDefault(getDefault());
return ce;
return integer ? ce.asInteger() : ce;
}
@Override
@ -62,13 +89,43 @@ public class ConfigNumericEntry extends ConfigEntry<Double> implements DNumber {
@Override
public CategoryBuilder<?> buildEntry(GuiEntryBuilderParam args) {
return args.builder().value(args.name(), getDefault(), min == null ? Double.NEGATIVE_INFINITY : min, max == null ? Double.POSITIVE_INFINITY : max, this::getValue, v -> {
if (!Objects.equals(getValue(), v)) {
if (RespackoptsConfig.debugLogs) Respackopts.LOGGER.info("ConfigNumericEntryNormal SaveCallback");
args.saveCallback();
}
setValue(v);
});
double min = this.min == null ? Double.NEGATIVE_INFINITY : this.min;
double max = this.max == null ? Double.NEGATIVE_INFINITY : this.max;
if (integer) {
return args.builder().value(
args.name(),
asLong(getDefault()),
min,
max,
() -> asLong(getValue()),
v -> {
if (!Objects.equals(asLong(getValue()), v)) {
if (RespackoptsConfig.debugLogs) Respackopts.LOGGER.info("ConfigNumericEntryNormal SaveCallback");
args.saveCallback();
}
setValue(v == null ? null : v.doubleValue());
}
);
} else {
return args.builder().value(
args.name(),
getDefault(),
min,
max,
this::getValue,
v -> {
if (!Objects.equals(getValue(), v)) {
if (RespackoptsConfig.debugLogs) Respackopts.LOGGER.info("ConfigNumericEntryNormal SaveCallback");
args.saveCallback();
}
setValue(v);
}
);
}
}
private static Long asLong(Double d) {
return d == null ? null : d.longValue();
}
@Override
@ -76,11 +133,15 @@ public class ConfigNumericEntry extends ConfigEntry<Double> implements DNumber {
if (this == o) return true;
if (!(o instanceof ConfigNumericEntry that)) return false;
if (!super.equals(o)) return false;
return Objects.equals(getValue(), that.getValue()) && Objects.equals(getDefault(), that.getDefault()) && Objects.equals(min, that.min) && Objects.equals(max, that.max);
return Objects.equals(getValue(), that.getValue())
&& Objects.equals(getDefault(), that.getDefault())
&& Objects.equals(min, that.min)
&& Objects.equals(max, that.max)
&& integer == that.integer;
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), getValue(), getDefault(), min, max);
return Objects.hash(super.hashCode(), getValue(), getDefault(), min, max, integer);
}
}