Lots of config improvements
Removed redundant delegate methods by making the methods non-static Automatically saving config option to the yaml model when it's accessed for the first time Automatically saving yaml config on component/plugin disable Automatically resetting config cache on plugin/component disable Caching the config values so reading is cheaper (it still writes through) Correctly handling (non-)primitive types in configs Allowing to set either a primitive or non-primitive default value and the other is obtained from the provided value #48
This commit is contained in:
parent
bb31f4e378
commit
245f6bbf59
5 changed files with 103 additions and 60 deletions
|
@ -1,5 +1,10 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
|
<component name="EntryPointsManager">
|
||||||
|
<list size="1">
|
||||||
|
<item index="0" class="java.lang.String" itemvalue="org.bukkit.event.EventHandler" />
|
||||||
|
</list>
|
||||||
|
</component>
|
||||||
<component name="MavenProjectsManager">
|
<component name="MavenProjectsManager">
|
||||||
<option name="originalFiles">
|
<option name="originalFiles">
|
||||||
<list>
|
<list>
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
package buttondevteam.lib.architecture;
|
package buttondevteam.lib.architecture;
|
||||||
|
|
||||||
import buttondevteam.lib.TBMCCoreAPI;
|
import buttondevteam.lib.TBMCCoreAPI;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.experimental.var;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
public abstract class ButtonPlugin extends JavaPlugin {
|
public abstract class ButtonPlugin extends JavaPlugin {
|
||||||
private final HashMap<String, ConfigData<?>> datamap = new HashMap<>();
|
@Getter(AccessLevel.PROTECTED)
|
||||||
private ConfigurationSection section;
|
private IHaveConfig iConfig;
|
||||||
|
|
||||||
protected abstract void pluginEnable();
|
protected abstract void pluginEnable();
|
||||||
|
|
||||||
|
@ -18,8 +16,9 @@ public abstract class ButtonPlugin extends JavaPlugin {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
section = getConfig().getConfigurationSection("global");
|
var section = super.getConfig().getConfigurationSection("global");
|
||||||
if (section == null) section = getConfig().createSection("global");
|
if (section == null) section = super.getConfig().createSection("global");
|
||||||
|
iConfig = new IHaveConfig(section);
|
||||||
try {
|
try {
|
||||||
pluginEnable();
|
pluginEnable();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -31,22 +30,10 @@ public abstract class ButtonPlugin extends JavaPlugin {
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
try {
|
try {
|
||||||
pluginDisable();
|
pluginDisable();
|
||||||
|
saveConfig();
|
||||||
|
iConfig.resetConfigurationCache();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
TBMCCoreAPI.SendException("Error while disabling plugin " + getName() + "!", e);
|
TBMCCoreAPI.SendException("Error while disabling plugin " + getName() + "!", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see IHaveConfig#getData(Map, ConfigurationSection, String, Object)
|
|
||||||
*/
|
|
||||||
protected <T> ConfigData<T> getData(String path, T def) {
|
|
||||||
return IHaveConfig.getData(datamap, section, path, def);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see IHaveConfig#getData(Map, ConfigurationSection, String, Object, Function, Function)
|
|
||||||
*/
|
|
||||||
protected <T> ConfigData<T> getData(String path, T def, Function<Object, T> getter, Function<T, Object> setter) {
|
|
||||||
return IHaveConfig.getData(datamap, section, path, def, getter, setter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration is based on class name
|
* Configuration is based on class name
|
||||||
|
@ -31,26 +30,13 @@ public abstract class Component {
|
||||||
@NonNull
|
@NonNull
|
||||||
private JavaPlugin plugin;
|
private JavaPlugin plugin;
|
||||||
@NonNull
|
@NonNull
|
||||||
private ConfigurationSection config;
|
private ConfigurationSection configSect;
|
||||||
|
@NonNull
|
||||||
|
private @Getter
|
||||||
|
IHaveConfig config;
|
||||||
|
|
||||||
public ConfigData<Boolean> shouldBeEnabled() {
|
public ConfigData<Boolean> shouldBeEnabled() {
|
||||||
return getData("enabled", true);
|
return config.getData("enabled", true);
|
||||||
}
|
|
||||||
|
|
||||||
private HashMap<String, ConfigData<?>> datamap = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see IHaveConfig#getData(Map, ConfigurationSection, String, Object)
|
|
||||||
*/
|
|
||||||
protected <T> ConfigData<T> getData(String path, T def) {
|
|
||||||
return IHaveConfig.getData(datamap, config, path, def);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see IHaveConfig#getData(Map, ConfigurationSection, String, Object, Function, Function)
|
|
||||||
*/
|
|
||||||
protected <T> ConfigData<T> getData(String path, T def, Function<Object, T> getter, Function<T, Object> setter) {
|
|
||||||
return IHaveConfig.getData(datamap, config, path, def, getter, setter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -95,8 +81,10 @@ public abstract class Component {
|
||||||
component.plugin = plugin;
|
component.plugin = plugin;
|
||||||
var compconf = plugin.getConfig().getConfigurationSection("components");
|
var compconf = plugin.getConfig().getConfigurationSection("components");
|
||||||
if (compconf == null) compconf = plugin.getConfig().createSection("components");
|
if (compconf == null) compconf = plugin.getConfig().createSection("components");
|
||||||
component.config = compconf.getConfigurationSection(component.getClassName());
|
component.configSect = compconf.getConfigurationSection(component.getClassName());
|
||||||
if (component.config == null) component.config = compconf.createSection(component.getClassName());
|
if (component.configSect == null)
|
||||||
|
component.configSect = compconf.createSection(component.getClassName());
|
||||||
|
component.config = new IHaveConfig(component.configSect);
|
||||||
component.register(plugin);
|
component.register(plugin);
|
||||||
components.put(component.getClass(), component);
|
components.put(component.getClass(), component);
|
||||||
if (ComponentManager.areComponentsEnabled() && component.shouldBeEnabled().get()) {
|
if (ComponentManager.areComponentsEnabled() && component.shouldBeEnabled().get()) {
|
||||||
|
@ -108,12 +96,11 @@ public abstract class Component {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true; //Component shouldn't be enabled
|
||||||
} else {
|
} else {
|
||||||
if (component.enabled) {
|
if (component.enabled) {
|
||||||
try {
|
try {
|
||||||
component.disable();
|
setComponentEnabled(component, false);
|
||||||
component.enabled = false;
|
|
||||||
} catch (Exception | NoClassDefFoundError e) {
|
} catch (Exception | NoClassDefFoundError e) {
|
||||||
TBMCCoreAPI.SendException("Failed to disable component " + component.getClassName() + "!", e);
|
TBMCCoreAPI.SendException("Failed to disable component " + component.getClassName() + "!", e);
|
||||||
return false; //If failed to disable, won't unregister either
|
return false; //If failed to disable, won't unregister either
|
||||||
|
@ -140,8 +127,11 @@ public abstract class Component {
|
||||||
throw new UnregisteredComponentException(component);
|
throw new UnregisteredComponentException(component);
|
||||||
if (component.enabled = enabled)
|
if (component.enabled = enabled)
|
||||||
component.enable();
|
component.enable();
|
||||||
else
|
else {
|
||||||
component.disable();
|
component.disable();
|
||||||
|
component.plugin.saveConfig();
|
||||||
|
component.config.resetConfigurationCache();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -159,6 +149,7 @@ public abstract class Component {
|
||||||
*
|
*
|
||||||
* @param plugin Plugin object
|
* @param plugin Plugin object
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings({"unused", "WeakerAccess"})
|
||||||
protected void register(JavaPlugin plugin) {
|
protected void register(JavaPlugin plugin) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,6 +160,7 @@ public abstract class Component {
|
||||||
*
|
*
|
||||||
* @param plugin Plugin object
|
* @param plugin Plugin object
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings({"WeakerAccess", "unused"})
|
||||||
protected void unregister(JavaPlugin plugin) {
|
protected void unregister(JavaPlugin plugin) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,24 @@
|
||||||
package buttondevteam.lib.architecture;
|
package buttondevteam.lib.architecture;
|
||||||
|
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use the getter/setter constructor if {@link T} isn't a primitive type or String.<br>
|
* Use the getter/setter constructor if {@link T} isn't a primitive type or String.<br>
|
||||||
* Use {@link Component#getData(String, Object)} or {@link ButtonPlugin#getData(String, Object)} to get an instance.
|
* Use {@link Component#getConfig()} or {@link ButtonPlugin#getIConfig()} then {@link IHaveConfig#getData(String, Object)} to get an instance.
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
|
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
|
||||||
@AllArgsConstructor(access = AccessLevel.PACKAGE)
|
//@AllArgsConstructor(access = AccessLevel.PACKAGE)
|
||||||
public class ConfigData<T> { //TODO: Save after a while
|
public class ConfigData<T> { //TODO: Save after a while
|
||||||
private final ConfigurationSection config;
|
private final ConfigurationSection config;
|
||||||
private final String path;
|
private final String path;
|
||||||
private final T def;
|
private @Nullable final T def;
|
||||||
|
private final Object primitiveDef;
|
||||||
/**
|
/**
|
||||||
* The parameter is of a primitive type as returned by {@link YamlConfiguration#get(String)}
|
* The parameter is of a primitive type as returned by {@link YamlConfiguration#get(String)}
|
||||||
*/
|
*/
|
||||||
|
@ -27,9 +28,35 @@ public class ConfigData<T> { //TODO: Save after a while
|
||||||
*/
|
*/
|
||||||
private Function<T, Object> setter;
|
private Function<T, Object> setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The config value should not change outside this instance
|
||||||
|
*/
|
||||||
|
private T value;
|
||||||
|
private boolean saved = false;
|
||||||
|
|
||||||
|
public ConfigData(ConfigurationSection config, String path, T def, Object primitiveDef, Function<Object, T> getter, Function<T, Object> setter) {
|
||||||
|
this.config = config;
|
||||||
|
this.path = path;
|
||||||
|
this.def = def;
|
||||||
|
this.primitiveDef = primitiveDef;
|
||||||
|
this.getter = getter;
|
||||||
|
this.setter = setter;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public T get() {
|
public T get() {
|
||||||
Object val = config.get(path, def);
|
if (value != null) return value; //Speed things up
|
||||||
|
Object val = config.get(path);
|
||||||
|
if (val == null) {
|
||||||
|
val = primitiveDef;
|
||||||
|
}
|
||||||
|
if (val == primitiveDef && !saved) {
|
||||||
|
if (def != null)
|
||||||
|
set(def); //Save default value
|
||||||
|
else
|
||||||
|
config.set(path, primitiveDef);
|
||||||
|
saved = true;
|
||||||
|
}
|
||||||
if (getter != null) {
|
if (getter != null) {
|
||||||
T hmm = getter.apply(val);
|
T hmm = getter.apply(val);
|
||||||
if (hmm == null) hmm = def; //Set if the getter returned null
|
if (hmm == null) hmm = def; //Set if the getter returned null
|
||||||
|
@ -44,5 +71,6 @@ public class ConfigData<T> { //TODO: Save after a while
|
||||||
val = setter.apply(value);
|
val = setter.apply(value);
|
||||||
else val = value;
|
else val = value;
|
||||||
config.set(path, val);
|
config.set(path, val);
|
||||||
|
this.value =value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,19 @@ package buttondevteam.lib.architecture;
|
||||||
|
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.HashMap;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Members of this interface should be protected (access level)
|
* Members of this interface should be protected (access level)
|
||||||
*/
|
*/
|
||||||
final class IHaveConfig {
|
public final class IHaveConfig {
|
||||||
private IHaveConfig() {}
|
private final HashMap<String, ConfigData<?>> datamap = new HashMap<>();
|
||||||
|
private ConfigurationSection config;
|
||||||
|
|
||||||
|
IHaveConfig(ConfigurationSection section) {
|
||||||
|
config = section;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method overload should only be used with primitves or String.
|
* This method overload should only be used with primitves or String.
|
||||||
|
@ -20,9 +25,9 @@ final class IHaveConfig {
|
||||||
* @return The data object that can be used to get or set the value
|
* @return The data object that can be used to get or set the value
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected static <T> ConfigData<T> getData(Map<String, ConfigData<?>> datamap, ConfigurationSection config, String path, T def) {
|
public <T> ConfigData<T> getData(String path, T def) {
|
||||||
ConfigData<?> data = datamap.get(path);
|
ConfigData<?> data = datamap.get(path);
|
||||||
if (data == null) datamap.put(path, data = new ConfigData<>(config, path, def));
|
if (data == null) datamap.put(path, data = new ConfigData<>(config, path, def, def));
|
||||||
return (ConfigData<T>) data;
|
return (ConfigData<T>) data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,9 +42,35 @@ final class IHaveConfig {
|
||||||
* @return The data object that can be used to get or set the value
|
* @return The data object that can be used to get or set the value
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected static <T> ConfigData<T> getData(Map<String, ConfigData<?>> datamap, ConfigurationSection config, String path, T def, Function<Object, T> getter, Function<T, Object> setter) {
|
public <T> ConfigData<T> getData(String path, T def, Function<Object, T> getter, Function<T, Object> setter) {
|
||||||
ConfigData<?> data = datamap.get(path);
|
ConfigData<?> data = datamap.get(path);
|
||||||
if (data == null) datamap.put(path, data = new ConfigData<>(config, path, def, getter, setter));
|
if (data == null)
|
||||||
|
datamap.put(path, data = new ConfigData<>(config, path, def, setter.apply(def), getter, setter));
|
||||||
return (ConfigData<T>) data;
|
return (ConfigData<T>) data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method overload may be used with any class. The given default value will be run through the getter.
|
||||||
|
*
|
||||||
|
* @param path The path in config to use
|
||||||
|
* @param primitiveDef The <b>primitive</b> value to use by default
|
||||||
|
* @param getter A function that converts a primitive representation to the correct value
|
||||||
|
* @param setter A function that converts a value to a primitive representation
|
||||||
|
* @param <T> The type of this variable (can be any class)
|
||||||
|
* @return The data object that can be used to get or set the value
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> ConfigData<T> getDataPrimDef(String path, Object primitiveDef, Function<Object, T> getter, Function<T, Object> setter) {
|
||||||
|
ConfigData<?> data = datamap.get(path);
|
||||||
|
if (data == null)
|
||||||
|
datamap.put(path, data = new ConfigData<>(config, path, getter.apply(primitiveDef), primitiveDef, getter, setter));
|
||||||
|
return (ConfigData<T>) data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the config cache. Call this on component/plugin disable so that new values are read.
|
||||||
|
*/
|
||||||
|
public void resetConfigurationCache() {
|
||||||
|
datamap.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue