diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/ConfigBase.java b/core/src/main/java/com/seibel/distanthorizons/core/config/ConfigBase.java index 863d3adfa..eb0f54305 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/ConfigBase.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/ConfigBase.java @@ -18,6 +18,7 @@ import java.util.*; * * @author coolGi * @author Ran + * @version 2023-8-26 */ // Init the config after singletons have been blinded public class ConfigBase diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/file/ConfigFileHandling.java b/core/src/main/java/com/seibel/distanthorizons/core/config/file/ConfigFileHandling.java index 1204809cb..8fc4fa631 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/file/ConfigFileHandling.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/file/ConfigFileHandling.java @@ -18,19 +18,17 @@ import java.nio.file.Path; * Handles reading and writing config files. * * @author coolGi - * @version 2023-7-16 + * @version 2023-8-26 */ public class ConfigFileHandling { - private static final Logger LOGGER = ConfigBase.LOGGER; - public final ConfigBase configBase; public final Path configPath; private final Logger LOGGER; /** This is the object for night-config */ - private final CommentedFileConfig configFileConfig; + private final CommentedFileConfig nightConfig; public ConfigFileHandling(ConfigBase configBase) { @@ -40,50 +38,47 @@ public class ConfigFileHandling configPath = SingletonInjector.INSTANCE.get(IMinecraftSharedWrapper.class) .getInstallationDirectory().toPath().resolve("config").resolve(this.configBase.modName + ".toml"); - this.configFileConfig = CommentedFileConfig.builder(configPath.toFile()).build(); + this.nightConfig = CommentedFileConfig.builder(configPath.toFile()).build(); } /** Saves the entire config to the file */ public void saveToFile() { - CommentedFileConfig config = CommentedFileConfig.builder(configPath.toFile()).build(); + saveToFile(this.nightConfig); + } + /** Saves the entire config to the file */ + public void saveToFile(CommentedFileConfig nightConfig) + { if (!Files.exists(configPath)) // Try to check if the config exists - try - { - if (!this.configPath.getParent().toFile().exists()) - { - Files.createDirectory(this.configPath.getParent()); - } - Files.createFile(configPath); - } - catch (IOException ex) - { - ex.printStackTrace(); - } + { + reCreateFile(configPath); + } + + + loadNightConfig(nightConfig); - loadConfig(config); for (AbstractConfigType entry : this.configBase.entries) { if (ConfigEntry.class.isAssignableFrom(entry.getClass())) { - createComment((ConfigEntry) entry, config); - saveEntry((ConfigEntry) entry, config); + createComment((ConfigEntry) entry, nightConfig); + saveEntry((ConfigEntry) entry, nightConfig); } } try { - config.save(); + nightConfig.save(); } catch (Exception e) { // If it fails to save, crash game SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class).crashMinecraft("Failed to save config at [" + configPath.toString() + "]", e); } - config.close(); } + /** * Loads the entire config from the file * @@ -91,46 +86,50 @@ public class ConfigFileHandling */ public void loadFromFile() { - CommentedFileConfig config = CommentedFileConfig.builder(configPath.toFile()).build(); + loadFromFile(nightConfig); + } + /** + * Loads the entire config from the file + * + * @apiNote This overwrites any value currently stored in the config + */ + public void loadFromFile(CommentedFileConfig nightConfig) + { // Attempt to load the file and if it fails then save config to file - try + if (Files.exists(configPath)) { - if (Files.exists(configPath)) - config.load(); - else - { - saveToFile(); - return; - } + loadNightConfig(nightConfig); } - catch (Exception e) + else { - e.printStackTrace(); - saveToFile(); + reCreateFile(configPath); return; } + // Load all the entries for (AbstractConfigType entry : this.configBase.entries) { - if (ConfigEntry.class.isAssignableFrom(entry.getClass())) + if ( + ConfigEntry.class.isAssignableFrom(entry.getClass()) && + entry.getAppearance().showInFile + ) { - createComment((ConfigEntry) entry, config); - loadEntry((ConfigEntry) entry, config); + createComment((ConfigEntry) entry, nightConfig); + loadEntry((ConfigEntry) entry, nightConfig); } } try { - config.save(); + nightConfig.save(); } catch (Exception e) { // If it fails to save, crash game SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class).crashMinecraft("Failed to save config at [" + configPath.toString() + "]", e); } - config.close(); } @@ -139,146 +138,148 @@ public class ConfigFileHandling // Save an entry when only given the entry public void saveEntry(ConfigEntry entry) { - CommentedFileConfig config = CommentedFileConfig.builder(configPath.toFile()).build(); - loadConfig(config); - saveEntry(entry, config); - config.save(); - config.close(); + saveEntry(entry, nightConfig); + nightConfig.save(); } - // Save an entry - @SuppressWarnings("unchecked") + /** Save an entry */ public void saveEntry(ConfigEntry entry, CommentedFileConfig workConfig) { if (!entry.getAppearance().showInFile) return; if (entry.getTrueValue() == null) throw new IllegalArgumentException("Entry [" + entry.getNameWCategory() + "] is null, this may be a problem with [" + configBase.modName + "]. Please contact the authors"); - Class originalClass = ConfigTypeConverters.isClassConvertable(entry.getType()); - if (originalClass != null) - { - workConfig.set(entry.getNameWCategory(), ConfigTypeConverters.convertToString(originalClass, entry.getTrueValue())); - return; - } - workConfig.set(entry.getNameWCategory(), entry.getTrueValue()); + workConfig.set(entry.getNameWCategory(), ConfigTypeConverters.attemptToConvertToString(entry.getType(), entry.getTrueValue())); } - // Loads an entry when only given the entry + /** Loads an entry when only given the entry */ public void loadEntry(ConfigEntry entry) { - CommentedFileConfig config = CommentedFileConfig.builder(configPath.toFile()).autosave().build(); - loadConfig(config); - loadEntry(entry, config); - config.close(); - + loadEntry(entry, nightConfig); } - // Loads an entry - @SuppressWarnings("unchecked") // Suppress due to its always safe - public void loadEntry(ConfigEntry entry, CommentedFileConfig workConfig) + /** Loads an entry */ + @SuppressWarnings("unchecked") + public void loadEntry(ConfigEntry entry, CommentedFileConfig nightConfig) { - if (!entry.getAppearance().showInFile) return; + if (!entry.getAppearance().showInFile) + return; - if (workConfig.contains(entry.getNameWCategory())) + if (!nightConfig.contains(entry.getNameWCategory())) { - try + saveEntry(entry, nightConfig); + return; + } + + + try + { + if (entry.getType().isEnum()) { - if (entry.getType().isEnum()) - { - entry.pureSet((T) (workConfig.getEnum(entry.getNameWCategory(), (Class) entry.getType()))); - return; - } - Class originalClass = ConfigTypeConverters.isClassConvertable(entry.getType()); - if (originalClass != null) - { - entry.pureSet((T) ConfigTypeConverters.convertFromString(originalClass, workConfig.get(entry.getNameWCategory()))); - return; - } - - if (entry.getType() == workConfig.get(entry.getNameWCategory()).getClass()) - { // If the types are the same - entry.pureSet((T) workConfig.get(entry.getNameWCategory())); - entry.clampWithinRange(); - return; - } - - LOGGER.warn("Entry [" + entry.getNameWCategory() + "] is invalid. Expected " + entry.getType() + " but got " + workConfig.get(entry.getNameWCategory()).getClass() + ". Using default value."); - saveEntry(entry, workConfig); + entry.pureSet((T) (nightConfig.getEnum(entry.getNameWCategory(), (Class) entry.getType()))); + return; } - catch (Exception e) - { -// e.printStackTrace(); - LOGGER.warn("Entry [" + entry.getNameWCategory() + "] had an invalid value when loading the config. Using default value."); - saveEntry(entry, workConfig); + + entry.pureSet((T) ConfigTypeConverters.attemptToConvertFromString(entry.getType(), nightConfig.get(entry.getNameWCategory()))); + + if (entry.getTrueValue() == null) { + LOGGER.warn("Entry [" + entry.getNameWCategory() + "] returned as null from the config. Using default value."); + entry.pureSet(entry.getDefaultValue()); } } - else + catch (Exception e) { - saveEntry(entry, workConfig); +// e.printStackTrace(); + LOGGER.warn("Entry [" + entry.getNameWCategory() + "] had an invalid value when loading the config. Using default value."); + entry.pureSet(entry.getDefaultValue()); } } // Creates the comment for an entry when only given the entry public void createComment(ConfigEntry entry) { - CommentedFileConfig config = CommentedFileConfig.builder(configPath.toFile()).autosave().build(); - loadConfig(config); - createComment(entry, config); - config.close(); + createComment(entry, nightConfig); } // Creates a comment for an entry - public void createComment(ConfigEntry entry, CommentedFileConfig workConfig) + public void createComment(ConfigEntry entry, CommentedFileConfig nightConfig) { - if (!entry.getAppearance().showInFile) + if ( + !entry.getAppearance().showInFile || + entry.getComment() == null + ) return; - if (entry.getComment() != null) - { - workConfig.setComment(entry.getNameWCategory(), " " + entry.getComment().replaceAll("\n", "\n ") + "\n "); - } + + nightConfig.setComment(entry.getNameWCategory(), " " + entry.getComment().replaceAll("\n", "\n ") + "\n "); } + /** - * Does config.load(); but with error checking + * Uses {@link ConfigFileHandling#nightConfig} to do {@link CommentedFileConfig#load()} but with error checking * * @apiNote This overwrites any value currently stored in the config */ - public void loadConfig(CommentedFileConfig config) + public void loadNightConfig() + { + loadNightConfig(this.nightConfig); + } + /** + * Does {@link CommentedFileConfig#load()} but with error checking + * + * @apiNote This overwrites any value currently stored in the config + */ + public void loadNightConfig(CommentedFileConfig nightConfig) { try { - config.load(); - } - catch (Exception e) - { - System.out.println("Loading file failed because of this expectation:\n" + e); try - { // Now try remaking the file and loading it - if (!this.configPath.getParent().toFile().exists()) - { - Files.createDirectory(this.configPath.getParent()); - } - - boolean fileDeleted = Files.deleteIfExists(this.configPath); - System.out.println("File at [" + this.configPath + "] was " + (fileDeleted ? "" : "not ") + "able to be deleted."); - - - Files.createFile(this.configPath); - - config.load(); - } - catch (IOException ex) { - System.out.println("Creating file failed"); - ex.printStackTrace(); - SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class).crashMinecraft("Loading file and resetting config file failed at path [" + configPath + "]. Please check the file is ok and you have the permissions", ex); + if (!Files.exists(this.configPath)) + Files.createFile(this.configPath); + nightConfig.load(); } + catch (Exception e) + { + LOGGER.warn("Loading file failed because of this expectation:\n" + e); + + reCreateFile(this.configPath); + + nightConfig.load(); + } + } + catch (Exception ex) + { + System.out.println("Creating file failed"); + LOGGER.error(ex); + SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class).crashMinecraft("Loading file and resetting config file failed at path [" + configPath + "]. Please check the file is ok and you have the permissions", ex); } } + + public static void reCreateFile(Path path) + { + try + { + Files.deleteIfExists(path); + + if (!path.getParent().toFile().exists()) + { + Files.createDirectory(path.getParent()); + } + Files.createFile(path); + } + catch (IOException ex) + { + ex.printStackTrace(); + } + } + + + + // ========== API (server) STUFF ========== // - /** ALWAYS CLEAR WHEN NOT ON SERVER!!!! */ + /* * ALWAYS CLEAR WHEN NOT ON SERVER!!!! */ // We are not using this stuff, so comment it out for now (if we ever do need it then we can uncomment it) /* @SuppressWarnings("unchecked") diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/file/ConfigTypeConverters.java b/core/src/main/java/com/seibel/distanthorizons/core/config/file/ConfigTypeConverters.java index 32b6e5d1e..e35359770 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/file/ConfigTypeConverters.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/file/ConfigTypeConverters.java @@ -37,6 +37,32 @@ public class ConfigTypeConverters return null; } + public static Object attemptToConvertToString(Object value) + { + return attemptToConvertToString(value.getClass(), value); + } + public static Object attemptToConvertToString(Class clazz, Object value) + { + Class convertablClass = isClassConvertable(clazz); + if (convertablClass != null) { + return convertToString(convertablClass, value); + } + return value; + } + + public static Object attemptToConvertFromString(Object value) + { + return attemptToConvertFromString(value.getClass(), value); + } + public static Object attemptToConvertFromString(Class clazz, Object value) + { + Class convertablClass = isClassConvertable(clazz); + if (convertablClass != null) { + return convertFromString(convertablClass, (String) value); + } + return value; + } + public static String convertToString(Class clazz, Object value) { try diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/types/AbstractConfigType.java b/core/src/main/java/com/seibel/distanthorizons/core/config/types/AbstractConfigType.java index 40a709245..f7aaa3b15 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/types/AbstractConfigType.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/types/AbstractConfigType.java @@ -13,6 +13,7 @@ public abstract class AbstractConfigType { public String category = ""; // This should only be set once in the init public String name; // This should only be set once in the init + protected final T defaultValue; protected T value; public ConfigBase configBase; @@ -22,8 +23,9 @@ public abstract class AbstractConfigType protected AbstractConfigType(EConfigEntryAppearance appearance, T value) { - this.appearance = appearance; + this.defaultValue = value; this.value = value; + this.appearance = appearance; } @@ -65,7 +67,7 @@ public abstract class AbstractConfigType // Gets the class of T public Class getType() { - return value.getClass(); + return this.defaultValue.getClass(); } protected static abstract class Builder diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/types/ConfigEntry.java b/core/src/main/java/com/seibel/distanthorizons/core/config/types/ConfigEntry.java index cf3a820d1..2fbd85471 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/types/ConfigEntry.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/types/ConfigEntry.java @@ -19,7 +19,6 @@ import java.util.Arrays; */ public class ConfigEntry extends AbstractConfigType> implements IConfigEntry { - private final T defaultValue; private String comment; private T min; private T max; @@ -41,7 +40,6 @@ public class ConfigEntry extends AbstractConfigType> implem { super(appearance, value); - this.defaultValue = value; this.comment = comment; this.min = min; this.max = max; @@ -54,7 +52,7 @@ public class ConfigEntry extends AbstractConfigType> implem /** Gets the default value of the option */ @Override - public T getDefaultValue() { return this.defaultValue; } + public T getDefaultValue() { return super.defaultValue; } @Override public void setApiValue(T newApiValue) @@ -70,7 +68,7 @@ public class ConfigEntry extends AbstractConfigType> implem /** * DONT USE THIS IN YOUR CODE
* Sets the value without informing the rest of the code (ie, doesnt call listeners, or saves the value).
- * Should only be used when loading the config from the file + * Should only be used when loading the config from the file (in places like the {@link com.seibel.distanthorizons.core.config.file.ConfigFileHandling} or {@link com.seibel.distanthorizons.core.config.ConfigBase}) */ public void pureSet(T newValue) { super.set(newValue);