Fixed up how file handling works in the config
This commit is contained in:
@@ -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
|
||||
|
||||
+131
-130
@@ -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 <T> void loadEntry(ConfigEntry<T> entry, CommentedFileConfig workConfig)
|
||||
/** Loads an entry */
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> void loadEntry(ConfigEntry<T> 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<? extends Enum>) 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<? extends Enum>) 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")
|
||||
|
||||
+26
@@ -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
|
||||
|
||||
+4
-2
@@ -13,6 +13,7 @@ public abstract class AbstractConfigType<T, S>
|
||||
{
|
||||
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<T, S>
|
||||
|
||||
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<T, S>
|
||||
// Gets the class of T
|
||||
public Class<?> getType()
|
||||
{
|
||||
return value.getClass();
|
||||
return this.defaultValue.getClass();
|
||||
}
|
||||
|
||||
protected static abstract class Builder<T, S>
|
||||
|
||||
@@ -19,7 +19,6 @@ import java.util.Arrays;
|
||||
*/
|
||||
public class ConfigEntry<T> extends AbstractConfigType<T, ConfigEntry<T>> implements IConfigEntry<T>
|
||||
{
|
||||
private final T defaultValue;
|
||||
private String comment;
|
||||
private T min;
|
||||
private T max;
|
||||
@@ -41,7 +40,6 @@ public class ConfigEntry<T> extends AbstractConfigType<T, ConfigEntry<T>> implem
|
||||
{
|
||||
super(appearance, value);
|
||||
|
||||
this.defaultValue = value;
|
||||
this.comment = comment;
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
@@ -54,7 +52,7 @@ public class ConfigEntry<T> extends AbstractConfigType<T, ConfigEntry<T>> 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<T> extends AbstractConfigType<T, ConfigEntry<T>> implem
|
||||
/**
|
||||
* DONT USE THIS IN YOUR CODE <br>
|
||||
* Sets the value without informing the rest of the code (ie, doesnt call listeners, or saves the value). <br>
|
||||
* 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);
|
||||
|
||||
Reference in New Issue
Block a user