From bb76223da69cbd58c076cb21d58c03cdf6ff4c6d Mon Sep 17 00:00:00 2001 From: Vincent <79623093+V1nc3ntWasTaken@users.noreply.github.com> Date: Sun, 18 Sep 2022 19:09:34 -0500 Subject: [PATCH] Added a dynamic config --- .../me/doclic/noencryption/NoEncryption.java | 17 ++ .../noencryption/config/ConfigNodes.java | 102 ++++++++ .../config/ConfigurationHandler.java | 229 +++++++++++++++++ .../utils/CommentedConfiguration.java | 239 ++++++++++++++++++ .../doclic/noencryption/utils/FileMgmt.java | 93 +++++++ .../me/doclic/noencryption/NoEncryption.java | 17 ++ .../noencryption/config/ConfigNodes.java | 102 ++++++++ .../config/ConfigurationHandler.java | 228 +++++++++++++++++ .../utils/CommentedConfiguration.java | 239 ++++++++++++++++++ .../doclic/noencryption/utils/FileMgmt.java | 93 +++++++ .../me/doclic/noencryption/NoEncryption.java | 19 ++ .../noencryption/config/ConfigNodes.java | 102 ++++++++ .../config/ConfigurationHandler.java | 228 +++++++++++++++++ .../utils/CommentedConfiguration.java | 239 ++++++++++++++++++ .../doclic/noencryption/utils/FileMgmt.java | 93 +++++++ 15 files changed, 2040 insertions(+) create mode 100644 1.19.1/src/main/java/me/doclic/noencryption/config/ConfigNodes.java create mode 100644 1.19.1/src/main/java/me/doclic/noencryption/config/ConfigurationHandler.java create mode 100644 1.19.1/src/main/java/me/doclic/noencryption/utils/CommentedConfiguration.java create mode 100644 1.19.1/src/main/java/me/doclic/noencryption/utils/FileMgmt.java create mode 100644 1.19.2/src/main/java/me/doclic/noencryption/config/ConfigNodes.java create mode 100644 1.19.2/src/main/java/me/doclic/noencryption/config/ConfigurationHandler.java create mode 100644 1.19.2/src/main/java/me/doclic/noencryption/utils/CommentedConfiguration.java create mode 100644 1.19.2/src/main/java/me/doclic/noencryption/utils/FileMgmt.java create mode 100644 1.19/src/main/java/me/doclic/noencryption/config/ConfigNodes.java create mode 100644 1.19/src/main/java/me/doclic/noencryption/config/ConfigurationHandler.java create mode 100644 1.19/src/main/java/me/doclic/noencryption/utils/CommentedConfiguration.java create mode 100644 1.19/src/main/java/me/doclic/noencryption/utils/FileMgmt.java diff --git a/1.19.1/src/main/java/me/doclic/noencryption/NoEncryption.java b/1.19.1/src/main/java/me/doclic/noencryption/NoEncryption.java index 9c1e3d0..24efe59 100644 --- a/1.19.1/src/main/java/me/doclic/noencryption/NoEncryption.java +++ b/1.19.1/src/main/java/me/doclic/noencryption/NoEncryption.java @@ -1,6 +1,8 @@ package me.doclic.noencryption; import me.doclic.noencryption.compatibility.Compatibility; +import me.doclic.noencryption.config.ConfigurationHandler; +import me.doclic.noencryption.utils.FileMgmt; import org.bukkit.Bukkit; import org.bukkit.plugin.java.JavaPlugin; @@ -11,6 +13,17 @@ public void onEnable() { if (Compatibility.SERVER_COMPATIBLE) { + FileMgmt.initialize(this); + ConfigurationHandler.initialize(this); + + if (!ConfigurationHandler.loadSettings()) { + getLogger().severe("Configuration could not be loaded, disabling..."); + Bukkit.getPluginManager().disablePlugin(this); + return; + } + + ConfigurationHandler.printChanges(); + Bukkit.getPluginManager().registerEvents(new PlayerListener(), this); getLogger().info("Compatibility successful!"); @@ -27,4 +40,8 @@ public void onEnable() { } } + + public String getRootFolder() { + return this.getDataFolder().getPath(); + } } diff --git a/1.19.1/src/main/java/me/doclic/noencryption/config/ConfigNodes.java b/1.19.1/src/main/java/me/doclic/noencryption/config/ConfigNodes.java new file mode 100644 index 0000000..9b50c88 --- /dev/null +++ b/1.19.1/src/main/java/me/doclic/noencryption/config/ConfigNodes.java @@ -0,0 +1,102 @@ +package me.doclic.noencryption.config; + +public enum ConfigNodes { + HEADER(null, "fun", "", + " ", + "# |==========================================================|", + "# | |", + "# | NoEncryption Dynamic Configuration |", + "# | By Doclic and V1nc3ntWasTaken |", + "# | |", + "# | This is a dynamic configuration file that will be |", + "# | automatically updated when you update the plugin, |", + "# | although any new features will be disabled by default, |", + "# | and you will receive a one-time notification about |", + "# | any added config options in the console upon startup. |", + "# | |", + "# | -------------------------------------- |", + "# | |", + "# | Config entries will look like the following: |", + "# | |", + "# | friends: |", + "# | |", + "# | # Allows a user to become friends with the devs |", + "# | # |", + "# | # Note: Doesn't actually do anything, just here |", + "# | # for show, and example. |", + "# | # |", + "# | # Added in v3.0 |", + "# | # Default: false |", + "# | friendly-dev: false |", + "# | |", + "# |==========================================================|", + " "), + FRIENDLY_DEV("Test notice", "fun.friendly_dev", false, + " ", + "# Allows a user to become friends with the devs", + "# ", + "# Note: Doesn't actually do anything, just here", + "# for show, and example", + "# Added in v3.0", + "# Default: false"); + + + private final String Notice; + private final String Root; + private final Object Default; + private String[] comments; + + ConfigNodes(String notice, String root, Object def, String... comments) { + + this.Notice = notice; + this.Root = root; + this.Default = def; + this.comments = comments; + } + + /** + * Retrieves the root for a config option + * + * @return The root for a config option + */ + public String getNotice() { + + return (Notice != null ? Notice.trim() : null); + } + + /** + * Retrieves the root for a config option + * + * @return The root for a config option + */ + public String getRoot() { + + return Root; + } + + /** + * Retrieves the default value for a config path + * + * @return The default value for a config path + */ + public Object getDefault() { + + return Default; + } + + /** + * Retrieves the comment for a config path + * + * @return The comments for a config path + */ + public String[] getComments() { + + if (comments != null) { + return comments; + } + + String[] comments = new String[1]; + comments[0] = ""; + return comments; + } +} \ No newline at end of file diff --git a/1.19.1/src/main/java/me/doclic/noencryption/config/ConfigurationHandler.java b/1.19.1/src/main/java/me/doclic/noencryption/config/ConfigurationHandler.java new file mode 100644 index 0000000..b89620c --- /dev/null +++ b/1.19.1/src/main/java/me/doclic/noencryption/config/ConfigurationHandler.java @@ -0,0 +1,229 @@ +package me.doclic.noencryption.config; + +import me.doclic.noencryption.NoEncryption; +import me.doclic.noencryption.utils.CommentedConfiguration; +import me.doclic.noencryption.utils.FileMgmt; +import org.bukkit.Bukkit; + +import java.io.File; +import java.util.HashMap; +import java.util.logging.Level; + +public class ConfigurationHandler { + private static NoEncryption main; + private static CommentedConfiguration config, newConfig; + private static HashMap newOptions; + private static HashMap messages; + + public static void initialize(NoEncryption main) { + ConfigurationHandler.main = main; + newOptions = new HashMap<>(); + messages = new HashMap<>(); + } + + public static boolean loadSettings() { + FileMgmt.checkFolders(new String[]{ + main.getRootFolder(), + main.getRootFolder() + FileMgmt.fileSeparator() + "settings"}); + + return ConfigurationHandler.loadConfig(); + } + + private static boolean loadConfig() { + String filepath = main.getRootFolder() + FileMgmt.fileSeparator() + "settings" + FileMgmt.fileSeparator() + "config.yml"; + + File file = FileMgmt.CheckYMLExists(new File(filepath)); + if (file != null) { + + // read the config.yml into memory + config = new CommentedConfiguration(file); + if (!config.load()) { + main.getLogger().log(Level.SEVERE, "Failed to load config.yml"); + return false; + } + + setDefaults(file); + + config.save(); + } + return true; + } + + /** + * Builds a new config reading old config data. + */ + private static void setDefaults(File file) { + + newConfig = new CommentedConfiguration(file); + newConfig.load(); + + for (ConfigNodes root : ConfigNodes.values()) { + if (root.getComments().length > 0) { + addComment(root.getRoot(), root.getComments()); + } + + setNewProperty(root.getRoot(), (config.get(root.getRoot().toLowerCase()) != null) ? config.get(root.getRoot().toLowerCase()) : root.getDefault()); + + if (config != null && !config.getKeys(true).contains(root.getRoot()) && !root.getDefault().equals("")) { + newOptions.put(root.getRoot(), root.getDefault()); + } + + if (root.getNotice() != null) { + messages.put(root.getRoot(), root.getNotice()); + } + + } + + config = newConfig; + newConfig = null; + } + + /** + * Prints any new config options to the config + */ + public static void printChanges() { + + main.getLogger().log(Level.INFO, "Checking for new config option..."); + if (!newOptions.isEmpty()) { + + newOptions.forEach((root, def) -> main.getLogger().log(Level.INFO, " " + root + ": " + def)); + } else { + main.getLogger().log(Level.INFO, "No new config options detected"); + } + + main.getLogger().log(Level.INFO, "Checking for important messages..."); + if (!messages.isEmpty()) { + + messages.forEach((root, msg) -> main.getLogger().log(Level.WARNING, " " + root + ": \"" + msg + "\"")); + } else { + main.getLogger().log(Level.INFO, "No important messages detected"); + } + } + + private static void addComment(String root, String... comments) { + + newConfig.addComment(root.toLowerCase(), comments); + } + + private static void setProperty(String root, Object value) { + + config.set(root.toLowerCase(), value.toString()); + } + + private static void setNewProperty(String root, Object value) { + + if (value == null) { + // System.out.print("value is null for " + root.toLowerCase()); + value = ""; + } + newConfig.set(root.toLowerCase(), value.toString()); + } + + + /** + * Get's a value for a ConfigNode + * + * @param node - ConfigNode + * @return - Value for node + */ + private static String getString(ConfigNodes node) { + + return config.getString(node.getRoot().toLowerCase(), String.valueOf(node.getDefault())); + + } + + /** + * Get's a value for a ConfigNode + * + * @param node - ConfigNode + * @return - Value for node (specifically boolean) + */ + private static boolean getBoolean(ConfigNodes node) { + + return config.getBoolean(node.getRoot().toLowerCase(), Boolean.parseBoolean(String.valueOf(node.getDefault()))); + } + + /** + * Get's a value for a ConfigNode + * + * @param node - ConfigNode + * @return - Value for node (specifically double) + */ + private static double getDouble(ConfigNodes node) { + + try { + return config.getDouble(node.getRoot().toLowerCase(), Double.parseDouble(String.valueOf(node.getDefault()))); + } catch (NumberFormatException e) { + main.getLogger().log(Level.SEVERE, "Could not get/read double for value: " + node.getRoot().toLowerCase()); + return 0.0; + } + } + + /** + * Get's a value for a ConfigNode + * + * @param node - ConfigNode + * @return - Value for node (specifically int) + */ + private static int getInt(ConfigNodes node) { + + try { + return config.getInt(node.getRoot().toLowerCase(), Integer.parseInt(String.valueOf(node.getDefault()))); + } catch (NumberFormatException e) { + main.getLogger().log(Level.SEVERE, "Could not get/read int for value: " + node.getRoot().toLowerCase()); + return 0; + } + } + + /* public static String getDBTablePrefix() { + return getString(ConfigNodes.DATABASE_TABLE_PREFIX); + } + + public static String getLoadDBType() { + return getString(ConfigNodes.DATABASE_LOAD_TYPE).toLowerCase(); + } + + public static String getLoadDBHostname() { + return getString(ConfigNodes.DATABASE_LOAD_HOSTNAME); + } + + public static String getLoadDBPort() { + return getString(ConfigNodes.DATABASE_LOAD_PORT); + } + + public static String getLoadDBSchemaName() { + return getString(ConfigNodes.DATABASE_LOAD_SCHEMA_NAME); + } + + public static String getLoadDBUsername() { + return getString(ConfigNodes.DATABASE_LOAD_USERNAME); + } + + public static String getLoadDBPassword() { + return getString(ConfigNodes.DATABASE_LOAD_PASSWORD); + } + + public static String getSaveDBType() { + return getString(ConfigNodes.DATABASE_SAVE_TYPE).toLowerCase(); + } + + public static String getSaveDBHostname() { + return getString(ConfigNodes.DATABASE_SAVE_HOSTNAME); + } + + public static String getSaveDBPort() { + return getString(ConfigNodes.DATABASE_SAVE_PORT); + } + + public static String getSaveDBSchemaName() { + return getString(ConfigNodes.DATABASE_SAVE_SCHEMA_NAME); + } + + public static String getSaveDBUsername() { + return getString(ConfigNodes.DATABASE_SAVE_USERNAME); + } + + public static String getSaveDBPassword() { + return getString(ConfigNodes.DATABASE_SAVE_PASSWORD); + }*/ +} \ No newline at end of file diff --git a/1.19.1/src/main/java/me/doclic/noencryption/utils/CommentedConfiguration.java b/1.19.1/src/main/java/me/doclic/noencryption/utils/CommentedConfiguration.java new file mode 100644 index 0000000..8035db3 --- /dev/null +++ b/1.19.1/src/main/java/me/doclic/noencryption/utils/CommentedConfiguration.java @@ -0,0 +1,239 @@ +package me.doclic.noencryption.utils; + +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import org.apache.commons.lang.Validate; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.configuration.file.YamlConstructor; +import org.bukkit.configuration.file.YamlRepresenter; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.representer.Representer; + +import java.io.*; +import java.util.HashMap; + +/** + * @author dumptruckman, LlmDL & Articdive + */ +public class CommentedConfiguration extends YamlConfiguration { + + private final DumperOptions yamlOptions = new DumperOptions(); + private final Representer yamlRepresenter = new YamlRepresenter(); + private final Yaml yaml = new Yaml(new YamlConstructor(), yamlRepresenter, yamlOptions); + private HashMap comments; + private File file; + + public CommentedConfiguration(File file) { + + super(); + //this.load(file); + comments = new HashMap<>(); + this.file = file; + } + + public boolean load() { + + boolean loaded = true; + + try { + this.load(file); + } catch (InvalidConfigurationException | IOException e) { + loaded = false; + } + + return loaded; + } + + public void save() { + + boolean saved = true; + + // Save the config just like normal + try { + /* + * Doing some saving of our own. We have found that the implementation of YAMLComfiguration used by Bukkit will attempt to + * cap strings at 80 characters long, forming new lines in some of our longer strings (channel_formats.) + */ + this.save(file); + + } catch (Exception e) { + saved = false; + } + + // if there's comments to add and it saved fine, we need to add comments + if (!comments.isEmpty() && saved) { + // String array of each line in the config file + String[] yamlContents = FileMgmt.convertFileToString(file).split("[" + System.getProperty("line.separator") + "]"); + + // This will hold the newly formatted line + StringBuilder newContents = new StringBuilder(); + // This holds the current path the lines are at in the config + String currentPath = ""; + // This flags if the line is a node or unknown text. + boolean node; + // The depth of the path. (number of words separated by periods - 1) + int depth = 0; + + // Loop through the config lines + for (String line : yamlContents) { + // If the line is a node (and not something like a list value) + if (line.contains(": ") || (line.length() > 1 && line.charAt(line.length() - 1) == ':')) { + // This is a node so flag it as one + node = true; + + // Grab the index of the end of the node name + int index; + index = line.indexOf(": "); + if (index < 0) { + index = line.length() - 1; + } + // If currentPath is empty, store the node name as the currentPath. (this is only on the first iteration, i think) + if (currentPath.isEmpty()) { + currentPath = line.substring(0, index); + } else { + // Calculate the whitespace preceding the node name + int whiteSpace = 0; + for (int n = 0; n < line.length(); n++) { + if (line.charAt(n) == ' ') { + whiteSpace++; + } else { + break; + } + } + // Find out if the current depth (whitespace * 2) is greater/lesser/equal to the previous depth + if (whiteSpace / 2 > depth) { + // Path is deeper. Add a . and the node name + currentPath += "." + line.substring(whiteSpace, index); + depth++; + } else if (whiteSpace / 2 < depth) { + // Path is shallower, calculate current depth from whitespace (whitespace / 2) and subtract that many levels from the currentPath + int newDepth = whiteSpace / 2; + for (int i = 0; i < depth - newDepth; i++) { + currentPath = currentPath.replace(currentPath.substring(currentPath.lastIndexOf(".")), ""); + } + // Grab the index of the final period + int lastIndex = currentPath.lastIndexOf("."); + if (lastIndex < 0) { + // if there isn't a final period, set the current path to nothing because we're at root + currentPath = ""; + } else { + // If there is a final period, replace everything after it with nothing + currentPath = currentPath.replace(currentPath.substring(currentPath.lastIndexOf(".")), ""); + currentPath += "."; + } + // Add the new node name to the path + currentPath += line.substring(whiteSpace, index); + // Reset the depth + depth = newDepth; + } else { + // Path is same depth, replace the last path node name to the current node name + int lastIndex = currentPath.lastIndexOf("."); + if (lastIndex < 0) { + // if there isn't a final period, set the current path to nothing because we're at root + currentPath = ""; + } else { + // If there is a final period, replace everything after it with nothing + currentPath = currentPath.replace(currentPath.substring(currentPath.lastIndexOf(".")), ""); + currentPath += "."; + } + //currentPath = currentPath.replace(currentPath.substring(currentPath.lastIndexOf(".")), ""); + currentPath += line.substring(whiteSpace, index); + + } + + } + + } else + node = false; + + if (node) { + String comment; + // If there's a comment for the current path, retrieve it and flag that path as already commented + comment = comments.get(currentPath); + if (comment != null) { + // Add the comment to the beginning of the current line + line = comment + System.getProperty("line.separator") + line + System.getProperty("line.separator"); + } else { + // Add a new line as it is a node, but has no comment + line += System.getProperty("line.separator"); + } + } + // Add the (modified) line to the total config String + newContents.append(line).append((!node) ? System.getProperty("line.separator") : ""); + + } + /* + * Due to a bukkit bug we need to strip any extra new lines from the + * beginning of this file, else they will multiply. + */ + while (newContents.toString().startsWith(System.getProperty("line.separator"))) + newContents = new StringBuilder(newContents.toString().replaceFirst(System.getProperty("line.separator"), "")); + + // Write the string to the config file + FileMgmt.stringToFile(newContents.toString(), file); + } + } + + /** + * Adds a comment just before the specified path. The comment can be + * multiple lines. An empty string will indicate a blank line. + * + * @param path Configuration path to add comment. + * @param commentLines Comments to add. One String per line. + */ + public void addComment(String path, String... commentLines) { + + StringBuilder commentstring = new StringBuilder(); + StringBuilder leadingSpaces = new StringBuilder(); + for (int n = 0; n < path.length(); n++) { + if (path.charAt(n) == '.') { + leadingSpaces.append(" "); + } + } + for (String line : commentLines) { + if (!line.isEmpty()) { + line = leadingSpaces + line; + } else { + line = ""; + } + if (commentstring.length() > 0) { + commentstring.append(System.getProperty("line.separator")); + } + commentstring.append(line); + } + comments.put(path, commentstring.toString()); + } + + + public void save(File file) throws IOException { + Validate.notNull(file, "File cannot be null"); + + Files.createParentDirs(file); + + String data = this.saveToString(); + + try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), Charsets.UTF_8)) { + writer.write(data); + } + } + + @Override + public String saveToString() { + yamlOptions.setIndent(options().indent()); + yamlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + yamlOptions.setWidth(10000); + yamlRepresenter.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + + + String dump = yaml.dump(getValues(false)); + + + if (dump.equals(BLANK_CONFIG)) { + dump = ""; + } + + return dump; + } +} \ No newline at end of file diff --git a/1.19.1/src/main/java/me/doclic/noencryption/utils/FileMgmt.java b/1.19.1/src/main/java/me/doclic/noencryption/utils/FileMgmt.java new file mode 100644 index 0000000..8b6c8ca --- /dev/null +++ b/1.19.1/src/main/java/me/doclic/noencryption/utils/FileMgmt.java @@ -0,0 +1,93 @@ +package me.doclic.noencryption.utils; + +import me.doclic.noencryption.NoEncryption; + +import java.io.*; +import java.util.logging.Level; + +public class FileMgmt { + private static NoEncryption main; + + public static void initialize(NoEncryption main) { + FileMgmt.main = main; + } + + public static void checkFolders(String[] folders) { + + for (String folder : folders) { + File f = new File(folder); + if (!(f.exists() && f.isDirectory())) { + f.getParentFile().mkdirs(); + f.mkdir(); + + } + } + } + + public static String fileSeparator() { + + return System.getProperty("file.separator"); + } + + public static File CheckYMLExists(File file) { + + if (!file.exists()) { + try { + file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return file; + } + + /** + * Pass a file and it will return it's contents as a string. + * + * @param file File to read. + * @return Contents of file. String will be empty in case of any errors. + */ + public static String convertFileToString(File file) { + + if (file != null && file.exists() && file.canRead() && !file.isDirectory()) { + Writer writer = new StringWriter(); + + char[] buffer = new char[1024]; + try (InputStream is = new FileInputStream(file)) { + Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); + int n; + while ((n = reader.read(buffer)) != -1) { + writer.write(buffer, 0, n); + } + reader.close(); + } catch (IOException e) { + main.getLogger().log(Level.SEVERE, "Exception: " + e.getMessage()); + } + return writer.toString(); + } else { + return ""; + } + } + + /** + * Writes the contents of a string to a file. + * + * @param source String to write. + * @param file File to write to. + * @return True on success. + * @throws IOException + */ + public static void stringToFile(String source, File file) { + + try { + + OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(file), "UTF-8"); + + out.write(source); + out.close(); + + } catch (IOException e) { + main.getLogger().log(Level.SEVERE, "Exception: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/1.19.2/src/main/java/me/doclic/noencryption/NoEncryption.java b/1.19.2/src/main/java/me/doclic/noencryption/NoEncryption.java index 9c1e3d0..24efe59 100644 --- a/1.19.2/src/main/java/me/doclic/noencryption/NoEncryption.java +++ b/1.19.2/src/main/java/me/doclic/noencryption/NoEncryption.java @@ -1,6 +1,8 @@ package me.doclic.noencryption; import me.doclic.noencryption.compatibility.Compatibility; +import me.doclic.noencryption.config.ConfigurationHandler; +import me.doclic.noencryption.utils.FileMgmt; import org.bukkit.Bukkit; import org.bukkit.plugin.java.JavaPlugin; @@ -11,6 +13,17 @@ public void onEnable() { if (Compatibility.SERVER_COMPATIBLE) { + FileMgmt.initialize(this); + ConfigurationHandler.initialize(this); + + if (!ConfigurationHandler.loadSettings()) { + getLogger().severe("Configuration could not be loaded, disabling..."); + Bukkit.getPluginManager().disablePlugin(this); + return; + } + + ConfigurationHandler.printChanges(); + Bukkit.getPluginManager().registerEvents(new PlayerListener(), this); getLogger().info("Compatibility successful!"); @@ -27,4 +40,8 @@ public void onEnable() { } } + + public String getRootFolder() { + return this.getDataFolder().getPath(); + } } diff --git a/1.19.2/src/main/java/me/doclic/noencryption/config/ConfigNodes.java b/1.19.2/src/main/java/me/doclic/noencryption/config/ConfigNodes.java new file mode 100644 index 0000000..9b50c88 --- /dev/null +++ b/1.19.2/src/main/java/me/doclic/noencryption/config/ConfigNodes.java @@ -0,0 +1,102 @@ +package me.doclic.noencryption.config; + +public enum ConfigNodes { + HEADER(null, "fun", "", + " ", + "# |==========================================================|", + "# | |", + "# | NoEncryption Dynamic Configuration |", + "# | By Doclic and V1nc3ntWasTaken |", + "# | |", + "# | This is a dynamic configuration file that will be |", + "# | automatically updated when you update the plugin, |", + "# | although any new features will be disabled by default, |", + "# | and you will receive a one-time notification about |", + "# | any added config options in the console upon startup. |", + "# | |", + "# | -------------------------------------- |", + "# | |", + "# | Config entries will look like the following: |", + "# | |", + "# | friends: |", + "# | |", + "# | # Allows a user to become friends with the devs |", + "# | # |", + "# | # Note: Doesn't actually do anything, just here |", + "# | # for show, and example. |", + "# | # |", + "# | # Added in v3.0 |", + "# | # Default: false |", + "# | friendly-dev: false |", + "# | |", + "# |==========================================================|", + " "), + FRIENDLY_DEV("Test notice", "fun.friendly_dev", false, + " ", + "# Allows a user to become friends with the devs", + "# ", + "# Note: Doesn't actually do anything, just here", + "# for show, and example", + "# Added in v3.0", + "# Default: false"); + + + private final String Notice; + private final String Root; + private final Object Default; + private String[] comments; + + ConfigNodes(String notice, String root, Object def, String... comments) { + + this.Notice = notice; + this.Root = root; + this.Default = def; + this.comments = comments; + } + + /** + * Retrieves the root for a config option + * + * @return The root for a config option + */ + public String getNotice() { + + return (Notice != null ? Notice.trim() : null); + } + + /** + * Retrieves the root for a config option + * + * @return The root for a config option + */ + public String getRoot() { + + return Root; + } + + /** + * Retrieves the default value for a config path + * + * @return The default value for a config path + */ + public Object getDefault() { + + return Default; + } + + /** + * Retrieves the comment for a config path + * + * @return The comments for a config path + */ + public String[] getComments() { + + if (comments != null) { + return comments; + } + + String[] comments = new String[1]; + comments[0] = ""; + return comments; + } +} \ No newline at end of file diff --git a/1.19.2/src/main/java/me/doclic/noencryption/config/ConfigurationHandler.java b/1.19.2/src/main/java/me/doclic/noencryption/config/ConfigurationHandler.java new file mode 100644 index 0000000..5f3528a --- /dev/null +++ b/1.19.2/src/main/java/me/doclic/noencryption/config/ConfigurationHandler.java @@ -0,0 +1,228 @@ +package me.doclic.noencryption.config; + +import me.doclic.noencryption.NoEncryption; +import me.doclic.noencryption.utils.CommentedConfiguration; +import me.doclic.noencryption.utils.FileMgmt; + +import java.io.File; +import java.util.HashMap; +import java.util.logging.Level; + +public class ConfigurationHandler { + private static NoEncryption main; + private static CommentedConfiguration config, newConfig; + private static HashMap newOptions; + private static HashMap messages; + + public static void initialize(NoEncryption main) { + ConfigurationHandler.main = main; + newOptions = new HashMap<>(); + messages = new HashMap<>(); + } + + public static boolean loadSettings() { + FileMgmt.checkFolders(new String[]{ + main.getRootFolder(), + main.getRootFolder() + FileMgmt.fileSeparator() + "settings"}); + + return ConfigurationHandler.loadConfig(); + } + + private static boolean loadConfig() { + String filepath = main.getRootFolder() + FileMgmt.fileSeparator() + "settings" + FileMgmt.fileSeparator() + "config.yml"; + + File file = FileMgmt.CheckYMLExists(new File(filepath)); + if (file != null) { + + // read the config.yml into memory + config = new CommentedConfiguration(file); + if (!config.load()) { + main.getLogger().log(Level.SEVERE, "Failed to load config.yml"); + return false; + } + + setDefaults(file); + + config.save(); + } + return true; + } + + /** + * Builds a new config reading old config data. + */ + private static void setDefaults(File file) { + + newConfig = new CommentedConfiguration(file); + newConfig.load(); + + for (ConfigNodes root : ConfigNodes.values()) { + if (root.getComments().length > 0) { + addComment(root.getRoot(), root.getComments()); + } + + setNewProperty(root.getRoot(), (config.get(root.getRoot().toLowerCase()) != null) ? config.get(root.getRoot().toLowerCase()) : root.getDefault()); + + if (config != null && !config.getKeys(true).contains(root.getRoot()) && !root.getDefault().equals("")) { + newOptions.put(root.getRoot(), root.getDefault()); + } + + if (root.getNotice() != null) { + messages.put(root.getRoot(), root.getNotice()); + } + + } + + config = newConfig; + newConfig = null; + } + + /** + * Prints any new config options to the config + */ + public static void printChanges() { + + main.getLogger().log(Level.INFO, "Checking for new config option..."); + if (!newOptions.isEmpty()) { + + newOptions.forEach((root, def) -> main.getLogger().log(Level.INFO, " " + root + ": " + def)); + } else { + main.getLogger().log(Level.INFO, "No new config options detected"); + } + + main.getLogger().log(Level.INFO, "Checking for important messages..."); + if (!messages.isEmpty()) { + + messages.forEach((root, msg) -> main.getLogger().log(Level.WARNING, " " + root + ": \"" + msg + "\"")); + } else { + main.getLogger().log(Level.INFO, "No important messages detected"); + } + } + + private static void addComment(String root, String... comments) { + + newConfig.addComment(root.toLowerCase(), comments); + } + + private static void setProperty(String root, Object value) { + + config.set(root.toLowerCase(), value.toString()); + } + + private static void setNewProperty(String root, Object value) { + + if (value == null) { + // System.out.print("value is null for " + root.toLowerCase()); + value = ""; + } + newConfig.set(root.toLowerCase(), value.toString()); + } + + + /** + * Get's a value for a ConfigNode + * + * @param node - ConfigNode + * @return - Value for node + */ + private static String getString(ConfigNodes node) { + + return config.getString(node.getRoot().toLowerCase(), String.valueOf(node.getDefault())); + + } + + /** + * Get's a value for a ConfigNode + * + * @param node - ConfigNode + * @return - Value for node (specifically boolean) + */ + private static boolean getBoolean(ConfigNodes node) { + + return config.getBoolean(node.getRoot().toLowerCase(), Boolean.parseBoolean(String.valueOf(node.getDefault()))); + } + + /** + * Get's a value for a ConfigNode + * + * @param node - ConfigNode + * @return - Value for node (specifically double) + */ + private static double getDouble(ConfigNodes node) { + + try { + return config.getDouble(node.getRoot().toLowerCase(), Double.parseDouble(String.valueOf(node.getDefault()))); + } catch (NumberFormatException e) { + main.getLogger().log(Level.SEVERE, "Could not get/read double for value: " + node.getRoot().toLowerCase()); + return 0.0; + } + } + + /** + * Get's a value for a ConfigNode + * + * @param node - ConfigNode + * @return - Value for node (specifically int) + */ + private static int getInt(ConfigNodes node) { + + try { + return config.getInt(node.getRoot().toLowerCase(), Integer.parseInt(String.valueOf(node.getDefault()))); + } catch (NumberFormatException e) { + main.getLogger().log(Level.SEVERE, "Could not get/read int for value: " + node.getRoot().toLowerCase()); + return 0; + } + } + + /* public static String getDBTablePrefix() { + return getString(ConfigNodes.DATABASE_TABLE_PREFIX); + } + + public static String getLoadDBType() { + return getString(ConfigNodes.DATABASE_LOAD_TYPE).toLowerCase(); + } + + public static String getLoadDBHostname() { + return getString(ConfigNodes.DATABASE_LOAD_HOSTNAME); + } + + public static String getLoadDBPort() { + return getString(ConfigNodes.DATABASE_LOAD_PORT); + } + + public static String getLoadDBSchemaName() { + return getString(ConfigNodes.DATABASE_LOAD_SCHEMA_NAME); + } + + public static String getLoadDBUsername() { + return getString(ConfigNodes.DATABASE_LOAD_USERNAME); + } + + public static String getLoadDBPassword() { + return getString(ConfigNodes.DATABASE_LOAD_PASSWORD); + } + + public static String getSaveDBType() { + return getString(ConfigNodes.DATABASE_SAVE_TYPE).toLowerCase(); + } + + public static String getSaveDBHostname() { + return getString(ConfigNodes.DATABASE_SAVE_HOSTNAME); + } + + public static String getSaveDBPort() { + return getString(ConfigNodes.DATABASE_SAVE_PORT); + } + + public static String getSaveDBSchemaName() { + return getString(ConfigNodes.DATABASE_SAVE_SCHEMA_NAME); + } + + public static String getSaveDBUsername() { + return getString(ConfigNodes.DATABASE_SAVE_USERNAME); + } + + public static String getSaveDBPassword() { + return getString(ConfigNodes.DATABASE_SAVE_PASSWORD); + }*/ +} \ No newline at end of file diff --git a/1.19.2/src/main/java/me/doclic/noencryption/utils/CommentedConfiguration.java b/1.19.2/src/main/java/me/doclic/noencryption/utils/CommentedConfiguration.java new file mode 100644 index 0000000..8035db3 --- /dev/null +++ b/1.19.2/src/main/java/me/doclic/noencryption/utils/CommentedConfiguration.java @@ -0,0 +1,239 @@ +package me.doclic.noencryption.utils; + +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import org.apache.commons.lang.Validate; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.configuration.file.YamlConstructor; +import org.bukkit.configuration.file.YamlRepresenter; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.representer.Representer; + +import java.io.*; +import java.util.HashMap; + +/** + * @author dumptruckman, LlmDL & Articdive + */ +public class CommentedConfiguration extends YamlConfiguration { + + private final DumperOptions yamlOptions = new DumperOptions(); + private final Representer yamlRepresenter = new YamlRepresenter(); + private final Yaml yaml = new Yaml(new YamlConstructor(), yamlRepresenter, yamlOptions); + private HashMap comments; + private File file; + + public CommentedConfiguration(File file) { + + super(); + //this.load(file); + comments = new HashMap<>(); + this.file = file; + } + + public boolean load() { + + boolean loaded = true; + + try { + this.load(file); + } catch (InvalidConfigurationException | IOException e) { + loaded = false; + } + + return loaded; + } + + public void save() { + + boolean saved = true; + + // Save the config just like normal + try { + /* + * Doing some saving of our own. We have found that the implementation of YAMLComfiguration used by Bukkit will attempt to + * cap strings at 80 characters long, forming new lines in some of our longer strings (channel_formats.) + */ + this.save(file); + + } catch (Exception e) { + saved = false; + } + + // if there's comments to add and it saved fine, we need to add comments + if (!comments.isEmpty() && saved) { + // String array of each line in the config file + String[] yamlContents = FileMgmt.convertFileToString(file).split("[" + System.getProperty("line.separator") + "]"); + + // This will hold the newly formatted line + StringBuilder newContents = new StringBuilder(); + // This holds the current path the lines are at in the config + String currentPath = ""; + // This flags if the line is a node or unknown text. + boolean node; + // The depth of the path. (number of words separated by periods - 1) + int depth = 0; + + // Loop through the config lines + for (String line : yamlContents) { + // If the line is a node (and not something like a list value) + if (line.contains(": ") || (line.length() > 1 && line.charAt(line.length() - 1) == ':')) { + // This is a node so flag it as one + node = true; + + // Grab the index of the end of the node name + int index; + index = line.indexOf(": "); + if (index < 0) { + index = line.length() - 1; + } + // If currentPath is empty, store the node name as the currentPath. (this is only on the first iteration, i think) + if (currentPath.isEmpty()) { + currentPath = line.substring(0, index); + } else { + // Calculate the whitespace preceding the node name + int whiteSpace = 0; + for (int n = 0; n < line.length(); n++) { + if (line.charAt(n) == ' ') { + whiteSpace++; + } else { + break; + } + } + // Find out if the current depth (whitespace * 2) is greater/lesser/equal to the previous depth + if (whiteSpace / 2 > depth) { + // Path is deeper. Add a . and the node name + currentPath += "." + line.substring(whiteSpace, index); + depth++; + } else if (whiteSpace / 2 < depth) { + // Path is shallower, calculate current depth from whitespace (whitespace / 2) and subtract that many levels from the currentPath + int newDepth = whiteSpace / 2; + for (int i = 0; i < depth - newDepth; i++) { + currentPath = currentPath.replace(currentPath.substring(currentPath.lastIndexOf(".")), ""); + } + // Grab the index of the final period + int lastIndex = currentPath.lastIndexOf("."); + if (lastIndex < 0) { + // if there isn't a final period, set the current path to nothing because we're at root + currentPath = ""; + } else { + // If there is a final period, replace everything after it with nothing + currentPath = currentPath.replace(currentPath.substring(currentPath.lastIndexOf(".")), ""); + currentPath += "."; + } + // Add the new node name to the path + currentPath += line.substring(whiteSpace, index); + // Reset the depth + depth = newDepth; + } else { + // Path is same depth, replace the last path node name to the current node name + int lastIndex = currentPath.lastIndexOf("."); + if (lastIndex < 0) { + // if there isn't a final period, set the current path to nothing because we're at root + currentPath = ""; + } else { + // If there is a final period, replace everything after it with nothing + currentPath = currentPath.replace(currentPath.substring(currentPath.lastIndexOf(".")), ""); + currentPath += "."; + } + //currentPath = currentPath.replace(currentPath.substring(currentPath.lastIndexOf(".")), ""); + currentPath += line.substring(whiteSpace, index); + + } + + } + + } else + node = false; + + if (node) { + String comment; + // If there's a comment for the current path, retrieve it and flag that path as already commented + comment = comments.get(currentPath); + if (comment != null) { + // Add the comment to the beginning of the current line + line = comment + System.getProperty("line.separator") + line + System.getProperty("line.separator"); + } else { + // Add a new line as it is a node, but has no comment + line += System.getProperty("line.separator"); + } + } + // Add the (modified) line to the total config String + newContents.append(line).append((!node) ? System.getProperty("line.separator") : ""); + + } + /* + * Due to a bukkit bug we need to strip any extra new lines from the + * beginning of this file, else they will multiply. + */ + while (newContents.toString().startsWith(System.getProperty("line.separator"))) + newContents = new StringBuilder(newContents.toString().replaceFirst(System.getProperty("line.separator"), "")); + + // Write the string to the config file + FileMgmt.stringToFile(newContents.toString(), file); + } + } + + /** + * Adds a comment just before the specified path. The comment can be + * multiple lines. An empty string will indicate a blank line. + * + * @param path Configuration path to add comment. + * @param commentLines Comments to add. One String per line. + */ + public void addComment(String path, String... commentLines) { + + StringBuilder commentstring = new StringBuilder(); + StringBuilder leadingSpaces = new StringBuilder(); + for (int n = 0; n < path.length(); n++) { + if (path.charAt(n) == '.') { + leadingSpaces.append(" "); + } + } + for (String line : commentLines) { + if (!line.isEmpty()) { + line = leadingSpaces + line; + } else { + line = ""; + } + if (commentstring.length() > 0) { + commentstring.append(System.getProperty("line.separator")); + } + commentstring.append(line); + } + comments.put(path, commentstring.toString()); + } + + + public void save(File file) throws IOException { + Validate.notNull(file, "File cannot be null"); + + Files.createParentDirs(file); + + String data = this.saveToString(); + + try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), Charsets.UTF_8)) { + writer.write(data); + } + } + + @Override + public String saveToString() { + yamlOptions.setIndent(options().indent()); + yamlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + yamlOptions.setWidth(10000); + yamlRepresenter.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + + + String dump = yaml.dump(getValues(false)); + + + if (dump.equals(BLANK_CONFIG)) { + dump = ""; + } + + return dump; + } +} \ No newline at end of file diff --git a/1.19.2/src/main/java/me/doclic/noencryption/utils/FileMgmt.java b/1.19.2/src/main/java/me/doclic/noencryption/utils/FileMgmt.java new file mode 100644 index 0000000..8b6c8ca --- /dev/null +++ b/1.19.2/src/main/java/me/doclic/noencryption/utils/FileMgmt.java @@ -0,0 +1,93 @@ +package me.doclic.noencryption.utils; + +import me.doclic.noencryption.NoEncryption; + +import java.io.*; +import java.util.logging.Level; + +public class FileMgmt { + private static NoEncryption main; + + public static void initialize(NoEncryption main) { + FileMgmt.main = main; + } + + public static void checkFolders(String[] folders) { + + for (String folder : folders) { + File f = new File(folder); + if (!(f.exists() && f.isDirectory())) { + f.getParentFile().mkdirs(); + f.mkdir(); + + } + } + } + + public static String fileSeparator() { + + return System.getProperty("file.separator"); + } + + public static File CheckYMLExists(File file) { + + if (!file.exists()) { + try { + file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return file; + } + + /** + * Pass a file and it will return it's contents as a string. + * + * @param file File to read. + * @return Contents of file. String will be empty in case of any errors. + */ + public static String convertFileToString(File file) { + + if (file != null && file.exists() && file.canRead() && !file.isDirectory()) { + Writer writer = new StringWriter(); + + char[] buffer = new char[1024]; + try (InputStream is = new FileInputStream(file)) { + Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); + int n; + while ((n = reader.read(buffer)) != -1) { + writer.write(buffer, 0, n); + } + reader.close(); + } catch (IOException e) { + main.getLogger().log(Level.SEVERE, "Exception: " + e.getMessage()); + } + return writer.toString(); + } else { + return ""; + } + } + + /** + * Writes the contents of a string to a file. + * + * @param source String to write. + * @param file File to write to. + * @return True on success. + * @throws IOException + */ + public static void stringToFile(String source, File file) { + + try { + + OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(file), "UTF-8"); + + out.write(source); + out.close(); + + } catch (IOException e) { + main.getLogger().log(Level.SEVERE, "Exception: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/1.19/src/main/java/me/doclic/noencryption/NoEncryption.java b/1.19/src/main/java/me/doclic/noencryption/NoEncryption.java index 9c1e3d0..4e0e696 100644 --- a/1.19/src/main/java/me/doclic/noencryption/NoEncryption.java +++ b/1.19/src/main/java/me/doclic/noencryption/NoEncryption.java @@ -1,9 +1,13 @@ package me.doclic.noencryption; import me.doclic.noencryption.compatibility.Compatibility; +import me.doclic.noencryption.config.ConfigurationHandler; +import me.doclic.noencryption.utils.FileMgmt; import org.bukkit.Bukkit; import org.bukkit.plugin.java.JavaPlugin; +import java.util.logging.Level; + public final class NoEncryption extends JavaPlugin { @Override @@ -11,6 +15,17 @@ public void onEnable() { if (Compatibility.SERVER_COMPATIBLE) { + FileMgmt.initialize(this); + ConfigurationHandler.initialize(this); + + if (!ConfigurationHandler.loadSettings()) { + getLogger().severe("Configuration could not be loaded, disabling..."); + Bukkit.getPluginManager().disablePlugin(this); + return; + } + + ConfigurationHandler.printChanges(); + Bukkit.getPluginManager().registerEvents(new PlayerListener(), this); getLogger().info("Compatibility successful!"); @@ -27,4 +42,8 @@ public void onEnable() { } } + + public String getRootFolder() { + return this.getDataFolder().getPath(); + } } diff --git a/1.19/src/main/java/me/doclic/noencryption/config/ConfigNodes.java b/1.19/src/main/java/me/doclic/noencryption/config/ConfigNodes.java new file mode 100644 index 0000000..9b50c88 --- /dev/null +++ b/1.19/src/main/java/me/doclic/noencryption/config/ConfigNodes.java @@ -0,0 +1,102 @@ +package me.doclic.noencryption.config; + +public enum ConfigNodes { + HEADER(null, "fun", "", + " ", + "# |==========================================================|", + "# | |", + "# | NoEncryption Dynamic Configuration |", + "# | By Doclic and V1nc3ntWasTaken |", + "# | |", + "# | This is a dynamic configuration file that will be |", + "# | automatically updated when you update the plugin, |", + "# | although any new features will be disabled by default, |", + "# | and you will receive a one-time notification about |", + "# | any added config options in the console upon startup. |", + "# | |", + "# | -------------------------------------- |", + "# | |", + "# | Config entries will look like the following: |", + "# | |", + "# | friends: |", + "# | |", + "# | # Allows a user to become friends with the devs |", + "# | # |", + "# | # Note: Doesn't actually do anything, just here |", + "# | # for show, and example. |", + "# | # |", + "# | # Added in v3.0 |", + "# | # Default: false |", + "# | friendly-dev: false |", + "# | |", + "# |==========================================================|", + " "), + FRIENDLY_DEV("Test notice", "fun.friendly_dev", false, + " ", + "# Allows a user to become friends with the devs", + "# ", + "# Note: Doesn't actually do anything, just here", + "# for show, and example", + "# Added in v3.0", + "# Default: false"); + + + private final String Notice; + private final String Root; + private final Object Default; + private String[] comments; + + ConfigNodes(String notice, String root, Object def, String... comments) { + + this.Notice = notice; + this.Root = root; + this.Default = def; + this.comments = comments; + } + + /** + * Retrieves the root for a config option + * + * @return The root for a config option + */ + public String getNotice() { + + return (Notice != null ? Notice.trim() : null); + } + + /** + * Retrieves the root for a config option + * + * @return The root for a config option + */ + public String getRoot() { + + return Root; + } + + /** + * Retrieves the default value for a config path + * + * @return The default value for a config path + */ + public Object getDefault() { + + return Default; + } + + /** + * Retrieves the comment for a config path + * + * @return The comments for a config path + */ + public String[] getComments() { + + if (comments != null) { + return comments; + } + + String[] comments = new String[1]; + comments[0] = ""; + return comments; + } +} \ No newline at end of file diff --git a/1.19/src/main/java/me/doclic/noencryption/config/ConfigurationHandler.java b/1.19/src/main/java/me/doclic/noencryption/config/ConfigurationHandler.java new file mode 100644 index 0000000..5f3528a --- /dev/null +++ b/1.19/src/main/java/me/doclic/noencryption/config/ConfigurationHandler.java @@ -0,0 +1,228 @@ +package me.doclic.noencryption.config; + +import me.doclic.noencryption.NoEncryption; +import me.doclic.noencryption.utils.CommentedConfiguration; +import me.doclic.noencryption.utils.FileMgmt; + +import java.io.File; +import java.util.HashMap; +import java.util.logging.Level; + +public class ConfigurationHandler { + private static NoEncryption main; + private static CommentedConfiguration config, newConfig; + private static HashMap newOptions; + private static HashMap messages; + + public static void initialize(NoEncryption main) { + ConfigurationHandler.main = main; + newOptions = new HashMap<>(); + messages = new HashMap<>(); + } + + public static boolean loadSettings() { + FileMgmt.checkFolders(new String[]{ + main.getRootFolder(), + main.getRootFolder() + FileMgmt.fileSeparator() + "settings"}); + + return ConfigurationHandler.loadConfig(); + } + + private static boolean loadConfig() { + String filepath = main.getRootFolder() + FileMgmt.fileSeparator() + "settings" + FileMgmt.fileSeparator() + "config.yml"; + + File file = FileMgmt.CheckYMLExists(new File(filepath)); + if (file != null) { + + // read the config.yml into memory + config = new CommentedConfiguration(file); + if (!config.load()) { + main.getLogger().log(Level.SEVERE, "Failed to load config.yml"); + return false; + } + + setDefaults(file); + + config.save(); + } + return true; + } + + /** + * Builds a new config reading old config data. + */ + private static void setDefaults(File file) { + + newConfig = new CommentedConfiguration(file); + newConfig.load(); + + for (ConfigNodes root : ConfigNodes.values()) { + if (root.getComments().length > 0) { + addComment(root.getRoot(), root.getComments()); + } + + setNewProperty(root.getRoot(), (config.get(root.getRoot().toLowerCase()) != null) ? config.get(root.getRoot().toLowerCase()) : root.getDefault()); + + if (config != null && !config.getKeys(true).contains(root.getRoot()) && !root.getDefault().equals("")) { + newOptions.put(root.getRoot(), root.getDefault()); + } + + if (root.getNotice() != null) { + messages.put(root.getRoot(), root.getNotice()); + } + + } + + config = newConfig; + newConfig = null; + } + + /** + * Prints any new config options to the config + */ + public static void printChanges() { + + main.getLogger().log(Level.INFO, "Checking for new config option..."); + if (!newOptions.isEmpty()) { + + newOptions.forEach((root, def) -> main.getLogger().log(Level.INFO, " " + root + ": " + def)); + } else { + main.getLogger().log(Level.INFO, "No new config options detected"); + } + + main.getLogger().log(Level.INFO, "Checking for important messages..."); + if (!messages.isEmpty()) { + + messages.forEach((root, msg) -> main.getLogger().log(Level.WARNING, " " + root + ": \"" + msg + "\"")); + } else { + main.getLogger().log(Level.INFO, "No important messages detected"); + } + } + + private static void addComment(String root, String... comments) { + + newConfig.addComment(root.toLowerCase(), comments); + } + + private static void setProperty(String root, Object value) { + + config.set(root.toLowerCase(), value.toString()); + } + + private static void setNewProperty(String root, Object value) { + + if (value == null) { + // System.out.print("value is null for " + root.toLowerCase()); + value = ""; + } + newConfig.set(root.toLowerCase(), value.toString()); + } + + + /** + * Get's a value for a ConfigNode + * + * @param node - ConfigNode + * @return - Value for node + */ + private static String getString(ConfigNodes node) { + + return config.getString(node.getRoot().toLowerCase(), String.valueOf(node.getDefault())); + + } + + /** + * Get's a value for a ConfigNode + * + * @param node - ConfigNode + * @return - Value for node (specifically boolean) + */ + private static boolean getBoolean(ConfigNodes node) { + + return config.getBoolean(node.getRoot().toLowerCase(), Boolean.parseBoolean(String.valueOf(node.getDefault()))); + } + + /** + * Get's a value for a ConfigNode + * + * @param node - ConfigNode + * @return - Value for node (specifically double) + */ + private static double getDouble(ConfigNodes node) { + + try { + return config.getDouble(node.getRoot().toLowerCase(), Double.parseDouble(String.valueOf(node.getDefault()))); + } catch (NumberFormatException e) { + main.getLogger().log(Level.SEVERE, "Could not get/read double for value: " + node.getRoot().toLowerCase()); + return 0.0; + } + } + + /** + * Get's a value for a ConfigNode + * + * @param node - ConfigNode + * @return - Value for node (specifically int) + */ + private static int getInt(ConfigNodes node) { + + try { + return config.getInt(node.getRoot().toLowerCase(), Integer.parseInt(String.valueOf(node.getDefault()))); + } catch (NumberFormatException e) { + main.getLogger().log(Level.SEVERE, "Could not get/read int for value: " + node.getRoot().toLowerCase()); + return 0; + } + } + + /* public static String getDBTablePrefix() { + return getString(ConfigNodes.DATABASE_TABLE_PREFIX); + } + + public static String getLoadDBType() { + return getString(ConfigNodes.DATABASE_LOAD_TYPE).toLowerCase(); + } + + public static String getLoadDBHostname() { + return getString(ConfigNodes.DATABASE_LOAD_HOSTNAME); + } + + public static String getLoadDBPort() { + return getString(ConfigNodes.DATABASE_LOAD_PORT); + } + + public static String getLoadDBSchemaName() { + return getString(ConfigNodes.DATABASE_LOAD_SCHEMA_NAME); + } + + public static String getLoadDBUsername() { + return getString(ConfigNodes.DATABASE_LOAD_USERNAME); + } + + public static String getLoadDBPassword() { + return getString(ConfigNodes.DATABASE_LOAD_PASSWORD); + } + + public static String getSaveDBType() { + return getString(ConfigNodes.DATABASE_SAVE_TYPE).toLowerCase(); + } + + public static String getSaveDBHostname() { + return getString(ConfigNodes.DATABASE_SAVE_HOSTNAME); + } + + public static String getSaveDBPort() { + return getString(ConfigNodes.DATABASE_SAVE_PORT); + } + + public static String getSaveDBSchemaName() { + return getString(ConfigNodes.DATABASE_SAVE_SCHEMA_NAME); + } + + public static String getSaveDBUsername() { + return getString(ConfigNodes.DATABASE_SAVE_USERNAME); + } + + public static String getSaveDBPassword() { + return getString(ConfigNodes.DATABASE_SAVE_PASSWORD); + }*/ +} \ No newline at end of file diff --git a/1.19/src/main/java/me/doclic/noencryption/utils/CommentedConfiguration.java b/1.19/src/main/java/me/doclic/noencryption/utils/CommentedConfiguration.java new file mode 100644 index 0000000..8035db3 --- /dev/null +++ b/1.19/src/main/java/me/doclic/noencryption/utils/CommentedConfiguration.java @@ -0,0 +1,239 @@ +package me.doclic.noencryption.utils; + +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import org.apache.commons.lang.Validate; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.configuration.file.YamlConstructor; +import org.bukkit.configuration.file.YamlRepresenter; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.representer.Representer; + +import java.io.*; +import java.util.HashMap; + +/** + * @author dumptruckman, LlmDL & Articdive + */ +public class CommentedConfiguration extends YamlConfiguration { + + private final DumperOptions yamlOptions = new DumperOptions(); + private final Representer yamlRepresenter = new YamlRepresenter(); + private final Yaml yaml = new Yaml(new YamlConstructor(), yamlRepresenter, yamlOptions); + private HashMap comments; + private File file; + + public CommentedConfiguration(File file) { + + super(); + //this.load(file); + comments = new HashMap<>(); + this.file = file; + } + + public boolean load() { + + boolean loaded = true; + + try { + this.load(file); + } catch (InvalidConfigurationException | IOException e) { + loaded = false; + } + + return loaded; + } + + public void save() { + + boolean saved = true; + + // Save the config just like normal + try { + /* + * Doing some saving of our own. We have found that the implementation of YAMLComfiguration used by Bukkit will attempt to + * cap strings at 80 characters long, forming new lines in some of our longer strings (channel_formats.) + */ + this.save(file); + + } catch (Exception e) { + saved = false; + } + + // if there's comments to add and it saved fine, we need to add comments + if (!comments.isEmpty() && saved) { + // String array of each line in the config file + String[] yamlContents = FileMgmt.convertFileToString(file).split("[" + System.getProperty("line.separator") + "]"); + + // This will hold the newly formatted line + StringBuilder newContents = new StringBuilder(); + // This holds the current path the lines are at in the config + String currentPath = ""; + // This flags if the line is a node or unknown text. + boolean node; + // The depth of the path. (number of words separated by periods - 1) + int depth = 0; + + // Loop through the config lines + for (String line : yamlContents) { + // If the line is a node (and not something like a list value) + if (line.contains(": ") || (line.length() > 1 && line.charAt(line.length() - 1) == ':')) { + // This is a node so flag it as one + node = true; + + // Grab the index of the end of the node name + int index; + index = line.indexOf(": "); + if (index < 0) { + index = line.length() - 1; + } + // If currentPath is empty, store the node name as the currentPath. (this is only on the first iteration, i think) + if (currentPath.isEmpty()) { + currentPath = line.substring(0, index); + } else { + // Calculate the whitespace preceding the node name + int whiteSpace = 0; + for (int n = 0; n < line.length(); n++) { + if (line.charAt(n) == ' ') { + whiteSpace++; + } else { + break; + } + } + // Find out if the current depth (whitespace * 2) is greater/lesser/equal to the previous depth + if (whiteSpace / 2 > depth) { + // Path is deeper. Add a . and the node name + currentPath += "." + line.substring(whiteSpace, index); + depth++; + } else if (whiteSpace / 2 < depth) { + // Path is shallower, calculate current depth from whitespace (whitespace / 2) and subtract that many levels from the currentPath + int newDepth = whiteSpace / 2; + for (int i = 0; i < depth - newDepth; i++) { + currentPath = currentPath.replace(currentPath.substring(currentPath.lastIndexOf(".")), ""); + } + // Grab the index of the final period + int lastIndex = currentPath.lastIndexOf("."); + if (lastIndex < 0) { + // if there isn't a final period, set the current path to nothing because we're at root + currentPath = ""; + } else { + // If there is a final period, replace everything after it with nothing + currentPath = currentPath.replace(currentPath.substring(currentPath.lastIndexOf(".")), ""); + currentPath += "."; + } + // Add the new node name to the path + currentPath += line.substring(whiteSpace, index); + // Reset the depth + depth = newDepth; + } else { + // Path is same depth, replace the last path node name to the current node name + int lastIndex = currentPath.lastIndexOf("."); + if (lastIndex < 0) { + // if there isn't a final period, set the current path to nothing because we're at root + currentPath = ""; + } else { + // If there is a final period, replace everything after it with nothing + currentPath = currentPath.replace(currentPath.substring(currentPath.lastIndexOf(".")), ""); + currentPath += "."; + } + //currentPath = currentPath.replace(currentPath.substring(currentPath.lastIndexOf(".")), ""); + currentPath += line.substring(whiteSpace, index); + + } + + } + + } else + node = false; + + if (node) { + String comment; + // If there's a comment for the current path, retrieve it and flag that path as already commented + comment = comments.get(currentPath); + if (comment != null) { + // Add the comment to the beginning of the current line + line = comment + System.getProperty("line.separator") + line + System.getProperty("line.separator"); + } else { + // Add a new line as it is a node, but has no comment + line += System.getProperty("line.separator"); + } + } + // Add the (modified) line to the total config String + newContents.append(line).append((!node) ? System.getProperty("line.separator") : ""); + + } + /* + * Due to a bukkit bug we need to strip any extra new lines from the + * beginning of this file, else they will multiply. + */ + while (newContents.toString().startsWith(System.getProperty("line.separator"))) + newContents = new StringBuilder(newContents.toString().replaceFirst(System.getProperty("line.separator"), "")); + + // Write the string to the config file + FileMgmt.stringToFile(newContents.toString(), file); + } + } + + /** + * Adds a comment just before the specified path. The comment can be + * multiple lines. An empty string will indicate a blank line. + * + * @param path Configuration path to add comment. + * @param commentLines Comments to add. One String per line. + */ + public void addComment(String path, String... commentLines) { + + StringBuilder commentstring = new StringBuilder(); + StringBuilder leadingSpaces = new StringBuilder(); + for (int n = 0; n < path.length(); n++) { + if (path.charAt(n) == '.') { + leadingSpaces.append(" "); + } + } + for (String line : commentLines) { + if (!line.isEmpty()) { + line = leadingSpaces + line; + } else { + line = ""; + } + if (commentstring.length() > 0) { + commentstring.append(System.getProperty("line.separator")); + } + commentstring.append(line); + } + comments.put(path, commentstring.toString()); + } + + + public void save(File file) throws IOException { + Validate.notNull(file, "File cannot be null"); + + Files.createParentDirs(file); + + String data = this.saveToString(); + + try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), Charsets.UTF_8)) { + writer.write(data); + } + } + + @Override + public String saveToString() { + yamlOptions.setIndent(options().indent()); + yamlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + yamlOptions.setWidth(10000); + yamlRepresenter.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + + + String dump = yaml.dump(getValues(false)); + + + if (dump.equals(BLANK_CONFIG)) { + dump = ""; + } + + return dump; + } +} \ No newline at end of file diff --git a/1.19/src/main/java/me/doclic/noencryption/utils/FileMgmt.java b/1.19/src/main/java/me/doclic/noencryption/utils/FileMgmt.java new file mode 100644 index 0000000..8b6c8ca --- /dev/null +++ b/1.19/src/main/java/me/doclic/noencryption/utils/FileMgmt.java @@ -0,0 +1,93 @@ +package me.doclic.noencryption.utils; + +import me.doclic.noencryption.NoEncryption; + +import java.io.*; +import java.util.logging.Level; + +public class FileMgmt { + private static NoEncryption main; + + public static void initialize(NoEncryption main) { + FileMgmt.main = main; + } + + public static void checkFolders(String[] folders) { + + for (String folder : folders) { + File f = new File(folder); + if (!(f.exists() && f.isDirectory())) { + f.getParentFile().mkdirs(); + f.mkdir(); + + } + } + } + + public static String fileSeparator() { + + return System.getProperty("file.separator"); + } + + public static File CheckYMLExists(File file) { + + if (!file.exists()) { + try { + file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return file; + } + + /** + * Pass a file and it will return it's contents as a string. + * + * @param file File to read. + * @return Contents of file. String will be empty in case of any errors. + */ + public static String convertFileToString(File file) { + + if (file != null && file.exists() && file.canRead() && !file.isDirectory()) { + Writer writer = new StringWriter(); + + char[] buffer = new char[1024]; + try (InputStream is = new FileInputStream(file)) { + Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); + int n; + while ((n = reader.read(buffer)) != -1) { + writer.write(buffer, 0, n); + } + reader.close(); + } catch (IOException e) { + main.getLogger().log(Level.SEVERE, "Exception: " + e.getMessage()); + } + return writer.toString(); + } else { + return ""; + } + } + + /** + * Writes the contents of a string to a file. + * + * @param source String to write. + * @param file File to write to. + * @return True on success. + * @throws IOException + */ + public static void stringToFile(String source, File file) { + + try { + + OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(file), "UTF-8"); + + out.write(source); + out.close(); + + } catch (IOException e) { + main.getLogger().log(Level.SEVERE, "Exception: " + e.getMessage()); + } + } +} \ No newline at end of file