nested namespaces

This commit is contained in:
2025-04-03 02:07:04 +02:00
parent 8557c10354
commit dc70abf450
6 changed files with 244 additions and 183 deletions
@@ -20,20 +20,28 @@ public class ConfigManager {
"saturn.json");
private static Map<String, Map<String, Property<?>>> properties = new HashMap<>();
private String namespace;
private Map<String, Property<?>> currentMap;
public ConfigManager(String namespace) {
this.namespace = namespace;
properties.put(namespace, new LinkedHashMap<>());
currentMap = new LinkedHashMap<>();
properties.put(namespace, currentMap);
}
public ConfigManager(ConfigManager config, String namespace) {
currentMap = new LinkedHashMap<>();
Property<Map<String, Property<?>>> namespaceProperty = new Property<>(currentMap,
Property.PropertyType.NAMESPACE);
config.property(namespace, namespaceProperty);
// Update the parent's state
config.currentMap.put(namespace, namespaceProperty);
}
// Generic method to store any type of property
public <T> Property<T> property(String name, Property<T> value) {
properties.get(namespace).put(name, value);
currentMap.put(name, value);
return value;
}
@SuppressWarnings("unchecked")
public static void load() {
try {
SaturnClient.LOGGER.info("Starting to load config...");
@@ -57,48 +65,59 @@ public class ConfigManager {
continue;
}
Map<String, Property<?>> propertyMap = properties.get(
namespace);
for (String propertyName : propertyMap.keySet()) {
JsonElement c = config.get(propertyName);
if (c == null) {
continue;
}
Property<?> p = propertyMap.get(propertyName);
if (p.matchesJson(c)) {
switch (p.getType()) {
case BOOLEAN:
((Property<Boolean>) p).value = c.getAsBoolean();
break;
case INTEGER:
((Property<Integer>) p).value = c.getAsInt();
break;
case FLOAT:
((Property<Float>) p).value = c.getAsFloat();
break;
case STRING:
((Property<String>) p).value = c.getAsString();
break;
case HEX:
((Property<Integer>) p).value = c.getAsInt();
break;
default:
break;
}
} else {
SaturnClient.LOGGER.warn(
"Property does not match JSON: " + propertyName);
}
}
Map<String, Property<?>> propertyMap = properties.get(namespace);
loadProperties(config, propertyMap);
}
} catch (IOException e) {
SaturnClient.LOGGER.error("Error reading the config file", e);
}
}
@SuppressWarnings("unchecked")
private static void loadProperties(JsonObject config, Map<String, Property<?>> propertyMap) {
for (String propertyName : propertyMap.keySet()) {
JsonElement c = config.get(propertyName);
if (c == null) {
continue;
}
Property<?> p = propertyMap.get(propertyName);
if (p.matchesJson(c)) {
if (p.getType() == Property.PropertyType.NAMESPACE) {
// Handle nested namespace
JsonObject nestedConfig = c.getAsJsonObject();
Map<String, Property<?>> nestedProperties = (Map<String, Property<?>>) p.value;
loadProperties(nestedConfig, nestedProperties);
} else {
// Handle regular properties
switch (p.getType()) {
case BOOLEAN:
((Property<Boolean>) p).value = c.getAsBoolean();
break;
case INTEGER:
((Property<Integer>) p).value = c.getAsInt();
break;
case FLOAT:
((Property<Float>) p).value = c.getAsFloat();
break;
case STRING:
((Property<String>) p).value = c.getAsString();
break;
case HEX:
((Property<Integer>) p).value = c.getAsInt();
break;
default:
break;
}
}
} else {
SaturnClient.LOGGER.warn(
"Property does not match JSON: " + propertyName);
}
}
}
public static void save() {
try {
SaturnClient.LOGGER.info("Starting to save config...");
@@ -108,46 +127,10 @@ public class ConfigManager {
// Iterate through all namespaces and their properties
for (String namespace : properties.keySet()) {
JsonObject namespaceConfig = new JsonObject();
Map<String, Property<?>> propertyMap = properties.get(
namespace);
Map<String, Property<?>> propertyMap = properties.get(namespace);
// Iterate through each property in the namespace
for (String propertyName : propertyMap.keySet()) {
Property<?> property = propertyMap.get(propertyName);
JsonElement propertyValue = null;
// Convert the property value based on its type
switch (property.getType()) {
case BOOLEAN:
propertyValue = new JsonPrimitive(
(Boolean) property.value);
break;
case INTEGER:
propertyValue = new JsonPrimitive(
(Integer) property.value);
break;
case FLOAT:
propertyValue = new JsonPrimitive(
(Float) property.value);
break;
case STRING:
propertyValue = new JsonPrimitive(
(String) property.value);
break;
case HEX:
propertyValue = new JsonPrimitive(
(Integer) property.value);
break;
default:
SaturnClient.LOGGER.warn(
"Unknown property type for: " + propertyName);
break;
}
if (propertyValue != null) {
namespaceConfig.add(propertyName, propertyValue);
}
}
// Save properties for this namespace
saveProperties(namespaceConfig, propertyMap);
// Add the namespace config to the main JSON object
jsonObject.add(namespace, namespaceConfig);
@@ -161,7 +144,51 @@ public class ConfigManager {
}
}
@SuppressWarnings("unchecked")
private static void saveProperties(JsonObject config, Map<String, Property<?>> propertyMap) {
// Iterate through each property in the namespace
for (String propertyName : propertyMap.keySet()) {
Property<?> property = propertyMap.get(propertyName);
JsonElement propertyValue = null;
if (property.getType() == Property.PropertyType.NAMESPACE) {
// Handle nested namespace
JsonObject nestedConfig = new JsonObject();
Map<String, Property<?>> nestedProperties = (Map<String, Property<?>>) property.value;
saveProperties(nestedConfig, nestedProperties);
propertyValue = nestedConfig;
} else {
// Convert the property value based on its type
switch (property.getType()) {
case BOOLEAN:
propertyValue = new JsonPrimitive((Boolean) property.value);
break;
case INTEGER:
propertyValue = new JsonPrimitive((Integer) property.value);
break;
case FLOAT:
propertyValue = new JsonPrimitive((Float) property.value);
break;
case STRING:
propertyValue = new JsonPrimitive((String) property.value);
break;
case HEX:
propertyValue = new JsonPrimitive((Integer) property.value);
break;
default:
SaturnClient.LOGGER.warn(
"Unknown property type for: " + propertyName);
break;
}
}
if (propertyValue != null) {
config.add(propertyName, propertyValue);
}
}
}
public Map<String, Property<?>> getProperties() {
return properties.get(namespace);
return currentMap;
}
}
@@ -1,5 +1,7 @@
package org.saturnclient.saturnclient.config;
import java.util.Map;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
@@ -11,6 +13,7 @@ public class Property<T> {
FLOAT,
STRING,
HEX,
NAMESPACE
}
public T value;
@@ -26,6 +29,8 @@ public class Property<T> {
type = PropertyType.FLOAT;
} else if (value instanceof String) {
type = PropertyType.STRING;
} else if (isMapOfStringToProperty(value)) {
type = PropertyType.NAMESPACE;
}
}
@@ -70,14 +75,12 @@ public class Property<T> {
return Integer.parseInt(str.substring(2), 16);
} catch (NumberFormatException e) {
throw new IllegalStateException(
"Invalid hexadecimal integer format"
);
"Invalid hexadecimal integer format");
}
}
}
throw new IllegalStateException(
"Property does not contain a valid hex integer"
);
"Property does not contain a valid hex integer");
}
public PropertyType getType() {
@@ -87,10 +90,16 @@ public class Property<T> {
public boolean matchesJson(JsonElement element) {
if (element.isJsonPrimitive()) {
JsonPrimitive primitive = element.getAsJsonPrimitive();
if (value instanceof Boolean && primitive.isBoolean()) return true;
if (value instanceof Integer && primitive.isNumber()) return true;
if (value instanceof Float && primitive.isNumber()) return true;
if (value instanceof String && primitive.isString()) return true;
if (value instanceof Boolean && primitive.isBoolean())
return true;
if (value instanceof Integer && primitive.isNumber())
return true;
if (value instanceof Float && primitive.isNumber())
return true;
if (value instanceof String && primitive.isString())
return true;
if (isMapOfStringToProperty(value) && primitive.isJsonObject())
return true;
// Check if JSON string represents a valid hex integer
if (value instanceof String && primitive.isString()) {
@@ -105,4 +114,20 @@ public class Property<T> {
public String toString() {
return String.valueOf(value);
}
public static boolean isMapOfStringToProperty(Object obj) {
if (!(obj instanceof Map<?, ?> map)) {
return false;
}
for (Map.Entry<?, ?> entry : map.entrySet()) {
if (!(entry.getKey() instanceof String)) {
return false;
}
if (!(entry.getValue() instanceof Property<?>)) {
return false;
}
}
return true;
}
}
@@ -26,7 +26,6 @@ public class ConfigEditor extends SaturnUi {
this.config = config;
}
@SuppressWarnings("unchecked")
@Override
protected void init() {
int rectWidth = 330;
@@ -57,9 +56,24 @@ public class ConfigEditor extends SaturnUi {
int row = 0;
int col = 0;
for (Map.Entry<String, Property<?>> propEntry : config
.getProperties()
.entrySet()) {
drawProperties(configScroll, config.getProperties(), rectWidth, row, col);
draw(
configScroll
.setX(rectX + 17)
.setY(rectY + 10)
.setWidth(rectWidth - 17)
.setHeight(rectHeight - 10)
.setAnimations(SaturnClient.getAnimations()));
super.init();
}
@SuppressWarnings("unchecked")
private int drawProperties(SaturnScroll configScroll, Map<String, Property<?>> properties, int rectWidth,
int row, int col) {
int totalRows = row;
for (Map.Entry<String, Property<?>> propEntry : properties.entrySet()) {
Property<?> prop = propEntry.getValue();
String propName = propEntry.getKey();
@@ -67,11 +81,11 @@ public class ConfigEditor extends SaturnUi {
if (full && col > 0) {
col = 0;
row++;
totalRows++;
}
int modX = ((rectWidth / 2) - 17) * col;
int modY = 14 * row;
int modY = 14 * totalRows;
switch (prop.getType()) {
case BOOLEAN:
@@ -151,28 +165,31 @@ public class ConfigEditor extends SaturnUi {
modY,
70));
break;
case NAMESPACE:
configScroll.draw(
new SaturnText(
propName.substring(0, 1).toUpperCase() +
propName.substring(1))
.setX(modX)
.setY(modY)
.setScale(0.8f));
// Recursively draw nested properties and update total rows
Map<String, Property<?>> nestedProperties = (Map<String, Property<?>>) prop.value;
totalRows = drawProperties(configScroll, nestedProperties, rectWidth, totalRows + 1, 0);
}
if (full) {
row++;
totalRows++;
} else {
col++;
if (col > 1) {
col = 0;
row++;
totalRows++;
}
}
}
draw(
configScroll
.setX(rectX + 17)
.setY(rectY + 10)
.setWidth(rectWidth - 17)
.setHeight(rectHeight - 10)
.setAnimations(SaturnClient.getAnimations()));
super.init();
return totalRows;
}
public static boolean isFull(Property<?> prop) {
@@ -22,7 +22,6 @@ public class SaturnConfigEditor extends SaturnUi {
super(Text.of("Config editor"));
}
@SuppressWarnings("unchecked")
@Override
protected void init() {
int rectWidth = 330;
@@ -38,48 +37,14 @@ public class SaturnConfigEditor extends SaturnUi {
.setHeight(rectHeight)
.setAnimations(SaturnClient.getAnimations()));
int tabsX = (width - 43) / 2;
int tabsY = rectY - 17;
draw(
new SaturnSprite(Textures.TABS)
.setX(tabsX)
.setY(tabsY)
.setWidth(43)
.setHeight(15)
.setAnimations(SaturnClient.getAnimations()));
int tabSize = 9;
tabsX = (width - tabSize) / 2;
draw(
new SaturnClickableImage(Textures.SETTINGS, () -> {
client.setScreen(new SaturnConfigEditor());
new SaturnClickableImage(Textures.CLOSE, () -> {
this.close();
})
.setColor(SaturnClient.COLOR.value)
.setX(tabsX)
.setY(tabsY + 3)
.setWidth(tabSize)
.setHeight(tabSize)
.setAnimations(SaturnClient.getAnimations()));
draw(
new SaturnClickableImage(Textures.MODS_TAB, () -> {
client.setScreen(new ModMenu());
})
.setX(tabsX - 12)
.setY(tabsY + 3)
.setWidth(tabSize)
.setHeight(tabSize)
.setAnimations(SaturnClient.getAnimations()));
draw(
new SaturnClickableImage(Textures.SEARCH, () -> {
System.out.println("Pressed");
})
.setX(tabsX + 12)
.setY(tabsY + 3)
.setWidth(tabSize)
.setHeight(tabSize)
.setX(rectX)
.setY(rectY - 15)
.setWidth(13)
.setHeight(13)
.setAnimations(SaturnClient.getAnimations()));
SaturnScroll configScroll = new SaturnScroll();
@@ -87,9 +52,24 @@ public class SaturnConfigEditor extends SaturnUi {
int row = 0;
int col = 0;
for (Map.Entry<String, Property<?>> propEntry : SaturnClient.config
.getProperties()
.entrySet()) {
drawProperties(configScroll, SaturnClient.config.getProperties(), rectWidth, row, col);
draw(
configScroll
.setX(rectX + 17)
.setY(rectY + 10)
.setWidth(rectWidth - 17)
.setHeight(rectHeight - 10)
.setAnimations(SaturnClient.getAnimations()));
super.init();
}
@SuppressWarnings("unchecked")
private int drawProperties(SaturnScroll configScroll, Map<String, Property<?>> properties, int rectWidth,
int row, int col) {
int totalRows = row;
for (Map.Entry<String, Property<?>> propEntry : properties.entrySet()) {
Property<?> prop = propEntry.getValue();
String propName = propEntry.getKey();
@@ -97,11 +77,11 @@ public class SaturnConfigEditor extends SaturnUi {
if (full && col > 0) {
col = 0;
row++;
totalRows++;
}
int modX = ((rectWidth / 2) - 17) * col;
int modY = 14 * row;
int modY = 14 * totalRows;
switch (prop.getType()) {
case BOOLEAN:
@@ -181,28 +161,31 @@ public class SaturnConfigEditor extends SaturnUi {
modY,
70));
break;
case NAMESPACE:
configScroll.draw(
new SaturnText(
propName.substring(0, 1).toUpperCase() +
propName.substring(1))
.setX(modX)
.setY(modY)
.setScale(0.8f));
// Recursively draw nested properties and update total rows
Map<String, Property<?>> nestedProperties = (Map<String, Property<?>>) prop.value;
totalRows = drawProperties(configScroll, nestedProperties, rectWidth, totalRows + 1, 0);
}
if (full) {
row++;
totalRows++;
} else {
col++;
if (col > 1) {
col = 0;
row++;
totalRows++;
}
}
}
draw(
configScroll
.setX(rectX + 17)
.setY(rectY + 10)
.setWidth(rectWidth - 17)
.setHeight(rectHeight - 10)
.setAnimations(SaturnClient.getAnimations()));
super.init();
return totalRows;
}
public static boolean isFull(Property<?> prop) {
@@ -11,47 +11,54 @@ public class ModDimensions {
public int width = 0;
public int height = 0;
private final ConfigManager dimensionsConfig;
public ModDimensions(ConfigManager configManager) {
configManager.property("x", this.x);
configManager.property("y", this.y);
configManager.property("scale", this.scale);
dimensionsConfig = new ConfigManager(configManager, "Dimensions");
dimensionsConfig.property("x", this.x);
dimensionsConfig.property("y", this.y);
dimensionsConfig.property("scale", this.scale);
}
public ModDimensions(ConfigManager configManager, int x, int y) {
dimensionsConfig = new ConfigManager(configManager, "Dimensions");
this.x.value = x;
this.y.value = y;
configManager.property("x", this.x);
configManager.property("y", this.y);
configManager.property("scale", this.scale);
dimensionsConfig.property("x", this.x);
dimensionsConfig.property("y", this.y);
dimensionsConfig.property("scale", this.scale);
}
public ModDimensions(ConfigManager configManager, int x, int y, int width, int height) {
dimensionsConfig = new ConfigManager(configManager, "Dimensions");
this.x.value = x;
this.y.value = y;
this.width = width;
this.height = height;
configManager.property("x", this.x);
configManager.property("y", this.y);
configManager.property("scale", this.scale);
dimensionsConfig.property("x", this.x);
dimensionsConfig.property("y", this.y);
dimensionsConfig.property("scale", this.scale);
}
public ModDimensions(ConfigManager configManager, int x, int y, float scale) {
dimensionsConfig = new ConfigManager(configManager, "Dimensions");
this.x.value = x;
this.y.value = y;
this.scale.value = scale;
configManager.property("x", this.x);
configManager.property("y", this.y);
configManager.property("scale", this.scale);
dimensionsConfig.property("x", this.x);
dimensionsConfig.property("y", this.y);
dimensionsConfig.property("scale", this.scale);
}
public ModDimensions(ConfigManager configManager, int x, int y, int width, int height, float scale) {
dimensionsConfig = new ConfigManager(configManager, "Dimensions");
this.x.value = x;
this.y.value = y;
this.scale.value = scale;
this.width = width;
this.height = height;
configManager.property("x", this.x);
configManager.property("y", this.y);
configManager.property("scale", this.scale);
dimensionsConfig.property("x", this.x);
dimensionsConfig.property("y", this.y);
dimensionsConfig.property("scale", this.scale);
}
}
@@ -14,15 +14,17 @@ public class Particles implements SaturnMod {
"Enabled",
new Property<>(false));
public static Property<Boolean> totem_enabled = config.property(
public static ConfigManager totem = new ConfigManager(config, "Totem particles");
public static Property<Boolean> totem_enabled = totem.property(
"Change totem color",
new Property<>(false));
public static Property<Integer> totem_1 = config.property(
public static Property<Integer> totem_1 = totem.property(
"Totem particle color 1",
new Property<>(SaturnClient.COLOR.value, Property.PropertyType.HEX));
public static Property<Integer> totem_2 = config.property(
public static Property<Integer> totem_2 = totem.property(
"Totem particle color 2",
new Property<>(SaturnClient.COLOR.value, Property.PropertyType.HEX));