Last active
March 9, 2024 16:02
-
-
Save Magnum97/65aa169a3073d43b4aa3a3c326eade79 to your computer and use it in GitHub Desktop.
Config manager for Bukkit / Spigot Minecraft plugins. Allows easy & attractive header, comments add & preserve on change and automatically updated the config with resource file if key does not exist.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Base with comment and header features created by Log-out | |
* https://bukkit.org/threads/tut-custom-yaml-configurations-with-comments.142592/ | |
* Updated by Magnum1997 to auto update config files from resources | |
*/ | |
import org.bukkit.configuration.ConfigurationSection; | |
import org.bukkit.configuration.file.FileConfiguration; | |
import org.bukkit.configuration.file.YamlConfiguration; | |
import org.bukkit.plugin.java.JavaPlugin; | |
import org.mineacademy.fo.Common; | |
import java.io.File; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.io.InputStreamReader; | |
import java.nio.charset.StandardCharsets; | |
import java.nio.file.Files; | |
import java.nio.file.Paths; | |
import java.nio.file.StandardCopyOption; | |
import java.util.HashSet; | |
import java.util.List; | |
import java.util.Objects; | |
import java.util.Set; | |
public class SimpleConfig extends YamlConfiguration { | |
private JavaPlugin plugin; | |
private int comments; | |
private SimpleConfigManager manager; | |
private File file; | |
private FileConfiguration config; | |
private boolean useDefaults; | |
private YamlConfiguration defaults; | |
public SimpleConfig (InputStreamReader configStream, File configFile, int comments, boolean useDefaults, JavaPlugin plugin) { | |
this.plugin = plugin; | |
this.comments = comments; | |
this.manager = new SimpleConfigManager(plugin); | |
this.file = configFile; | |
this.config = YamlConfiguration.loadConfiguration(configStream); | |
this.useDefaults = useDefaults; | |
if (useDefaults) { | |
this.defaults = YamlConfiguration.loadConfiguration(new InputStreamReader(SimpleConfig.class.getResourceAsStream("/" + file.getName()), StandardCharsets.UTF_8)); | |
Objects.requireNonNull(defaults, "Could not find the default " + file.getName() + " in jar file."); | |
} | |
else | |
this.defaults = null; | |
this.file = extract(file.getName()); | |
} | |
// Extract the file from your jar to the plugins/YourPlugin folder. | |
// Does nothing if the file exists | |
private File extract (String fileName) { | |
File file = new File(plugin.getDataFolder(), fileName); | |
if (file.exists()) | |
return file; | |
createPath(fileName); | |
if (defaults != null) | |
try (InputStream inputStream = plugin.getResource(fileName)) { | |
Objects.requireNonNull(inputStream, "File not found in archive: +" + fileName); | |
Files.copy(inputStream, Paths.get(file.toURI()), StandardCopyOption.REPLACE_EXISTING); | |
} | |
catch (final IOException e) { | |
e.printStackTrace(); | |
} | |
return file; | |
} | |
private File createPath (String fileName) { | |
final File datafolder = plugin.getDataFolder(); | |
final int lastIndex = fileName.lastIndexOf("/"); | |
final File directory = new File(datafolder, fileName.substring(0, Math.max(lastIndex, 0))); | |
directory.mkdirs(); | |
final File destination = new File(datafolder, fileName); | |
try { | |
destination.createNewFile(); | |
} | |
catch (IOException e) { | |
e.printStackTrace(); | |
System.out.println("File creation failed: " + fileName); | |
} | |
return destination; | |
} | |
public Object get (String path) { | |
return get(path, null); | |
} | |
/** | |
* Gets an unspecified value from your file, so you must cast it to your desired value (example: (boolean) get("disable.this.feature", true)) | |
* The "def" is the default value, must be null since we use default values from your file in your .jar. | |
*/ | |
@Override | |
public Object get (String path, Object def) { | |
if (defaults != null) { | |
if (def != null && ! def.getClass().isPrimitive() && ! PrimitiveWrapper.isWrapperType(def.getClass())) | |
throw new IllegalArgumentException("The default value must be null since we use defaults from file inside of the plugin! Path: " + path + ", default called: " + def); | |
if (super.get(path, null) == null) { | |
final Object defaultValue = defaults.get(path); | |
Objects.requireNonNull(defaultValue, "Default " + file.getName() + " in your .jar lacks a key at '" + path + "' path"); | |
Common.log("&fUpdating &a" + file.getName() + "&f. Set '&b" + path + "&f' to '" + defaultValue + "'"); | |
set(path, defaultValue); | |
saveConfig(); | |
reloadConfig(); | |
} | |
} | |
/* | |
// prevent infinite loop due to how get works in the parent class | |
final String m = new Throwable().getStackTrace()[1].getMethodName(); | |
// Add path prefix, but only when the default file doesn't exist | |
if (defaults == null && pathPrefix != null && !m.equals("getConfigurationSection") && !m.equals("get")) | |
path = pathPrefix + "." + path; | |
*/ | |
// return super.get(path, null); | |
return this.config.get(path, null); | |
} | |
public String getString (String path) { | |
return this.config.getString(path); | |
} | |
public String getString (String path, String def) { | |
return this.config.getString(path, def); | |
} | |
public int getInt (String path) { | |
return this.config.getInt(path); | |
} | |
public int getInt (String path, int def) { | |
return this.config.getInt(path, def); | |
} | |
public boolean getBoolean (String path) { | |
return this.config.getBoolean(path); | |
} | |
public boolean getBoolean (String path, boolean def) { | |
return this.config.getBoolean(path, def); | |
} | |
/* | |
public void createSection (String path) { | |
this.config.createSection(path); | |
} | |
*/ | |
public ConfigurationSection getConfigurationSection (String path) { | |
return this.config.getConfigurationSection(path); | |
} | |
public double getDouble (String path) { | |
return this.config.getDouble(path); | |
} | |
public double getDouble (String path, double def) { | |
return this.config.getDouble(path, def); | |
} | |
public List <?> getList (String path) { | |
return this.config.getList(path); | |
} | |
public List <?> getList (String path, List <?> def) { | |
return this.config.getList(path, def); | |
} | |
public boolean contains (String path) { | |
return this.config.contains(path); | |
} | |
public void removeKey (String path) { | |
this.config.set(path, null); | |
} | |
public void set (String path, Object value) { | |
this.config.set(path, value); | |
} | |
public void set (String path, Object value, String comment) { | |
if (! this.config.contains(path)) { | |
this.config.set(manager.getPluginName() + "_COMMENT_" + comments, " " + comment); | |
comments++; | |
} | |
this.config.set(path, value); | |
} | |
public void set (String path, Object value, String[] comment) { | |
for (String comm : comment) { | |
if (! this.config.contains(path)) { | |
this.config.set(manager.getPluginName() + "_COMMENT_" + comments, " " + comm); | |
comments++; | |
} | |
} | |
this.config.set(path, value); | |
} | |
public void setHeader (String[] header) { | |
manager.setHeader(this.file, header); | |
this.comments = header.length + 2; | |
this.reloadConfig(); | |
} | |
public void reloadConfig () { | |
this.config = YamlConfiguration.loadConfiguration(manager.getConfigContent(file)); | |
} | |
public void saveConfig () { | |
String config = this.config.saveToString(); | |
manager.saveConfig(config, this.file); | |
} | |
public Set <String> getKeys () { | |
return this.config.getKeys(false); | |
} | |
// A helper class | |
private static final class PrimitiveWrapper { | |
private static final Set <Class <?>> WRAPPER_TYPES = getWrapperTypes(); | |
private static boolean isWrapperType (Class <?> clazz) { | |
return WRAPPER_TYPES.contains(clazz); | |
} | |
private static Set <Class <?>> getWrapperTypes () { | |
final Set <Class <?>> ret = new HashSet <>(); | |
ret.add(Boolean.class); | |
ret.add(Character.class); | |
ret.add(Byte.class); | |
ret.add(Short.class); | |
ret.add(Integer.class); | |
ret.add(Long.class); | |
ret.add(Float.class); | |
ret.add(Double.class); | |
ret.add(Void.class); | |
return ret; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Base with comment and header features created by Log-out | |
* https://bukkit.org/threads/tut-custom-yaml-configurations-with-comments.142592/ | |
* Updated by Magnum1997 to auto update config files from resources | |
*/ | |
import org.bukkit.plugin.java.JavaPlugin; | |
import java.io.*; | |
import java.nio.charset.Charset; | |
public class SimpleConfigManager { | |
private JavaPlugin plugin; | |
/** | |
* Manage custom configurations and files | |
*/ | |
public SimpleConfigManager (JavaPlugin plugin) { | |
this.plugin = plugin; | |
} | |
/** | |
* Get new configuration with header | |
* | |
* @param filePath - Path to file | |
* @return - New SimpleConfig | |
*/ | |
public SimpleConfig getNewConfig (String filePath, String[] header,boolean useDefaults) { | |
File file = this.getConfigFile(filePath); | |
if (! file.exists()) { | |
this.prepareFile(filePath); | |
if (header != null && header.length != 0) { | |
this.setHeader(file, header); | |
} | |
} | |
SimpleConfig config = new SimpleConfig(this.getConfigContent(filePath), file, this.getCommentsNum(file), useDefaults,plugin); | |
return config; | |
} | |
/** | |
* Get new configuration. | |
* <p>It will be blank unless (@link useDefaults) is true | |
* <b>and</b> include it in resources.</p> | |
* | |
* @param filePath - Path to file | |
* @return - New SimpleConfig | |
*/ | |
public SimpleConfig getNewConfig (String filePath) { | |
return this.getNewConfig(filePath, null,false); | |
} | |
/** | |
* Get configuration file from string | |
* | |
* @param file - File path | |
* @return - New file object | |
*/ | |
private File getConfigFile (String file) { | |
if (file == null || file.isEmpty()) { | |
return null; | |
} | |
File configFile; | |
if (file.contains("/")) { | |
if (file.startsWith("/")) { | |
configFile = new File(plugin.getDataFolder() + file.replace("/", File.separator)); | |
} | |
else { | |
configFile = new File(plugin.getDataFolder() + File.separator + file.replace("/", File.separator)); | |
} | |
} | |
else { | |
configFile = new File(plugin.getDataFolder(), file); | |
} | |
return configFile; | |
} | |
/** | |
* Create new file for config and copy resource into it | |
* | |
* @param filePath - Path to file | |
* @param resource - Resource to copy | |
*/ | |
public void prepareFile (String filePath, String resource) { | |
File file = this.getConfigFile(filePath); | |
if (file.exists()) { | |
return; | |
} | |
try { | |
file.getParentFile().mkdirs(); | |
file.createNewFile(); | |
if (resource != null && ! resource.isEmpty()) { | |
this.copyResource(plugin.getResource(resource), file); | |
} | |
} | |
catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
/** | |
* Create new file for config without resource | |
* | |
* @param filePath - File to create | |
*/ | |
public void prepareFile (String filePath) { | |
this.prepareFile(filePath, null); | |
} | |
/** | |
* Adds header block to config | |
* | |
* @param file - Config file | |
* @param header - Header lines | |
*/ | |
public void setHeader (File file, String[] header) { | |
if (! file.exists()) { | |
return; | |
} | |
try { | |
String currentLine; | |
StringBuilder config = new StringBuilder(""); | |
BufferedReader reader = new BufferedReader(new FileReader(file)); | |
while ((currentLine = reader.readLine()) != null) { | |
config.append(currentLine + "\n"); | |
} | |
reader.close(); | |
config.append("# +----------------------------------------------------+ #\n"); | |
for (String line : header) { | |
if (line.length() > 50) { | |
continue; | |
} | |
int lenght = (50 - line.length()) / 2; | |
StringBuilder finalLine = new StringBuilder(line); | |
for (int i = 0; i < lenght; i++) { | |
finalLine.append(" "); | |
finalLine.reverse(); | |
finalLine.append(" "); | |
finalLine.reverse(); | |
} | |
if (line.length() % 2 != 0) { | |
finalLine.append(" "); | |
} | |
config.append("# < " + finalLine.toString() + " > #\n"); | |
} | |
config.append("# +----------------------------------------------------+ #"); | |
BufferedWriter writer = new BufferedWriter(new FileWriter(file)); | |
writer.write(this.prepareConfigString(config.toString())); | |
writer.flush(); | |
writer.close(); | |
} | |
catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
/** | |
* Read file and make comments SnakeYAML friendly | |
* | |
* @param file - Path to file | |
* @return - File as Input Stream | |
*/ | |
public InputStreamReader getConfigContent (File file) { | |
if (! file.exists()) { | |
return null; | |
} | |
try { | |
int commentNum = 0; | |
String addLine; | |
String currentLine; | |
String pluginName = this.getPluginName(); | |
StringBuilder whole = new StringBuilder(""); | |
BufferedReader reader = new BufferedReader(new FileReader(file)); | |
while ((currentLine = reader.readLine()) != null) { | |
if (currentLine.startsWith("#")) { | |
addLine = currentLine.replaceFirst("#", pluginName + "_COMMENT_" + commentNum + ":"); | |
whole.append(addLine + "\n"); | |
commentNum++; | |
} | |
else { | |
whole.append(currentLine + "\n"); | |
} | |
} | |
String config = whole.toString(); | |
InputStream configStream = new ByteArrayInputStream(config.getBytes(Charset.forName("UTF-8"))); | |
InputStreamReader configStreamReader = new InputStreamReader(configStream); | |
reader.close(); | |
return configStreamReader; | |
} | |
catch (IOException e) { | |
e.printStackTrace(); | |
return null; | |
} | |
} | |
/** | |
* Get comments from file | |
* | |
* @param file - File | |
* @return - Comments number | |
*/ | |
private int getCommentsNum (File file) { | |
if (! file.exists()) { | |
return 0; | |
} | |
try { | |
int comments = 0; | |
String currentLine; | |
BufferedReader reader = new BufferedReader(new FileReader(file)); | |
while ((currentLine = reader.readLine()) != null) { | |
if (currentLine.startsWith("#")) { | |
comments++; | |
} | |
} | |
reader.close(); | |
return comments; | |
} | |
catch (IOException e) { | |
e.printStackTrace(); | |
return 0; | |
} | |
} | |
/** | |
* Get config content from file | |
* | |
* @param filePath - Path to file | |
* @return - readied file | |
*/ | |
public InputStreamReader getConfigContent (String filePath) { | |
return this.getConfigContent(this.getConfigFile(filePath)); | |
} | |
private String prepareConfigString (String configString) { | |
int lastLine = 0; | |
int headerLine = 0; | |
String[] lines = configString.split("\n"); | |
StringBuilder config = new StringBuilder(""); | |
for (String line : lines) { | |
if (line.startsWith(this.getPluginName() + "_COMMENT")) { | |
String comment = "#" + line.trim().substring(line.indexOf(":") + 1); | |
if (comment.startsWith("# +-")) { | |
/* | |
* If header line = 0 then it is | |
* header start, if it's equal | |
* to 1 it's the end of header | |
*/ | |
if (headerLine == 0) { | |
config.append(comment + "\n"); | |
lastLine = 0; | |
headerLine = 1; | |
} | |
else if (headerLine == 1) { | |
config.append(comment + "\n\n"); | |
lastLine = 0; | |
headerLine = 0; | |
} | |
} | |
else { | |
/* | |
* Last line = 0 - Comment | |
* Last line = 1 - Normal path | |
*/ | |
String normalComment; | |
if (comment.startsWith("# ' ")) { | |
normalComment = comment.substring(0, comment.length() - 1).replaceFirst("# ' ", "# "); | |
} | |
else { | |
normalComment = comment; | |
} | |
if (lastLine == 0) { | |
config.append(normalComment + "\n"); | |
} | |
else if (lastLine == 1) { | |
config.append("\n" + normalComment + "\n"); | |
} | |
lastLine = 0; | |
} | |
} | |
else { | |
config.append(line + "\n"); | |
lastLine = 1; | |
} | |
} | |
return config.toString(); | |
} | |
/** | |
* Saves configuration to file | |
* | |
* @param configString - Config string | |
* @param file - Config file | |
*/ | |
public void saveConfig (String configString, File file) { | |
String configuration = this.prepareConfigString(configString); | |
try { | |
BufferedWriter writer = new BufferedWriter(new FileWriter(file)); | |
writer.write(configuration); | |
writer.flush(); | |
writer.close(); | |
} | |
catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
public String getPluginName () { | |
return plugin.getDescription().getName(); | |
} | |
/** | |
* Copy resource from Input Stream to file | |
* | |
* @param resource - Resource from .jar | |
* @param file - File to write | |
*/ | |
private void copyResource (InputStream resource, File file) { | |
try { | |
OutputStream out = new FileOutputStream(file); | |
int lenght; | |
byte[] buf = new byte[1024]; | |
while ((lenght = resource.read(buf)) > 0) { | |
out.write(buf, 0, lenght); | |
} | |
out.close(); | |
resource.close(); | |
} | |
catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment