401 lines
13 KiB
Java
Raw Normal View History

2012-04-26 07:32:38 -07:00
package com.gmail.nossr50.config;
2019-02-18 09:04:20 -08:00
import com.gmail.nossr50.mcMMO;
2019-02-16 16:09:48 -08:00
import com.google.common.io.Files;
2019-02-18 15:35:46 -08:00
import com.google.common.reflect.TypeToken;
2019-02-16 16:09:48 -08:00
import ninja.leaping.configurate.commented.CommentedConfigurationNode;
import ninja.leaping.configurate.loader.ConfigurationLoader;
2019-02-18 15:35:46 -08:00
import ninja.leaping.configurate.objectmapping.ObjectMappingException;
2019-02-16 16:09:48 -08:00
import ninja.leaping.configurate.yaml.YAMLConfigurationLoader;
import org.yaml.snakeyaml.DumperOptions;
2019-02-16 16:09:48 -08:00
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
2019-02-18 15:35:46 -08:00
import java.util.List;
2013-07-12 18:49:02 +02:00
2019-02-16 16:09:48 -08:00
/**
* Handles loading and cacheing configuration settings from a configurable compatible config file
*/
public abstract class Config implements VersionedConfig, Unload {
2013-07-12 18:49:02 +02:00
2019-02-16 16:09:48 -08:00
/* SETTINGS */
2019-02-18 09:04:20 -08:00
private boolean mergeNewKeys; //Whether or not to merge keys found in the default config
private boolean removeOldKeys; //Whether or not to remove unused keys form the config
private boolean copyDefaults; //Whether or not to copy the default config when first creating the file
2013-07-12 18:49:02 +02:00
2019-02-16 16:09:48 -08:00
/* PATH VARS */
2013-07-12 18:49:02 +02:00
2019-02-16 16:09:48 -08:00
public final File DIRECTORY_DATA_FOLDER; //Directory that the file is in
public final String FILE_RELATIVE_PATH; //Relative Path to the file
protected final String DIRECTORY_DEFAULTS = "defaults";
2013-07-12 18:49:02 +02:00
2019-02-16 16:09:48 -08:00
/* LOADERS */
2013-07-12 18:49:02 +02:00
private ConfigurationLoader<CommentedConfigurationNode> defaultCopyLoader;
private ConfigurationLoader<CommentedConfigurationNode> userCopyLoader;
2019-02-16 16:09:48 -08:00
/* CONFIG FILES */
2019-02-16 16:09:48 -08:00
private File resourceConfigCopy; //Copy of the default config from the JAR (file is copied so that admins can easily compare to defaults)
private File resourceUserCopy; //File in the /$MCMMO_ROOT/mcMMO/ directory that may contain user edited settings
2019-02-16 16:09:48 -08:00
/* ROOT NODES */
private CommentedConfigurationNode userRootNode = null;
private CommentedConfigurationNode defaultRootNode = null;
2013-07-12 18:49:02 +02:00
2019-02-16 16:09:48 -08:00
/* CONFIG MANAGER */
2019-02-20 19:14:21 -08:00
//private ConfigurationLoader<CommentedConfigurationNode> configManager;
2013-07-12 18:49:02 +02:00
2019-02-20 19:14:21 -08:00
public Config(String pathToParentFolder, String relativePath, boolean mergeNewKeys, boolean copyDefaults) {
2019-02-16 16:09:48 -08:00
//TODO: Check if this works...
2019-02-20 19:14:21 -08:00
this(new File(pathToParentFolder), relativePath, mergeNewKeys, copyDefaults);
2019-02-16 16:09:48 -08:00
System.out.println("mcMMO Debug: Don't forget to check if loading config file by string instead of File works...");
}
2013-07-12 18:49:02 +02:00
2019-02-20 19:14:21 -08:00
public Config(File pathToParentFolder, String relativePath, boolean mergeNewKeys, boolean copyDefaults) {
2019-02-16 16:09:48 -08:00
/*
* These must be at the top
*/
2019-02-20 19:14:21 -08:00
this.copyDefaults = copyDefaults;
2019-02-16 16:09:48 -08:00
this.mergeNewKeys = mergeNewKeys; //Whether or not we add new keys when they are found
mkdirDefaults(); // Make our default config dir
DIRECTORY_DATA_FOLDER = pathToParentFolder; //Data Folder for our plugin
FILE_RELATIVE_PATH = relativePath; //Relative path to config from a parent folder
2013-07-12 18:49:02 +02:00
registerUnload();
2019-02-16 16:09:48 -08:00
//Attempt IO Operations
try {
//Makes sure we have valid Files corresponding to this config
initConfigFiles();
2013-07-12 18:49:02 +02:00
2019-02-16 16:09:48 -08:00
//Init MainConfig Loaders
initConfigLoaders();
2013-07-12 18:49:02 +02:00
2019-02-16 16:09:48 -08:00
//Load MainConfig Nodes
loadConfig();
2013-07-12 18:49:02 +02:00
2019-02-16 16:09:48 -08:00
//Attempt to update user file, and then load it into memory
readConfig();
} catch (IOException e) {
e.printStackTrace();
2013-07-12 18:49:02 +02:00
}
}
2013-07-12 18:49:02 +02:00
/**
* Registers with the config managers unloader
* The unloader runs when the plugin gets disabled which cleans up registries to make reloading safe
*/
private void registerUnload()
{
mcMMO.getConfigManager().registerUnloadable(this);
2019-02-16 16:09:48 -08:00
}
2013-07-12 18:49:02 +02:00
2019-02-16 16:09:48 -08:00
/**
* Initializes the default copy File and the user config File
* @throws IOException
*/
private void initConfigFiles() throws IOException {
//Init our config copy
resourceConfigCopy = initDefaultConfig();
2013-07-12 18:49:02 +02:00
2019-02-16 16:09:48 -08:00
//Init the user file
resourceUserCopy = initUserConfig();
}
2013-07-12 18:49:02 +02:00
2019-02-16 16:09:48 -08:00
/**
* Loads the root node for the default config File and user config File
*/
private void loadConfig()
{
try {
final CommentedConfigurationNode defaultConfig = this.defaultCopyLoader.load();
2019-02-16 16:09:48 -08:00
defaultRootNode = defaultConfig;
final CommentedConfigurationNode userConfig = this.userCopyLoader.load();
2019-02-16 16:09:48 -08:00
userRootNode = userConfig;
2019-02-16 16:09:48 -08:00
} catch (IOException e) {
e.printStackTrace();
2013-07-12 18:49:02 +02:00
}
2019-02-16 16:09:48 -08:00
}
2013-07-12 18:49:02 +02:00
2019-02-16 16:09:48 -08:00
/**
* Initializes the YAMLConfigurationLoaders for this config
*/
private void initConfigLoaders()
{
this.defaultCopyLoader = YAMLConfigurationLoader.builder().setPath(resourceConfigCopy.toPath()).setFlowStyle(DumperOptions.FlowStyle.BLOCK).build();
this.userCopyLoader = YAMLConfigurationLoader.builder().setPath(resourceUserCopy.toPath()).setFlowStyle(DumperOptions.FlowStyle.FLOW).build();
}
2013-07-12 18:49:02 +02:00
2019-02-16 16:09:48 -08:00
/**
* Copies a new file from the JAR to the defaults directory and uses that new file to initialize our resourceConfigCopy
* @see Config#resourceConfigCopy
* @throws IOException
*/
private File initDefaultConfig() throws IOException {
return copyDefaultFromJar(getDefaultConfigCopyRelativePath(), true);
}
2019-02-16 16:09:48 -08:00
/**
* Attemps to load the config file if it exists, if it doesn't it copies a new one from within the JAR
* @return user config File
* @see Config#resourceUserCopy
* @throws IOException
*/
private File initUserConfig() throws IOException {
File userCopy = new File(DIRECTORY_DATA_FOLDER, FILE_RELATIVE_PATH); //Load the user file;
2013-07-12 18:49:02 +02:00
2019-02-16 16:09:48 -08:00
if(userCopy.exists())
{
// Yay
return userCopy;
2013-07-12 18:49:02 +02:00
}
2019-02-16 16:09:48 -08:00
else
{
//If it's gone we copy default files
//Note that we don't copy the values from the default copy put in /defaults/ that file exists only as a reference to admins and is unreliable
2019-02-20 19:14:21 -08:00
if(copyDefaults)
return copyDefaultFromJar(FILE_RELATIVE_PATH, false);
else
{
//Make a new empty file
userCopy.createNewFile();
return userCopy;
}
2013-07-12 18:49:02 +02:00
}
2019-02-16 16:09:48 -08:00
}
2013-07-12 18:49:02 +02:00
2019-02-16 16:09:48 -08:00
/**
* Used to make a new config file at a specified relative output path inside the data directory by copying the matching file found in that same relative path within the JAR
* @param relativeOutputPath the path to the output file
* @param deleteOld whether or not to delete the existing output file on disk
* @return a copy of the default config within the JAR
* @throws IOException
*/
private File copyDefaultFromJar(String relativeOutputPath, boolean deleteOld) throws IOException
{
/*
* Gen a Default config from inside the JAR
*/
2019-02-18 09:04:20 -08:00
mcMMO.p.getLogger().info("Preparing to copy internal resource file (in JAR) - "+FILE_RELATIVE_PATH);
//InputStream inputStream = McmmoCore.getResource(FILE_RELATIVE_PATH);
InputStream inputStream = mcMMO.p.getResource(FILE_RELATIVE_PATH);
2013-07-12 18:49:02 +02:00
2019-02-16 16:09:48 -08:00
byte[] buffer = new byte[inputStream.available()];
inputStream.read(buffer);
2013-07-12 18:49:02 +02:00
2019-02-16 16:09:48 -08:00
//This is a copy of the default file, which we will overwrite every time mcMMO loads
File targetFile = new File(DIRECTORY_DATA_FOLDER, relativeOutputPath);
2013-07-12 18:49:02 +02:00
2019-02-16 16:09:48 -08:00
//Wipe old default file on disk
if (targetFile.exists() && deleteOld)
{
2019-02-18 09:04:20 -08:00
mcMMO.p.getLogger().info("Updating file " + relativeOutputPath);
2019-02-16 16:09:48 -08:00
targetFile.delete(); //Necessary?
}
2019-02-16 16:09:48 -08:00
if(!targetFile.exists())
{
targetFile.getParentFile().mkdirs();
targetFile.createNewFile(); //New File Boys
}
2019-02-16 16:09:48 -08:00
Files.write(buffer, targetFile);
2019-02-18 09:04:20 -08:00
mcMMO.p.getLogger().info("Created config file - " + relativeOutputPath);
2019-02-16 16:09:48 -08:00
inputStream.close(); //Close the input stream
2013-07-24 23:45:31 +02:00
2019-02-16 16:09:48 -08:00
return targetFile;
}
2019-02-16 16:09:48 -08:00
/**
* The path to the defaults directory
* @return the path to the defaults directory
*/
private String getDefaultConfigCopyRelativePath() {
return DIRECTORY_DEFAULTS + File.separator + FILE_RELATIVE_PATH;
}
2019-02-16 16:09:48 -08:00
/**
* Creates the defaults directory
*/
private void mkdirDefaults() {
//Make Default Subdirectory
File defaultsDir = new File (DIRECTORY_DATA_FOLDER, "defaults");
2013-07-24 23:45:31 +02:00
2019-02-16 16:09:48 -08:00
if(!defaultsDir.exists())
defaultsDir.mkdir();
2013-07-12 18:49:02 +02:00
}
2019-02-16 16:09:48 -08:00
/**
* Configs are versioned based on when they had significant changes to keys
* @return current MainConfig Version String
2012-04-26 07:32:38 -07:00
*/
2019-02-16 16:09:48 -08:00
public String getVersion()
{
return String.valueOf(getConfigVersion());
}
2012-04-26 07:32:38 -07:00
2019-02-16 16:09:48 -08:00
/**
* Attempts to read the loaded config file
* MainConfig will have any necessary updates applied
* MainConfig will be compared to the default config to see if it is missing any nodes
* MainConfig will have any missing nodes inserted with their default value
*/
public void readConfig() {
2019-02-18 09:04:20 -08:00
mcMMO.p.getLogger().info("Attempting to read " + FILE_RELATIVE_PATH + ".");
2018-12-31 10:10:00 -08:00
2019-02-16 16:09:48 -08:00
int version = this.userRootNode.getNode("ConfigVersion").getInt();
2019-02-18 09:04:20 -08:00
mcMMO.p.getLogger().info(FILE_RELATIVE_PATH + " version is " + version);
2019-02-16 16:09:48 -08:00
//Update our config
updateConfig();
}
2019-02-16 16:09:48 -08:00
/**
* Compares the users config file to the default and adds any missing nodes and applies any necessary updates
*/
private void updateConfig()
{
2019-02-18 09:04:20 -08:00
mcMMO.p.getLogger().info(defaultRootNode.getChildrenMap().size() +" items in default children map");
mcMMO.p.getLogger().info(userRootNode.getChildrenMap().size() +" items in default root map");
2019-02-16 16:09:48 -08:00
// Merge Values from default
if(mergeNewKeys)
userRootNode = userRootNode.mergeValuesFrom(defaultRootNode);
2019-02-16 16:09:48 -08:00
removeOldKeys();
2019-02-16 16:09:48 -08:00
// Update config version
updateConfigVersion();
2017-10-03 23:32:54 -04:00
2019-02-16 16:09:48 -08:00
//Attempt to save
try {
2019-02-16 16:09:48 -08:00
saveUserCopy();
} catch (IOException e) {
e.printStackTrace();
}
}
2019-02-18 09:04:20 -08:00
/**
* Finds any keys in the users config that are not present in the default config and removes them
*/
private void removeOldKeys()
{
if(!removeOldKeys)
return;
for(CommentedConfigurationNode configurationNode : defaultRootNode.getChildrenList())
2019-02-18 09:04:20 -08:00
{
}
}
2019-02-16 16:09:48 -08:00
/**
* Saves the current state information of the config to the users copy (which they may edit)
* @throws IOException
*/
private void saveUserCopy() throws IOException
{
2019-02-18 09:04:20 -08:00
mcMMO.p.getLogger().info("Saving new node");
2019-02-16 16:09:48 -08:00
userCopyLoader.save(userRootNode);
}
2012-12-28 11:40:15 +01:00
2019-02-16 16:09:48 -08:00
/**
* Performs any necessary operations to update this config
*/
private void updateConfigVersion() {
// Set a version for our config
this.userRootNode.getNode("ConfigVersion").setValue(getConfigVersion());
2019-02-18 09:04:20 -08:00
mcMMO.p.getLogger().info("Updated config to ["+getConfigVersion()+"] - " + FILE_RELATIVE_PATH);
}
2019-02-16 16:09:48 -08:00
/**
* Returns the root node of this config
* @return the root node of this config
2012-04-26 07:32:38 -07:00
*/
protected CommentedConfigurationNode getUserRootNode() {
2019-02-16 16:09:48 -08:00
return userRootNode;
}
2012-04-26 07:32:38 -07:00
/**
* Gets an int from the config and casts it to short before returning
* @param path the path to the int
* @return the value of the int after being cast to short at the node, null references will zero initialize
*/
public short getShortValue(String... path) { return (short) userRootNode.getNode(path).getInt();}
2019-02-16 16:09:48 -08:00
/**
* Grabs an int from the specified node
* @param path
* @return the int from the node, null references will zero initialize
2012-04-26 07:32:38 -07:00
*/
2019-02-16 16:09:48 -08:00
public int getIntValue(String... path)
{
return userRootNode.getNode(path).getInt();
}
2012-04-26 07:32:38 -07:00
2019-02-16 16:09:48 -08:00
/**
* Grabs a double from the specified node
* @param path
* @return the double from the node, null references will zero initialize
*/
public double getDoubleValue(String... path)
{
return userRootNode.getNode(path).getDouble();
}
2019-02-18 14:29:29 -08:00
/**
* Grabs a long from the specified node
* @param path
* @return the long from the node, null references will zero initialize
*/
public long getLongValue(String... path)
{
return userRootNode.getNode(path).getLong();
}
2019-02-16 16:09:48 -08:00
/**
* Grabs a boolean from the specified node
* @param path
* @return the boolean from the node, null references will zero initialize
*/
public boolean getBooleanValue(String... path)
{
return userRootNode.getNode(path).getBoolean();
}
2012-04-26 07:32:38 -07:00
2019-02-16 16:09:48 -08:00
/**
* Grabs a string from the specified node
* @param path
* @return the string from the node, null references will zero initialize
*/
public String getStringValue(String... path)
{
return userRootNode.getNode(path).getString();
}
2019-02-16 16:09:48 -08:00
/**
* Checks to see if a node exists in the user's config file
* @param path path to the node
* @return true if the node exists
*/
public boolean hasNode(String... path) {
return (userRootNode.getNode(path) != null);
}
2019-02-18 15:35:46 -08:00
/**
* Gets a a List of type String from the Configuration file
* @param path path to the node
* @return a list of strings at the node, if null it will most likely zero initialize (empty list)
* @throws ObjectMappingException
*/
2019-02-18 15:35:46 -08:00
public List<String> getStringValueList(String... path) throws ObjectMappingException {
return userRootNode.getList(TypeToken.of(String.class));
}
}