mirror of
https://github.com/filoghost/ChestCommands.git
synced 2024-11-26 03:55:40 +01:00
Large configuration refactoring
This commit is contained in:
parent
dfc060fdcd
commit
58bdf388bf
@ -17,12 +17,11 @@ package me.filoghost.chestcommands;
|
||||
import me.filoghost.chestcommands.api.internal.BackendAPI;
|
||||
import me.filoghost.chestcommands.command.CommandHandler;
|
||||
import me.filoghost.chestcommands.command.framework.CommandFramework;
|
||||
import me.filoghost.chestcommands.config.ConfigLoader;
|
||||
import me.filoghost.chestcommands.config.framework.ConfigLoader;
|
||||
import me.filoghost.chestcommands.config.ConfigManager;
|
||||
import me.filoghost.chestcommands.config.files.CustomPlaceholders;
|
||||
import me.filoghost.chestcommands.config.files.Lang;
|
||||
import me.filoghost.chestcommands.parsing.menu.LoadedMenu;
|
||||
import me.filoghost.chestcommands.config.files.Settings;
|
||||
import me.filoghost.chestcommands.config.CustomPlaceholders;
|
||||
import me.filoghost.chestcommands.config.Lang;
|
||||
import me.filoghost.chestcommands.config.Settings;
|
||||
import me.filoghost.chestcommands.hook.BarAPIHook;
|
||||
import me.filoghost.chestcommands.hook.BungeeCordHook;
|
||||
import me.filoghost.chestcommands.hook.PlaceholderAPIHook;
|
||||
@ -34,10 +33,11 @@ import me.filoghost.chestcommands.listener.InventoryListener;
|
||||
import me.filoghost.chestcommands.listener.JoinListener;
|
||||
import me.filoghost.chestcommands.listener.SignListener;
|
||||
import me.filoghost.chestcommands.menu.MenuManager;
|
||||
import me.filoghost.chestcommands.parsing.menu.LoadedMenu;
|
||||
import me.filoghost.chestcommands.task.RefreshMenusTask;
|
||||
import me.filoghost.chestcommands.util.Log;
|
||||
import me.filoghost.chestcommands.util.Utils;
|
||||
import me.filoghost.chestcommands.util.collection.ErrorCollector;
|
||||
import me.filoghost.chestcommands.util.Log;
|
||||
import me.filoghost.updatechecker.UpdateChecker;
|
||||
import org.bstats.bukkit.MetricsLite;
|
||||
import org.bukkit.Bukkit;
|
||||
@ -152,9 +152,9 @@ public class ChestCommands extends JavaPlugin {
|
||||
public ErrorCollector load() {
|
||||
ErrorCollector errors = new ErrorCollector();
|
||||
menuManager.clear();
|
||||
boolean isFreshInstall = !Files.isDirectory(configManager.getBaseDataPath());
|
||||
boolean isFreshInstall = !Files.isDirectory(configManager.getRootDataFolder());
|
||||
try {
|
||||
Files.createDirectories(configManager.getBaseDataPath());
|
||||
Files.createDirectories(configManager.getRootDataFolder());
|
||||
} catch (IOException e) {
|
||||
errors.addError("Plugin failed to load, couldn't create data folder.");
|
||||
return errors;
|
||||
@ -172,7 +172,7 @@ public class ChestCommands extends JavaPlugin {
|
||||
|
||||
// Create the menu folder with the example menu
|
||||
if (!Files.isDirectory(configManager.getMenusFolder())) {
|
||||
ConfigLoader exampleMenuLoader = new ConfigLoader(configManager.getMenusFolder().resolve("example.yml"));
|
||||
ConfigLoader exampleMenuLoader = configManager.getConfigLoader(configManager.getMenusFolder().resolve("example.yml"));
|
||||
configManager.tryCreateDefault(exampleMenuLoader);
|
||||
}
|
||||
|
||||
|
@ -1,126 +0,0 @@
|
||||
/*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config;
|
||||
|
||||
import me.filoghost.chestcommands.util.Preconditions;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
public class ConfigLoader {
|
||||
|
||||
private final Path path;
|
||||
|
||||
public ConfigLoader(Path path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public Path getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void createDefault(Path baseDataPath) throws IOException {
|
||||
if (!path.startsWith(baseDataPath)) {
|
||||
throw new IOException("Config file " + path + " must be inside " + baseDataPath);
|
||||
}
|
||||
|
||||
if (Files.exists(path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (path.getParent() != null) {
|
||||
Files.createDirectories(path.getParent());
|
||||
}
|
||||
|
||||
Path absoluteDataPath = baseDataPath.toAbsolutePath();
|
||||
Path absoluteConfigPath = path.toAbsolutePath();
|
||||
|
||||
if (absoluteConfigPath.startsWith(absoluteDataPath)) {
|
||||
Path relativeConfigPath = absoluteDataPath.relativize(absoluteConfigPath);
|
||||
String internalJarPath = toInternalJarPath(relativeConfigPath);
|
||||
|
||||
try (InputStream defaultFile = getResource(internalJarPath)) {
|
||||
if (defaultFile != null) {
|
||||
Files.copy(defaultFile, path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Files.createFile(path);
|
||||
}
|
||||
|
||||
private String toInternalJarPath(Path path) {
|
||||
return StreamSupport.stream(path.spliterator(), false)
|
||||
.map(Path::toString)
|
||||
.collect(Collectors.joining("/", "/", ""));
|
||||
}
|
||||
|
||||
|
||||
private InputStream getResource(String internalJarPath) throws IOException {
|
||||
Preconditions.notNull(internalJarPath, "internalJarPath");
|
||||
|
||||
URL resourceURL = getClass().getResource(internalJarPath);
|
||||
if (resourceURL == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
URLConnection connection = resourceURL.openConnection();
|
||||
connection.setUseCaches(false);
|
||||
return connection.getInputStream();
|
||||
}
|
||||
|
||||
|
||||
public Config load() throws IOException, InvalidConfigurationException {
|
||||
YamlConfiguration yaml = new YamlConfiguration();
|
||||
|
||||
try (BufferedReader reader = Files.newBufferedReader(path)) {
|
||||
yaml.load(reader);
|
||||
}
|
||||
|
||||
return new Config(yaml, path);
|
||||
}
|
||||
|
||||
public Config loadEmpty() {
|
||||
return new Config(new YamlConfiguration(), path);
|
||||
}
|
||||
|
||||
public void save(Config config) throws IOException {
|
||||
if (path.getParent() != null) {
|
||||
Files.createDirectories(path.getParent());
|
||||
}
|
||||
|
||||
String data = config.saveToString();
|
||||
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(path)) {
|
||||
writer.write(data);
|
||||
}
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return path.getFileName().toString();
|
||||
}
|
||||
|
||||
}
|
@ -14,14 +14,17 @@
|
||||
*/
|
||||
package me.filoghost.chestcommands.config;
|
||||
|
||||
import me.filoghost.chestcommands.config.files.CustomPlaceholders;
|
||||
import me.filoghost.chestcommands.config.files.Lang;
|
||||
import me.filoghost.chestcommands.config.framework.BaseConfigManager;
|
||||
import me.filoghost.chestcommands.config.framework.Config;
|
||||
import me.filoghost.chestcommands.config.framework.ConfigLoader;
|
||||
import me.filoghost.chestcommands.config.framework.exception.ConfigException;
|
||||
import me.filoghost.chestcommands.config.framework.exception.ConfigSyntaxException;
|
||||
import me.filoghost.chestcommands.config.framework.mapped.MappedConfigLoader;
|
||||
import me.filoghost.chestcommands.parsing.menu.LoadedMenu;
|
||||
import me.filoghost.chestcommands.config.files.Settings;
|
||||
import me.filoghost.chestcommands.parsing.menu.MenuParser;
|
||||
import me.filoghost.chestcommands.util.collection.ErrorCollector;
|
||||
import me.filoghost.chestcommands.util.Log;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import me.filoghost.chestcommands.util.Preconditions;
|
||||
import me.filoghost.chestcommands.util.collection.ErrorCollector;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileVisitOption;
|
||||
@ -33,55 +36,46 @@ import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ConfigManager {
|
||||
public class ConfigManager extends BaseConfigManager {
|
||||
|
||||
private final Path baseDataPath;
|
||||
private final ConfigLoader settingsConfigLoader;
|
||||
private final MappedConfigLoader<Settings> settingsConfigLoader;
|
||||
private final ConfigLoader placeholdersConfigLoader;
|
||||
private final ConfigLoader langConfigLoader;
|
||||
private final MappedConfigLoader<Lang> langConfigLoader;
|
||||
|
||||
public ConfigManager(Path baseDataPath) {
|
||||
this.baseDataPath = baseDataPath;
|
||||
settingsConfigLoader = new ConfigLoader(baseDataPath.resolve("config.yml"));
|
||||
placeholdersConfigLoader = new ConfigLoader(baseDataPath.resolve("custom-placeholders.yml"));
|
||||
langConfigLoader = new ConfigLoader(baseDataPath.resolve("lang.yml"));
|
||||
public ConfigManager(Path rootDataFolder) {
|
||||
super(rootDataFolder);
|
||||
|
||||
settingsConfigLoader = getMappedConfigLoader("config.yml", Settings::new);
|
||||
placeholdersConfigLoader = getConfigLoader("custom-placeholders.yml");
|
||||
langConfigLoader = getMappedConfigLoader("lang.yml", Lang::new);
|
||||
}
|
||||
|
||||
public Settings tryLoadSettings() {
|
||||
Settings settings = new Settings();
|
||||
|
||||
try {
|
||||
settingsConfigLoader.createDefault(baseDataPath);
|
||||
settings.load(settingsConfigLoader);
|
||||
} catch (Throwable t) {
|
||||
logConfigLoadException(settingsConfigLoader, t);
|
||||
return settingsConfigLoader.init();
|
||||
} catch (ConfigException e) {
|
||||
logConfigInitException(settingsConfigLoader.getFileName(), e);
|
||||
return new Settings();
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
public Lang tryLoadLang() {
|
||||
Lang lang = new Lang();
|
||||
|
||||
try {
|
||||
langConfigLoader.createDefault(baseDataPath);
|
||||
lang.load(langConfigLoader);
|
||||
} catch (Throwable t) {
|
||||
logConfigLoadException(langConfigLoader, t);
|
||||
return langConfigLoader.init();
|
||||
} catch (ConfigException e) {
|
||||
logConfigInitException(langConfigLoader.getFileName(), e);
|
||||
return new Lang();
|
||||
}
|
||||
|
||||
return lang;
|
||||
}
|
||||
|
||||
public CustomPlaceholders tryLoadCustomPlaceholders(ErrorCollector errorCollector) {
|
||||
CustomPlaceholders placeholders = new CustomPlaceholders();
|
||||
|
||||
try {
|
||||
placeholdersConfigLoader.createDefault(baseDataPath);
|
||||
Config placeholdersConfig = placeholdersConfigLoader.load();
|
||||
Config placeholdersConfig = placeholdersConfigLoader.init();
|
||||
placeholders.load(placeholdersConfig, errorCollector);
|
||||
} catch (Throwable t) {
|
||||
logConfigLoadException(placeholdersConfigLoader, t);
|
||||
} catch (ConfigException t) {
|
||||
logConfigInitException(placeholdersConfigLoader.getFileName(), t);
|
||||
}
|
||||
|
||||
return placeholders;
|
||||
@ -89,20 +83,22 @@ public class ConfigManager {
|
||||
|
||||
public void tryCreateDefault(ConfigLoader configLoader) {
|
||||
try {
|
||||
configLoader.createDefault(baseDataPath);
|
||||
} catch (Throwable t) {
|
||||
logConfigLoadException(configLoader, t);
|
||||
configLoader.createDefault();
|
||||
} catch (ConfigException e) {
|
||||
logConfigInitException(configLoader.getFileName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public Path getMenusFolder() {
|
||||
return baseDataPath.resolve("menu");
|
||||
return rootDataFolder.resolve("menu");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of YML menu files.
|
||||
*/
|
||||
public List<Path> getMenuPaths() throws IOException {
|
||||
Preconditions.checkState(Files.isDirectory(getMenusFolder()), "menus folder doesn't exist");
|
||||
|
||||
try (Stream<Path> paths = Files.walk(getMenusFolder(), FileVisitOption.FOLLOW_LINKS)) {
|
||||
return paths.filter(Files::isRegularFile)
|
||||
.filter(this::isYmlPath)
|
||||
@ -110,39 +106,15 @@ public class ConfigManager {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean isYmlPath(Path path) {
|
||||
return path.getFileName().toString().toLowerCase().endsWith(".yml");
|
||||
}
|
||||
|
||||
private void logConfigLoadException(ConfigLoader configLoader, Throwable t) {
|
||||
t.printStackTrace();
|
||||
|
||||
if (t instanceof IOException) {
|
||||
Log.warning("Error while reading the file \"" + configLoader.getFileName() + "\". Default values will be used.");
|
||||
} else if (t instanceof InvalidConfigurationException) {
|
||||
Log.warning("Invalid YAML syntax in the file \"" + configLoader.getFileName() + "\", please look at the error above. Default values will be used.");
|
||||
private void logConfigInitException(String fileName, ConfigException e) {
|
||||
if (e instanceof ConfigSyntaxException) {
|
||||
Log.warning("Invalid YAML syntax in config file \"" + fileName + "\": " + e.getMessage());
|
||||
} else {
|
||||
Log.warning("Unhandled error while parsing the file \"" + configLoader.getFileName() + "\". Please inform the developer.");
|
||||
e.printStackTrace();
|
||||
Log.warning("Error while reading config file \"" + fileName + "\": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public Path getBaseDataPath() {
|
||||
return baseDataPath;
|
||||
}
|
||||
|
||||
public ConfigLoader getSettingsConfigLoader() {
|
||||
return settingsConfigLoader;
|
||||
}
|
||||
|
||||
public ConfigLoader getPlaceholdersConfigLoader() {
|
||||
return placeholdersConfigLoader;
|
||||
}
|
||||
|
||||
public ConfigLoader getLangConfigLoader() {
|
||||
return langConfigLoader;
|
||||
}
|
||||
|
||||
public List<LoadedMenu> tryLoadMenus(ErrorCollector errorCollector) {
|
||||
List<LoadedMenu> loadedMenus = new ArrayList<>();
|
||||
List<Path> menuPaths;
|
||||
@ -155,16 +127,21 @@ public class ConfigManager {
|
||||
}
|
||||
|
||||
for (Path menuFile : menuPaths) {
|
||||
ConfigLoader menuConfigLoader = new ConfigLoader(menuFile);
|
||||
ConfigLoader menuConfigLoader = new ConfigLoader(rootDataFolder, menuFile);
|
||||
|
||||
try {
|
||||
Config menuConfig = menuConfigLoader.load();
|
||||
loadedMenus.add(MenuParser.loadMenu(menuConfig, errorCollector));
|
||||
} catch (Throwable t) {
|
||||
logConfigLoadException(menuConfigLoader, t);
|
||||
} catch (ConfigException e) {
|
||||
logConfigInitException(menuConfigLoader.getFileName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
return loadedMenus;
|
||||
}
|
||||
|
||||
private boolean isYmlPath(Path path) {
|
||||
return path.getFileName().toString().toLowerCase().endsWith(".yml");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,9 +0,0 @@
|
||||
package me.filoghost.chestcommands.config;
|
||||
|
||||
public class ConfigValueException extends Exception {
|
||||
|
||||
public ConfigValueException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
@ -12,12 +12,12 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config.files;
|
||||
package me.filoghost.chestcommands.config;
|
||||
|
||||
import me.filoghost.chestcommands.config.Config;
|
||||
import me.filoghost.chestcommands.util.collection.ErrorCollector;
|
||||
import me.filoghost.chestcommands.config.framework.Config;
|
||||
import me.filoghost.chestcommands.util.Colors;
|
||||
import me.filoghost.chestcommands.util.collection.CollectionUtils;
|
||||
import me.filoghost.chestcommands.util.collection.ErrorCollector;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -36,12 +36,12 @@ public class CustomPlaceholders {
|
||||
String replacement = Colors.addColors(config.getString(key));
|
||||
|
||||
if (placeholder.length() == 0) {
|
||||
errorCollector.addError("Error in " + config.getFileName() + ": placeholder cannot be empty (skipped).");
|
||||
errorCollector.addError("Error in " + config.getSourceFileName() + ": placeholder cannot be empty (skipped).");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (placeholder.length() > 100) {
|
||||
errorCollector.addError("Error in " + config.getFileName() + ": placeholder cannot be longer than 100 character (" + placeholder + ").");
|
||||
errorCollector.addError("Error in " + config.getSourceFileName() + ": placeholder cannot be longer than 100 character (" + placeholder + ").");
|
||||
continue;
|
||||
}
|
||||
|
@ -12,11 +12,13 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config.files;
|
||||
package me.filoghost.chestcommands.config;
|
||||
|
||||
import me.filoghost.chestcommands.config.SpecialConfig;
|
||||
import me.filoghost.chestcommands.config.framework.mapped.MappedConfig;
|
||||
import me.filoghost.chestcommands.config.framework.mapped.modifier.ChatColors;
|
||||
|
||||
public class Lang extends SpecialConfig {
|
||||
@ChatColors
|
||||
public class Lang extends MappedConfig {
|
||||
|
||||
public String no_open_permission = "&cYou don't have permission &e{permission} &cto use this menu.";
|
||||
public String default_no_icon_permission = "&cYou don't have permission for this icon.";
|
@ -12,11 +12,13 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config.files;
|
||||
package me.filoghost.chestcommands.config;
|
||||
|
||||
import me.filoghost.chestcommands.config.SpecialConfig;
|
||||
import me.filoghost.chestcommands.config.framework.mapped.MappedConfig;
|
||||
import me.filoghost.chestcommands.config.framework.mapped.modifier.ChatColors;
|
||||
|
||||
public class Settings extends SpecialConfig {
|
||||
@ChatColors
|
||||
public class Settings extends MappedConfig {
|
||||
|
||||
public String default_color__name = "&f";
|
||||
public String default_color__lore = "&7";
|
||||
@ -25,8 +27,8 @@ public class Settings extends SpecialConfig {
|
||||
|
||||
public Settings() {
|
||||
setHeader(
|
||||
"ChestCommands main configuration file.\n" +
|
||||
"Documentation: https://filoghost.me/docs/chest-commands\n");
|
||||
"ChestCommands main configuration file.",
|
||||
"Documentation: https://filoghost.me/docs/chest-commands");
|
||||
}
|
||||
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
/*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config;
|
||||
|
||||
import me.filoghost.chestcommands.util.Colors;
|
||||
import me.filoghost.chestcommands.util.Log;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* A special configuration wrapper that reads the values using reflection.
|
||||
* It will also save default values if not set.
|
||||
*/
|
||||
public abstract class SpecialConfig {
|
||||
|
||||
private transient String header;
|
||||
private transient Map<String, Object> defaultValuesMap;
|
||||
|
||||
public void setHeader(String header) {
|
||||
this.header = header;
|
||||
}
|
||||
|
||||
public void load(ConfigLoader loader) throws IOException, IllegalAccessException, InvalidConfigurationException {
|
||||
Config config = loader.load();
|
||||
|
||||
// Check if the configuration was initialized
|
||||
if (defaultValuesMap == null) {
|
||||
defaultValuesMap = new HashMap<>();
|
||||
|
||||
// Put the values in the default values map
|
||||
for (Field field : getClass().getDeclaredFields()) {
|
||||
if (skipField(field)) continue;
|
||||
|
||||
field.setAccessible(true);
|
||||
String configKey = getConfigNode(field);
|
||||
|
||||
try {
|
||||
Object defaultValue = field.get(this);
|
||||
if (defaultValue != null) {
|
||||
defaultValuesMap.put(configKey, defaultValue);
|
||||
} else {
|
||||
Log.warning("The field " + field.getName() + " was not provided with a default value, please inform the developer.");
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean needsSave = false;
|
||||
|
||||
// Save default values not set
|
||||
for (Entry<String, Object> entry : defaultValuesMap.entrySet()) {
|
||||
if (!config.isSet(entry.getKey())) {
|
||||
needsSave = true;
|
||||
config.set(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (needsSave) {
|
||||
config.setHeader(header);
|
||||
loader.save(config);
|
||||
}
|
||||
|
||||
// Now read change the fields
|
||||
for (Field field : getClass().getDeclaredFields()) {
|
||||
if (skipField(field)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
field.setAccessible(true);
|
||||
String configNode = getConfigNode(field);
|
||||
|
||||
if (config.isSet(configNode)) {
|
||||
Class<?> type = field.getType();
|
||||
|
||||
if (type == boolean.class || type == Boolean.class) {
|
||||
field.set(this, config.getBoolean(configNode));
|
||||
|
||||
} else if (type == int.class || type == Integer.class) {
|
||||
field.set(this, config.getInt(configNode));
|
||||
|
||||
} else if (type == double.class || type == Double.class) {
|
||||
field.set(this, config.getDouble(configNode));
|
||||
|
||||
} else if (type == String.class) {
|
||||
field.set(this, Colors.addColors(config.getString(configNode))); // Always add colors
|
||||
|
||||
} else {
|
||||
Log.warning("Unknown field type: " + field.getType().getName() + " (" + field.getName() + "). Please inform the developer.");
|
||||
}
|
||||
|
||||
} else {
|
||||
field.set(this, defaultValuesMap.get(configNode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean skipField(Field field) {
|
||||
int modifiers = field.getModifiers();
|
||||
return Modifier.isTransient(modifiers) || Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers);
|
||||
}
|
||||
|
||||
private String getConfigNode(Field field) {
|
||||
return field.getName().replace("__", ".").replace("_", "-");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config.framework;
|
||||
|
||||
import me.filoghost.chestcommands.config.framework.mapped.MappedConfig;
|
||||
import me.filoghost.chestcommands.config.framework.mapped.MappedConfigLoader;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class BaseConfigManager {
|
||||
|
||||
protected final Path rootDataFolder;
|
||||
|
||||
public BaseConfigManager(Path rootDataFolder) {
|
||||
this.rootDataFolder = rootDataFolder;
|
||||
}
|
||||
|
||||
public Path getRootDataFolder() {
|
||||
return rootDataFolder;
|
||||
}
|
||||
|
||||
public ConfigLoader getConfigLoader(String fileName) {
|
||||
return getConfigLoader(rootDataFolder.resolve(fileName));
|
||||
}
|
||||
|
||||
public ConfigLoader getConfigLoader(Path configPath) {
|
||||
return new ConfigLoader(rootDataFolder, configPath);
|
||||
}
|
||||
|
||||
public <T extends MappedConfig> MappedConfigLoader<T> getMappedConfigLoader(String fileName, Supplier<T> mappedObjectConstructor) {
|
||||
return getMappedConfigLoader(rootDataFolder.resolve(fileName), mappedObjectConstructor);
|
||||
}
|
||||
|
||||
public <T extends MappedConfig> MappedConfigLoader<T> getMappedConfigLoader(Path configPath, Supplier<T> mappedObjectConstructor) {
|
||||
return new MappedConfigLoader<>(rootDataFolder, configPath, mappedObjectConstructor);
|
||||
}
|
||||
|
||||
}
|
@ -12,7 +12,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config;
|
||||
package me.filoghost.chestcommands.config.framework;
|
||||
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
@ -21,16 +21,20 @@ import java.nio.file.Path;
|
||||
public class Config extends ConfigSection {
|
||||
|
||||
private final YamlConfiguration yaml;
|
||||
private final Path filePath;
|
||||
private final Path sourceFilePath;
|
||||
|
||||
public Config(YamlConfiguration yaml, Path filePath) {
|
||||
super(yaml);
|
||||
this.yaml = yaml;
|
||||
this.filePath = filePath;
|
||||
public Config(Path sourceFilePath) {
|
||||
this(new YamlConfiguration(), sourceFilePath);
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return filePath.getFileName().toString();
|
||||
public Config(YamlConfiguration yaml, Path sourceFilePath) {
|
||||
super(yaml);
|
||||
this.yaml = yaml;
|
||||
this.sourceFilePath = sourceFilePath;
|
||||
}
|
||||
|
||||
public String getSourceFileName() {
|
||||
return sourceFilePath.getFileName().toString();
|
||||
}
|
||||
|
||||
public String saveToString() {
|
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config.framework;
|
||||
|
||||
import me.filoghost.chestcommands.config.framework.exception.ConfigLoadException;
|
||||
import me.filoghost.chestcommands.config.framework.exception.ConfigSaveException;
|
||||
import me.filoghost.chestcommands.config.framework.exception.ConfigSyntaxException;
|
||||
import me.filoghost.chestcommands.util.Preconditions;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
public class ConfigLoader {
|
||||
|
||||
private final Path rootDataFolder;
|
||||
private final Path configPath;
|
||||
|
||||
public ConfigLoader(Path rootDataFolder, Path configPath) {
|
||||
Preconditions.checkArgument(configPath.startsWith(rootDataFolder), "config file " + configPath + " cannot be outside " + rootDataFolder);
|
||||
|
||||
this.rootDataFolder = rootDataFolder;
|
||||
this.configPath = configPath;
|
||||
}
|
||||
|
||||
public Config init() throws ConfigSaveException, ConfigLoadException {
|
||||
createDefault();
|
||||
return load();
|
||||
}
|
||||
|
||||
public void createDefault() throws ConfigSaveException {
|
||||
if (fileExists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
createParentDirectory();
|
||||
|
||||
Path relativeConfigPath = rootDataFolder.relativize(configPath);
|
||||
String internalJarPath = toInternalJarPath(relativeConfigPath);
|
||||
|
||||
try (InputStream defaultFile = getInternalResource(internalJarPath)) {
|
||||
if (defaultFile != null) {
|
||||
Files.copy(defaultFile, configPath);
|
||||
} else {
|
||||
Files.createFile(configPath);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new ConfigSaveException("couldn't create default config file " + configPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
private String toInternalJarPath(Path path) {
|
||||
return StreamSupport.stream(path.spliterator(), false)
|
||||
.map(Path::toString)
|
||||
.collect(Collectors.joining("/", "/", ""));
|
||||
}
|
||||
|
||||
|
||||
private InputStream getInternalResource(String internalJarPath) throws IOException {
|
||||
Preconditions.notNull(internalJarPath, "internalJarPath");
|
||||
|
||||
URL resourceURL = getClass().getResource(internalJarPath);
|
||||
if (resourceURL == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
URLConnection connection = resourceURL.openConnection();
|
||||
connection.setUseCaches(false);
|
||||
return connection.getInputStream();
|
||||
}
|
||||
|
||||
public boolean fileExists() {
|
||||
return (Files.isRegularFile(configPath));
|
||||
}
|
||||
|
||||
public Config load() throws ConfigLoadException {
|
||||
Preconditions.checkState(fileExists(), configPath.getFileName() + " doesn't exist or is not a regular file");
|
||||
|
||||
YamlConfiguration yaml = new YamlConfiguration();
|
||||
|
||||
try (BufferedReader reader = Files.newBufferedReader(configPath)) {
|
||||
yaml.load(reader);
|
||||
} catch (IOException e) {
|
||||
throw new ConfigLoadException("couldn't read config file " + configPath, e);
|
||||
} catch (InvalidConfigurationException e) {
|
||||
throw new ConfigSyntaxException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
return new Config(yaml, configPath);
|
||||
}
|
||||
|
||||
public void save(Config config) throws ConfigSaveException {
|
||||
createParentDirectory();
|
||||
|
||||
String data = config.saveToString();
|
||||
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(configPath)) {
|
||||
writer.write(data);
|
||||
} catch (IOException e) {
|
||||
throw new ConfigSaveException("couldn't write config data to " + configPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void createParentDirectory() throws ConfigSaveException {
|
||||
if (configPath.getParent() != null) {
|
||||
try {
|
||||
Files.createDirectories(configPath.getParent());
|
||||
} catch (IOException e) {
|
||||
throw new ConfigSaveException("couldn't create directory " + configPath.getParent(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Path getConfigPath() {
|
||||
return configPath;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return configPath.getFileName().toString();
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package me.filoghost.chestcommands.config;
|
||||
package me.filoghost.chestcommands.config.framework;
|
||||
|
||||
import me.filoghost.chestcommands.config.framework.exception.ConfigValueException;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -75,10 +76,6 @@ public class ConfigSection {
|
||||
return yamlSection.getKeys(deep);
|
||||
}
|
||||
|
||||
public boolean contains(String path) {
|
||||
return yamlSection.contains(path);
|
||||
}
|
||||
|
||||
public boolean isSet(String path) {
|
||||
return yamlSection.isSet(path);
|
||||
}
|
||||
@ -91,10 +88,6 @@ public class ConfigSection {
|
||||
return yamlSection.getString(path);
|
||||
}
|
||||
|
||||
public String getString(String path, String def) {
|
||||
return yamlSection.getString(path, def);
|
||||
}
|
||||
|
||||
public int getInt(String path) {
|
||||
return yamlSection.getInt(path);
|
||||
}
|
||||
@ -107,10 +100,6 @@ public class ConfigSection {
|
||||
return yamlSection.getDouble(path);
|
||||
}
|
||||
|
||||
public long getLong(String path) {
|
||||
return yamlSection.getLong(path);
|
||||
}
|
||||
|
||||
public List<String> getStringList(String path) {
|
||||
return yamlSection.getStringList(path);
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package me.filoghost.chestcommands.config.framework.exception;
|
||||
|
||||
public class ConfigException extends Exception {
|
||||
|
||||
public ConfigException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ConfigException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package me.filoghost.chestcommands.config.framework.exception;
|
||||
|
||||
public class ConfigLoadException extends ConfigException {
|
||||
|
||||
public ConfigLoadException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package me.filoghost.chestcommands.config.framework.exception;
|
||||
|
||||
public class ConfigSaveException extends ConfigException {
|
||||
|
||||
public ConfigSaveException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package me.filoghost.chestcommands.config.framework.exception;
|
||||
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
|
||||
public class ConfigSyntaxException extends ConfigLoadException {
|
||||
|
||||
public ConfigSyntaxException(String message, InvalidConfigurationException cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package me.filoghost.chestcommands.config.framework.exception;
|
||||
|
||||
public class ConfigValueException extends ConfigException {
|
||||
|
||||
public ConfigValueException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config.framework.mapped;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import me.filoghost.chestcommands.config.framework.ConfigSection;
|
||||
import me.filoghost.chestcommands.config.framework.mapped.converter.BooleanConverter;
|
||||
import me.filoghost.chestcommands.config.framework.mapped.converter.Converter;
|
||||
import me.filoghost.chestcommands.config.framework.mapped.converter.DoubleConverter;
|
||||
import me.filoghost.chestcommands.config.framework.mapped.converter.IntegerConverter;
|
||||
import me.filoghost.chestcommands.config.framework.mapped.converter.ListConverter;
|
||||
import me.filoghost.chestcommands.config.framework.mapped.converter.StringConverter;
|
||||
import me.filoghost.chestcommands.config.framework.mapped.modifier.ChatColorsModifier;
|
||||
import me.filoghost.chestcommands.config.framework.mapped.modifier.ValueModifier;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ConfigMapper {
|
||||
|
||||
private static final List<Converter> CONVERTERS = ImmutableList.of(
|
||||
new DoubleConverter(),
|
||||
new IntegerConverter(),
|
||||
new BooleanConverter(),
|
||||
new StringConverter(),
|
||||
new ListConverter()
|
||||
);
|
||||
|
||||
private static final List<ValueModifier<?, ?>> VALUE_MODIFIERS = ImmutableList.of(
|
||||
new ChatColorsModifier()
|
||||
);
|
||||
|
||||
private final MappedConfig mappedObject;
|
||||
private final ConfigSection config;
|
||||
private final List<MappedField> mappedFields;
|
||||
|
||||
public ConfigMapper(MappedConfig mappedObject, ConfigSection config) throws ReflectiveOperationException {
|
||||
this.mappedObject = mappedObject;
|
||||
this.config = config;
|
||||
this.mappedFields = getMappableFields(mappedObject.getClass());
|
||||
}
|
||||
|
||||
private List<MappedField> getMappableFields(Class<?> type) throws ReflectiveOperationException {
|
||||
Field[] declaredFields;
|
||||
|
||||
try {
|
||||
declaredFields = type.getDeclaredFields();
|
||||
} catch (Throwable t) {
|
||||
throw new ReflectiveOperationException(t);
|
||||
}
|
||||
|
||||
return Arrays.stream(declaredFields)
|
||||
.filter(this::isMappable)
|
||||
.map(MappedField::new)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public Map<MappedField, Object> getFieldValues() throws ReflectiveOperationException {
|
||||
Map<MappedField, Object> mappedFieldValues = new HashMap<>();
|
||||
|
||||
for (MappedField mappedField : mappedFields) {
|
||||
Object defaultValue = mappedField.getFromObject(mappedObject);
|
||||
|
||||
if (defaultValue == null) {
|
||||
throw new IllegalArgumentException("mapped field \"" + mappedField.getFieldName() + "\" cannot be null by default");
|
||||
}
|
||||
|
||||
mappedFieldValues.put(mappedField, defaultValue);
|
||||
}
|
||||
|
||||
return mappedFieldValues;
|
||||
}
|
||||
|
||||
public boolean addMissingConfigValues(Map<MappedField, Object> defaultValues) {
|
||||
boolean modified = false;
|
||||
|
||||
// Add missing values from defaults
|
||||
for (Entry<MappedField, Object> entry : defaultValues.entrySet()) {
|
||||
MappedField mappedField = entry.getKey();
|
||||
Object defaultValue = entry.getValue();
|
||||
|
||||
if (!config.isSet(mappedField.getConfigPath())) {
|
||||
modified = true;
|
||||
Converter converter = findConverter(mappedField.getFieldType());
|
||||
converter.setConfigValue(config, mappedField.getConfigPath(), defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
public void injectObjectFields() throws ReflectiveOperationException {
|
||||
for (MappedField mappedField : mappedFields) {
|
||||
injectObjectField(mappedField);
|
||||
}
|
||||
}
|
||||
|
||||
private void injectObjectField(MappedField mappedField) throws ReflectiveOperationException {
|
||||
Type[] genericTypes = mappedField.getGenericTypes();
|
||||
Converter converter = findConverter(mappedField.getFieldType());
|
||||
|
||||
Object fieldValue = converter.getFieldValue(config, mappedField.getConfigPath(), genericTypes);
|
||||
|
||||
for (Annotation annotation : mappedField.getAnnotations()) {
|
||||
fieldValue = applyValueModifiers(fieldValue, annotation);
|
||||
}
|
||||
|
||||
mappedField.setToObject(mappedObject, fieldValue);
|
||||
}
|
||||
|
||||
private Object applyValueModifiers(Object fieldValue, Annotation annotation) {
|
||||
for (ValueModifier<?, ?> modifier : VALUE_MODIFIERS) {
|
||||
if (modifier.isApplicable(annotation, fieldValue)) {
|
||||
fieldValue = modifier.transform(annotation, fieldValue);
|
||||
}
|
||||
}
|
||||
return fieldValue;
|
||||
}
|
||||
|
||||
private Converter findConverter(Class<?> type) {
|
||||
return CONVERTERS.stream()
|
||||
.filter(converter -> converter.matches(type))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("cannot find converter for type " + type));
|
||||
}
|
||||
|
||||
private boolean isMappable(Field field) {
|
||||
int modifiers = field.getModifiers();
|
||||
boolean includeStatic = field.isAnnotationPresent(IncludeStatic.class)
|
||||
|| field.getDeclaringClass().isAnnotationPresent(IncludeStatic.class);
|
||||
|
||||
return (!Modifier.isStatic(modifiers) || includeStatic)
|
||||
|| !Modifier.isTransient(modifiers)
|
||||
|| !Modifier.isFinal(modifiers);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config.framework.mapped;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.TYPE})
|
||||
public @interface IncludeStatic {
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config.framework.mapped;
|
||||
|
||||
import me.filoghost.chestcommands.config.framework.exception.ConfigLoadException;
|
||||
|
||||
public class MappedConfig {
|
||||
|
||||
private String header;
|
||||
|
||||
protected void setHeader(String... header) {
|
||||
this.header = String.join("\n", header) + "\n";
|
||||
}
|
||||
|
||||
public String getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
public void postLoad() throws ConfigLoadException {}
|
||||
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config.framework.mapped;
|
||||
|
||||
import me.filoghost.chestcommands.config.framework.Config;
|
||||
import me.filoghost.chestcommands.config.framework.ConfigLoader;
|
||||
import me.filoghost.chestcommands.config.framework.exception.ConfigLoadException;
|
||||
import me.filoghost.chestcommands.config.framework.exception.ConfigSaveException;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class MappedConfigLoader<T extends MappedConfig> {
|
||||
|
||||
private final ConfigLoader configLoader;
|
||||
private final Supplier<T> mappedObjectConstructor;
|
||||
private Map<MappedField, Object> defaultValues;
|
||||
|
||||
public MappedConfigLoader(Path rootDataFolder, Path configPath, Supplier<T> mappedObjectConstructor) {
|
||||
this.configLoader = new ConfigLoader(rootDataFolder, configPath);
|
||||
this.mappedObjectConstructor = mappedObjectConstructor;
|
||||
}
|
||||
|
||||
public T init() throws ConfigLoadException, ConfigSaveException {
|
||||
Config config = configLoader.init();
|
||||
T mappedObject = mappedObjectConstructor.get();
|
||||
|
||||
ConfigMapper mapper;
|
||||
try {
|
||||
mapper = new ConfigMapper(mappedObject, config);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new ConfigLoadException("couldn't initialize config mapper for class " + mappedObject.getClass(), e);
|
||||
}
|
||||
|
||||
// Extract default values from fields
|
||||
if (defaultValues == null) {
|
||||
try {
|
||||
defaultValues = mapper.getFieldValues();
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new ConfigLoadException("couldn't read field values in class " + mappedObject.getClass(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// Add missing values and save if necessary
|
||||
boolean modified = mapper.addMissingConfigValues(defaultValues);
|
||||
if (modified) {
|
||||
config.setHeader(mappedObject.getHeader());
|
||||
configLoader.save(config);
|
||||
}
|
||||
|
||||
// Update the mapped object with the contents from the config
|
||||
try {
|
||||
mapper.injectObjectFields();
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new ConfigLoadException("couldn't inject fields values in class " + mappedObject.getClass(), e);
|
||||
}
|
||||
mappedObject.postLoad();
|
||||
return mappedObject;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return configLoader.getFileName();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config.framework.mapped;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class MappedField {
|
||||
|
||||
private final Field field;
|
||||
private final String configPath;
|
||||
|
||||
public MappedField(Field field) {
|
||||
this.field = field;
|
||||
|
||||
this.configPath = field.getName()
|
||||
.replace("__", ".")
|
||||
.replace("_", "-");
|
||||
}
|
||||
|
||||
public Object getFromObject(MappedConfig mappedObject) throws ReflectiveOperationException {
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
return field.get(mappedObject);
|
||||
} catch (Throwable t) {
|
||||
throw new ReflectiveOperationException(t);
|
||||
}
|
||||
}
|
||||
|
||||
public void setToObject(MappedConfig mappedObject, Object fieldValue) throws ReflectiveOperationException {
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
field.set(mappedObject, fieldValue);
|
||||
} catch (Throwable t) {
|
||||
throw new ReflectiveOperationException(t);
|
||||
}
|
||||
}
|
||||
|
||||
public Type[] getGenericTypes() throws ReflectiveOperationException {
|
||||
try {
|
||||
Type genericType = field.getGenericType();
|
||||
if (genericType instanceof ParameterizedType) {
|
||||
return ((ParameterizedType) genericType).getActualTypeArguments();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
throw new ReflectiveOperationException(t);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Annotation> getAnnotations() {
|
||||
return Stream.concat(
|
||||
Arrays.stream(field.getDeclaredAnnotations()),
|
||||
Arrays.stream(field.getDeclaringClass().getDeclaredAnnotations()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public String getFieldName() {
|
||||
return field.getName();
|
||||
}
|
||||
|
||||
public Class<?> getFieldType() {
|
||||
return field.getType();
|
||||
}
|
||||
|
||||
public String getConfigPath() {
|
||||
return configPath;
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config.framework.mapped.converter;
|
||||
|
||||
import me.filoghost.chestcommands.config.framework.ConfigSection;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public class BooleanConverter implements Converter {
|
||||
|
||||
@Override
|
||||
public void setConfigValue(ConfigSection config, String path, Object value) {
|
||||
config.set(path, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getFieldValue(ConfigSection config, String path, Type[] parameterizedTypes) {
|
||||
return config.getBoolean(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Class<?> type) {
|
||||
return type == Boolean.class || type == boolean.class;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config.framework.mapped.converter;
|
||||
|
||||
import me.filoghost.chestcommands.config.framework.ConfigSection;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public interface Converter {
|
||||
|
||||
void setConfigValue(ConfigSection config, String path, Object value);
|
||||
|
||||
Object getFieldValue(ConfigSection config, String path, Type[] genericTypes);
|
||||
|
||||
boolean matches(Class<?> type);
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config.framework.mapped.converter;
|
||||
|
||||
import me.filoghost.chestcommands.config.framework.ConfigSection;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public class DoubleConverter implements Converter {
|
||||
|
||||
@Override
|
||||
public void setConfigValue(ConfigSection config, String path, Object value) {
|
||||
config.set(path, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getFieldValue(ConfigSection config, String path, Type[] parameterizedTypes) {
|
||||
return config.getDouble(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Class<?> type) {
|
||||
return type == Double.class || type == double.class;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config.framework.mapped.converter;
|
||||
|
||||
import me.filoghost.chestcommands.config.framework.ConfigSection;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public class IntegerConverter implements Converter {
|
||||
|
||||
@Override
|
||||
public void setConfigValue(ConfigSection config, String path, Object value) {
|
||||
config.set(path, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getFieldValue(ConfigSection config, String path, Type[] parameterizedTypes) {
|
||||
return config.getInt(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Class<?> type) {
|
||||
return type == Integer.class || type == int.class;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config.framework.mapped.converter;
|
||||
|
||||
import me.filoghost.chestcommands.config.framework.ConfigSection;
|
||||
import me.filoghost.chestcommands.util.Preconditions;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
public class ListConverter implements Converter {
|
||||
|
||||
@Override
|
||||
public void setConfigValue(ConfigSection config, String path, Object value) {
|
||||
config.set(path, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<?> getFieldValue(ConfigSection config, String path, Type[] genericTypes) {
|
||||
Preconditions.notNull(genericTypes, "genericTypes");
|
||||
Preconditions.checkArgument(genericTypes.length == 1, "genericTypes length must be 1");
|
||||
|
||||
Type listType = genericTypes[0];
|
||||
|
||||
if (listType == Integer.class) {
|
||||
return config.getIntegerList(path);
|
||||
} else if (listType == String.class) {
|
||||
return config.getStringList(path);
|
||||
} else {
|
||||
throw new IllegalArgumentException("unsupported list type: " + listType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Class<?> type) {
|
||||
return type == List.class;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config.framework.mapped.converter;
|
||||
|
||||
import me.filoghost.chestcommands.config.framework.ConfigSection;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public class StringConverter implements Converter {
|
||||
|
||||
@Override
|
||||
public void setConfigValue(ConfigSection config, String path, Object value) {
|
||||
config.set(path, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFieldValue(ConfigSection config, String path, Type[] parameterizedTypes) {
|
||||
return config.getString(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Class<?> type) {
|
||||
return type == String.class;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config.framework.mapped.modifier;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.TYPE})
|
||||
public @interface ChatColors {
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config.framework.mapped.modifier;
|
||||
|
||||
import me.filoghost.chestcommands.util.Colors;
|
||||
|
||||
public class ChatColorsModifier implements ValueModifier<String, ChatColors> {
|
||||
|
||||
@Override
|
||||
public String transformChecked(ChatColors annotation, String value) {
|
||||
return Colors.addColors(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<ChatColors> getAnnotationType() {
|
||||
return ChatColors.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<String> getValueType() {
|
||||
return String.class;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package me.filoghost.chestcommands.config.framework.mapped.modifier;
|
||||
|
||||
import me.filoghost.chestcommands.util.Preconditions;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
public interface ValueModifier<V, A extends Annotation> {
|
||||
|
||||
V transformChecked(A annotation, V value);
|
||||
|
||||
Class<A> getAnnotationType();
|
||||
|
||||
Class<V> getValueType();
|
||||
|
||||
default boolean isApplicable(Annotation annotation, Object value) {
|
||||
return getAnnotationType().isInstance(annotation) && getValueType().isInstance(value);
|
||||
}
|
||||
|
||||
default Object transform(Annotation annotation, Object fieldValue) {
|
||||
Preconditions.checkArgument(isApplicable(annotation, fieldValue), "modifier doesn't match given types");
|
||||
|
||||
return transformChecked(getAnnotationType().cast(annotation), getValueType().cast(fieldValue));
|
||||
}
|
||||
}
|
@ -14,10 +14,9 @@
|
||||
*/
|
||||
package me.filoghost.chestcommands.legacy;
|
||||
|
||||
import me.filoghost.chestcommands.config.Config;
|
||||
import me.filoghost.chestcommands.config.ConfigLoader;
|
||||
import me.filoghost.chestcommands.config.framework.exception.ConfigLoadException;
|
||||
import me.filoghost.chestcommands.config.framework.exception.ConfigSaveException;
|
||||
import me.filoghost.chestcommands.util.Preconditions;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
@ -40,7 +39,11 @@ public abstract class Upgrade {
|
||||
Preconditions.checkState(!hasRun, "Upgrade can only be run once");
|
||||
hasRun = true;
|
||||
|
||||
computeChanges();
|
||||
try {
|
||||
computeChanges();
|
||||
} catch (ConfigLoadException e) {
|
||||
throw new UpgradeException("couldn't load file to upgrade \"" + getOriginalFile().getFileName() + "\"", e);
|
||||
}
|
||||
|
||||
if (modified) {
|
||||
try {
|
||||
@ -51,7 +54,7 @@ public abstract class Upgrade {
|
||||
|
||||
try {
|
||||
saveChanges();
|
||||
} catch (IOException e) {
|
||||
} catch (ConfigSaveException e) {
|
||||
throw new UpgradeException("couldn't save upgraded file \"" + getUpgradedFile().getFileName() + "\"", e);
|
||||
}
|
||||
}
|
||||
@ -59,16 +62,6 @@ public abstract class Upgrade {
|
||||
return modified;
|
||||
}
|
||||
|
||||
protected Config loadConfig(ConfigLoader configLoader) throws UpgradeException {
|
||||
try {
|
||||
return configLoader.load();
|
||||
} catch (IOException e) {
|
||||
throw new UpgradeException("couldn't read configuration file \"" + configLoader.getFileName() + "\"", e);
|
||||
} catch (InvalidConfigurationException e) {
|
||||
throw new UpgradeException("couldn't parse YAML syntax of file \"" + configLoader.getFileName() + "\"", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void createBackupFile(Path path) throws IOException {
|
||||
String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy.MM.dd-HH.mm"));
|
||||
String backupName = path.getFileName() + "_" + date + ".backup";
|
||||
@ -80,8 +73,8 @@ public abstract class Upgrade {
|
||||
|
||||
public abstract Path getUpgradedFile();
|
||||
|
||||
protected abstract void computeChanges() throws UpgradeException;
|
||||
protected abstract void computeChanges() throws ConfigLoadException;
|
||||
|
||||
protected abstract void saveChanges() throws IOException;
|
||||
protected abstract void saveChanges() throws ConfigSaveException;
|
||||
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
package me.filoghost.chestcommands.legacy;
|
||||
|
||||
import me.filoghost.chestcommands.config.ConfigManager;
|
||||
import me.filoghost.chestcommands.config.ConfigLoader;
|
||||
import me.filoghost.chestcommands.config.framework.ConfigLoader;
|
||||
import me.filoghost.chestcommands.legacy.UpgradesDoneRegistry.UpgradeID;
|
||||
import me.filoghost.chestcommands.legacy.upgrades.MenuUpgrade;
|
||||
import me.filoghost.chestcommands.legacy.upgrades.PlaceholdersUpgrade;
|
||||
@ -42,7 +42,7 @@ public class UpgradesExecutor {
|
||||
|
||||
public void run(boolean isFreshInstall) throws UpgradeExecutorException {
|
||||
this.failedUpgrades = new ArrayList<>();
|
||||
Path upgradesDoneFile = configManager.getBaseDataPath().resolve(".upgrades-done");
|
||||
Path upgradesDoneFile = configManager.getRootDataFolder().resolve(".upgrades-done");
|
||||
|
||||
try {
|
||||
upgradesDoneRegistry = new UpgradesDoneRegistry(upgradesDoneFile);
|
||||
@ -56,18 +56,23 @@ public class UpgradesExecutor {
|
||||
upgradesDoneRegistry.setAllDone();
|
||||
|
||||
} else {
|
||||
String legacyCommandSeparator = readLegacyCommandSeparator();
|
||||
String legacyCommandSeparator;
|
||||
if (!upgradesDoneRegistry.isDone(UpgradeID.V4_MENUS)) {
|
||||
legacyCommandSeparator = readLegacyCommandSeparator();
|
||||
} else {
|
||||
legacyCommandSeparator = null;
|
||||
}
|
||||
|
||||
SettingsUpgrade settingsUpgrade = new SettingsUpgrade(configManager.getSettingsConfigLoader());
|
||||
SettingsUpgrade settingsUpgrade = new SettingsUpgrade(configManager);
|
||||
runIfNecessary(UpgradeID.V4_CONFIG, settingsUpgrade);
|
||||
|
||||
PlaceholdersUpgrade placeholdersUpgrade = new PlaceholdersUpgrade(configManager.getPlaceholdersConfigLoader(), configManager.getBaseDataPath());
|
||||
PlaceholdersUpgrade placeholdersUpgrade = new PlaceholdersUpgrade(configManager);
|
||||
runIfNecessary(UpgradeID.V4_PLACEHOLDERS, placeholdersUpgrade);
|
||||
|
||||
try {
|
||||
List<MenuUpgrade> menuUpgrades = CollectionUtils.transform(
|
||||
configManager.getMenuPaths(),
|
||||
menuPath -> new MenuUpgrade(new ConfigLoader(menuPath), legacyCommandSeparator));
|
||||
menuPath -> new MenuUpgrade(configManager.getConfigLoader(menuPath), legacyCommandSeparator));
|
||||
runIfNecessary(UpgradeID.V4_MENUS, menuUpgrades);
|
||||
} catch (IOException e) {
|
||||
failedUpgrades.add(configManager.getMenusFolder());
|
||||
@ -91,18 +96,18 @@ public class UpgradesExecutor {
|
||||
}
|
||||
|
||||
private String readLegacyCommandSeparator() {
|
||||
String legacyCommandSeparator;
|
||||
ConfigLoader settingsConfigLoader = configManager.getSettingsConfigLoader();
|
||||
ConfigLoader settingsConfigLoader = configManager.getConfigLoader("config.yml");
|
||||
|
||||
try {
|
||||
legacyCommandSeparator = settingsConfigLoader.load().getString("multiple-commands-separator", ";");
|
||||
} catch (Exception e) {
|
||||
legacyCommandSeparator = ";";
|
||||
Log.severe("Failed to load " + settingsConfigLoader.getFileName()
|
||||
+ ", assuming default command separator \"" + legacyCommandSeparator + "\".");
|
||||
if (!settingsConfigLoader.fileExists()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return legacyCommandSeparator;
|
||||
try {
|
||||
return settingsConfigLoader.load().getString("multiple-commands-separator");
|
||||
} catch (Throwable t) {
|
||||
Log.severe("Failed to load " + settingsConfigLoader.getFileName() + ", assuming default command separator \";\".");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -143,8 +148,7 @@ public class UpgradesExecutor {
|
||||
|
||||
private void logUpgradeException(Upgrade upgrade, UpgradeException upgradeException) {
|
||||
Log.severe(
|
||||
"Error while trying to automatically upgrade "
|
||||
+ upgrade.getOriginalFile() + ": " + upgradeException.getMessage(),
|
||||
"Error while trying to automatically upgrade " + upgrade.getOriginalFile() + ": " + upgradeException.getMessage(),
|
||||
upgradeException.getCause());
|
||||
}
|
||||
|
||||
|
@ -14,16 +14,16 @@
|
||||
*/
|
||||
package me.filoghost.chestcommands.legacy.upgrades;
|
||||
|
||||
import me.filoghost.chestcommands.config.Config;
|
||||
import me.filoghost.chestcommands.config.ConfigLoader;
|
||||
import me.filoghost.chestcommands.config.ConfigSection;
|
||||
import me.filoghost.chestcommands.config.framework.Config;
|
||||
import me.filoghost.chestcommands.config.framework.ConfigLoader;
|
||||
import me.filoghost.chestcommands.config.framework.ConfigSection;
|
||||
import me.filoghost.chestcommands.config.framework.exception.ConfigLoadException;
|
||||
import me.filoghost.chestcommands.config.framework.exception.ConfigSaveException;
|
||||
import me.filoghost.chestcommands.legacy.Upgrade;
|
||||
import me.filoghost.chestcommands.legacy.UpgradeException;
|
||||
import me.filoghost.chestcommands.parsing.menu.MenuSettingsNode;
|
||||
import me.filoghost.chestcommands.parsing.icon.IconSettingsNode;
|
||||
import me.filoghost.chestcommands.parsing.menu.MenuSettingsNode;
|
||||
import me.filoghost.chestcommands.util.Strings;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -43,17 +43,17 @@ public class MenuUpgrade extends Upgrade {
|
||||
|
||||
@Override
|
||||
public Path getOriginalFile() {
|
||||
return menuConfigLoader.getPath();
|
||||
return menuConfigLoader.getConfigPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getUpgradedFile() {
|
||||
return menuConfigLoader.getPath();
|
||||
return menuConfigLoader.getConfigPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void computeChanges() throws UpgradeException {
|
||||
Config menuConfig = loadConfig(menuConfigLoader);
|
||||
protected void computeChanges() throws ConfigLoadException {
|
||||
Config menuConfig = menuConfigLoader.load();
|
||||
menuConfig.setHeader(null);
|
||||
|
||||
for (String key : menuConfig.getKeys(true)) {
|
||||
@ -74,7 +74,7 @@ public class MenuUpgrade extends Upgrade {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveChanges() throws IOException {
|
||||
protected void saveChanges() throws ConfigSaveException {
|
||||
menuConfigLoader.save(updatedConfig);
|
||||
}
|
||||
|
||||
|
@ -14,10 +14,12 @@
|
||||
*/
|
||||
package me.filoghost.chestcommands.legacy.upgrades;
|
||||
|
||||
import me.filoghost.chestcommands.config.Config;
|
||||
import me.filoghost.chestcommands.config.ConfigLoader;
|
||||
import me.filoghost.chestcommands.config.ConfigManager;
|
||||
import me.filoghost.chestcommands.config.framework.Config;
|
||||
import me.filoghost.chestcommands.config.framework.ConfigLoader;
|
||||
import me.filoghost.chestcommands.config.framework.exception.ConfigLoadException;
|
||||
import me.filoghost.chestcommands.config.framework.exception.ConfigSaveException;
|
||||
import me.filoghost.chestcommands.legacy.Upgrade;
|
||||
import me.filoghost.chestcommands.legacy.UpgradeException;
|
||||
import me.filoghost.chestcommands.util.Strings;
|
||||
import org.apache.commons.lang.StringEscapeUtils;
|
||||
|
||||
@ -28,13 +30,13 @@ import java.util.List;
|
||||
|
||||
public class PlaceholdersUpgrade extends Upgrade {
|
||||
|
||||
private final ConfigLoader newPlaceholdersConfigLoader;
|
||||
private final Path oldPlaceholdersFile;
|
||||
private final ConfigLoader newPlaceholdersConfigLoader;
|
||||
private Config updatedConfig;
|
||||
|
||||
public PlaceholdersUpgrade(ConfigLoader placeholdersConfigLoader, Path dataPath) {
|
||||
this.newPlaceholdersConfigLoader = placeholdersConfigLoader;
|
||||
this.oldPlaceholdersFile = dataPath.resolve("placeholders.yml");
|
||||
public PlaceholdersUpgrade(ConfigManager configManager) {
|
||||
this.oldPlaceholdersFile = configManager.getRootDataFolder().resolve("placeholders.yml");
|
||||
this.newPlaceholdersConfigLoader = configManager.getConfigLoader("custom-placeholders.yml");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -44,22 +46,22 @@ public class PlaceholdersUpgrade extends Upgrade {
|
||||
|
||||
@Override
|
||||
public Path getUpgradedFile() {
|
||||
return newPlaceholdersConfigLoader.getPath();
|
||||
return newPlaceholdersConfigLoader.getConfigPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void computeChanges() throws UpgradeException {
|
||||
protected void computeChanges() throws ConfigLoadException {
|
||||
if (!Files.isRegularFile(oldPlaceholdersFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do NOT load the new placeholder configuration from disk, as it should only contain placeholders imported from the old file
|
||||
Config newPlaceholdersConfig = newPlaceholdersConfigLoader.loadEmpty();
|
||||
Config newPlaceholdersConfig = new Config(newPlaceholdersConfigLoader.getConfigPath());
|
||||
List<String> lines;
|
||||
try {
|
||||
lines = Files.readAllLines(oldPlaceholdersFile);
|
||||
} catch (IOException e) {
|
||||
throw new UpgradeException("couldn't read file \"" + oldPlaceholdersFile.getFileName() + "\"", e);
|
||||
throw new ConfigLoadException("couldn't read file \"" + oldPlaceholdersFile.getFileName() + "\"", e);
|
||||
}
|
||||
|
||||
for (String line : lines) {
|
||||
@ -85,7 +87,7 @@ public class PlaceholdersUpgrade extends Upgrade {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveChanges() throws IOException {
|
||||
protected void saveChanges() throws ConfigSaveException {
|
||||
try {
|
||||
Files.deleteIfExists(oldPlaceholdersFile);
|
||||
} catch (IOException ignored) {}
|
||||
|
@ -14,12 +14,13 @@
|
||||
*/
|
||||
package me.filoghost.chestcommands.legacy.upgrades;
|
||||
|
||||
import me.filoghost.chestcommands.config.Config;
|
||||
import me.filoghost.chestcommands.config.ConfigLoader;
|
||||
import me.filoghost.chestcommands.config.ConfigManager;
|
||||
import me.filoghost.chestcommands.config.framework.Config;
|
||||
import me.filoghost.chestcommands.config.framework.ConfigLoader;
|
||||
import me.filoghost.chestcommands.config.framework.exception.ConfigLoadException;
|
||||
import me.filoghost.chestcommands.config.framework.exception.ConfigSaveException;
|
||||
import me.filoghost.chestcommands.legacy.Upgrade;
|
||||
import me.filoghost.chestcommands.legacy.UpgradeException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class SettingsUpgrade extends Upgrade {
|
||||
@ -27,23 +28,23 @@ public class SettingsUpgrade extends Upgrade {
|
||||
private final ConfigLoader settingsConfigLoader;
|
||||
private Config updatedConfig;
|
||||
|
||||
public SettingsUpgrade(ConfigLoader settingsConfigLoader) {
|
||||
this.settingsConfigLoader = settingsConfigLoader;
|
||||
public SettingsUpgrade(ConfigManager configManager) {
|
||||
this.settingsConfigLoader = configManager.getConfigLoader("config.yml");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getOriginalFile() {
|
||||
return settingsConfigLoader.getPath();
|
||||
return settingsConfigLoader.getConfigPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getUpgradedFile() {
|
||||
return settingsConfigLoader.getPath();
|
||||
return settingsConfigLoader.getConfigPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void computeChanges() throws UpgradeException {
|
||||
Config settingsConfig = loadConfig(settingsConfigLoader);
|
||||
protected void computeChanges() throws ConfigLoadException {
|
||||
Config settingsConfig = settingsConfigLoader.load();
|
||||
|
||||
removeNode(settingsConfig, "use-only-commands-without-args");
|
||||
removeNode(settingsConfig, "use-console-colors");
|
||||
@ -61,7 +62,7 @@ public class SettingsUpgrade extends Upgrade {
|
||||
|
||||
|
||||
@Override
|
||||
protected void saveChanges() throws IOException {
|
||||
protected void saveChanges() throws ConfigSaveException {
|
||||
settingsConfigLoader.save(updatedConfig);
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,20 @@
|
||||
package me.filoghost.chestcommands.parsing;
|
||||
|
||||
import me.filoghost.chestcommands.config.framework.Config;
|
||||
import me.filoghost.chestcommands.parsing.icon.IconSettings;
|
||||
|
||||
public class ErrorFormat {
|
||||
|
||||
public static String invalidMenuSetting(String menuName, String invalidSetting, String errorMessage) {
|
||||
return menuError(menuName, "has an invalid menu setting \"" + invalidSetting + "\": " + errorMessage);
|
||||
public static String invalidMenuSetting(Config menuConfig, String invalidSetting, String errorMessage) {
|
||||
return menuError(menuConfig, "has an invalid menu setting \"" + invalidSetting + "\": " + errorMessage);
|
||||
}
|
||||
|
||||
public static String missingMenuSetting(String menuName, String missingSetting) {
|
||||
return menuError(menuName, "is missing the menu setting \"" + missingSetting + "\"");
|
||||
public static String missingMenuSetting(Config menuConfig, String missingSetting) {
|
||||
return menuError(menuConfig, "is missing the menu setting \"" + missingSetting + "\"");
|
||||
}
|
||||
|
||||
private static String menuError(String menuName, String errorMessage) {
|
||||
return "The menu \"" + menuName + "\" " + errorMessage + ".";
|
||||
private static String menuError(Config menuConfig, String errorMessage) {
|
||||
return "The menu \"" + menuConfig.getSourceFileName() + "\" " + errorMessage + ".";
|
||||
}
|
||||
|
||||
public static String invalidAttribute(IconSettings iconSettings, String attributeName, String errorMessage) {
|
||||
|
@ -14,8 +14,8 @@
|
||||
*/
|
||||
package me.filoghost.chestcommands.parsing.icon;
|
||||
|
||||
import me.filoghost.chestcommands.config.ConfigSection;
|
||||
import me.filoghost.chestcommands.config.ConfigValueException;
|
||||
import me.filoghost.chestcommands.config.framework.ConfigSection;
|
||||
import me.filoghost.chestcommands.config.framework.exception.ConfigValueException;
|
||||
import me.filoghost.chestcommands.icon.InternalConfigurableIcon;
|
||||
import me.filoghost.chestcommands.parsing.ParseException;
|
||||
import me.filoghost.chestcommands.parsing.icon.attributes.ActionsAttribute;
|
||||
|
@ -15,11 +15,11 @@
|
||||
package me.filoghost.chestcommands.parsing.menu;
|
||||
|
||||
import me.filoghost.chestcommands.action.Action;
|
||||
import me.filoghost.chestcommands.config.Config;
|
||||
import me.filoghost.chestcommands.config.ConfigSection;
|
||||
import me.filoghost.chestcommands.config.ConfigValueException;
|
||||
import me.filoghost.chestcommands.menu.InternalIconMenu;
|
||||
import me.filoghost.chestcommands.config.framework.Config;
|
||||
import me.filoghost.chestcommands.config.framework.ConfigSection;
|
||||
import me.filoghost.chestcommands.config.framework.exception.ConfigValueException;
|
||||
import me.filoghost.chestcommands.icon.InternalConfigurableIcon;
|
||||
import me.filoghost.chestcommands.menu.InternalIconMenu;
|
||||
import me.filoghost.chestcommands.parsing.ActionParser;
|
||||
import me.filoghost.chestcommands.parsing.ErrorFormat;
|
||||
import me.filoghost.chestcommands.parsing.ItemStackParser;
|
||||
@ -41,7 +41,7 @@ public class MenuParser {
|
||||
MenuSettings menuSettings = loadMenuSettings(menuConfig, errorCollector);
|
||||
List<IconSettings> iconSettingsList = loadIconSettingsList(menuConfig, errorCollector);
|
||||
|
||||
InternalIconMenu iconMenu = new InternalIconMenu(menuSettings.getTitle(), menuSettings.getRows(), menuConfig.getFileName());
|
||||
InternalIconMenu iconMenu = new InternalIconMenu(menuSettings.getTitle(), menuSettings.getRows(), menuConfig.getSourceFileName());
|
||||
|
||||
for (IconSettings iconSettings : iconSettingsList) {
|
||||
try {
|
||||
@ -54,7 +54,7 @@ public class MenuParser {
|
||||
iconMenu.setRefreshTicks(menuSettings.getRefreshTicks());
|
||||
iconMenu.setOpenActions(menuSettings.getOpenActions());
|
||||
|
||||
return new LoadedMenu(iconMenu, menuConfig.getFileName(), menuSettings.getCommands(), menuSettings.getOpenTrigger());
|
||||
return new LoadedMenu(iconMenu, menuConfig.getSourceFileName(), menuSettings.getCommands(), menuSettings.getOpenTrigger());
|
||||
}
|
||||
|
||||
|
||||
@ -105,7 +105,7 @@ public class MenuParser {
|
||||
}
|
||||
} catch (ConfigValueException e) {
|
||||
title = ChatColor.DARK_RED + "No name set";
|
||||
errorCollector.addError(ErrorFormat.missingMenuSetting(config.getFileName(), MenuSettingsNode.NAME));
|
||||
errorCollector.addError(ErrorFormat.missingMenuSetting(config, MenuSettingsNode.NAME));
|
||||
}
|
||||
|
||||
int rows;
|
||||
@ -116,7 +116,7 @@ public class MenuParser {
|
||||
}
|
||||
} catch (ConfigValueException e) {
|
||||
rows = 6; // Defaults to 6 rows
|
||||
errorCollector.addError(ErrorFormat.missingMenuSetting(config.getFileName(), MenuSettingsNode.ROWS));
|
||||
errorCollector.addError(ErrorFormat.missingMenuSetting(config, MenuSettingsNode.ROWS));
|
||||
}
|
||||
|
||||
MenuSettings menuSettings = new MenuSettings(title, rows);
|
||||
@ -157,7 +157,7 @@ public class MenuParser {
|
||||
menuSettings.setOpenTrigger(openTrigger);
|
||||
|
||||
} catch (ParseException e) {
|
||||
errorCollector.addError(ErrorFormat.invalidMenuSetting(config.getFileName(), MenuSettingsNode.OPEN_ITEM_MATERIAL, e.getMessage()));
|
||||
errorCollector.addError(ErrorFormat.invalidMenuSetting(config, MenuSettingsNode.OPEN_ITEM_MATERIAL, e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -183,7 +183,7 @@ public class MenuParser {
|
||||
}
|
||||
|
||||
ConfigSection iconSection = config.getConfigSection(iconSectionName);
|
||||
IconSettings iconSettings = new IconSettings(config.getFileName(), iconSectionName);
|
||||
IconSettings iconSettings = new IconSettings(config.getSourceFileName(), iconSectionName);
|
||||
iconSettings.loadFrom(iconSection, errorCollector);
|
||||
iconSettingsList.add(iconSettings);
|
||||
}
|
||||
|
@ -14,10 +14,10 @@
|
||||
*/
|
||||
package me.filoghost.chestcommands.util;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.bukkit.Material;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public final class Preconditions {
|
||||
|
||||
private Preconditions() {}
|
||||
|
Loading…
Reference in New Issue
Block a user