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"?>
|
||||
<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">
|
||||
<option name="originalFiles">
|
||||
<list>
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
package buttondevteam.lib.architecture;
|
||||
|
||||
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 java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
public abstract class ButtonPlugin extends JavaPlugin {
|
||||
private final HashMap<String, ConfigData<?>> datamap = new HashMap<>();
|
||||
private ConfigurationSection section;
|
||||
@Getter(AccessLevel.PROTECTED)
|
||||
private IHaveConfig iConfig;
|
||||
|
||||
protected abstract void pluginEnable();
|
||||
|
||||
|
@ -18,8 +16,9 @@ public abstract class ButtonPlugin extends JavaPlugin {
|
|||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
section = getConfig().getConfigurationSection("global");
|
||||
if (section == null) section = getConfig().createSection("global");
|
||||
var section = super.getConfig().getConfigurationSection("global");
|
||||
if (section == null) section = super.getConfig().createSection("global");
|
||||
iConfig = new IHaveConfig(section);
|
||||
try {
|
||||
pluginEnable();
|
||||
} catch (Exception e) {
|
||||
|
@ -31,22 +30,10 @@ public abstract class ButtonPlugin extends JavaPlugin {
|
|||
public void onDisable() {
|
||||
try {
|
||||
pluginDisable();
|
||||
saveConfig();
|
||||
iConfig.resetConfigurationCache();
|
||||
} catch (Exception 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.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Configuration is based on class name
|
||||
|
@ -31,26 +30,13 @@ public abstract class Component {
|
|||
@NonNull
|
||||
private JavaPlugin plugin;
|
||||
@NonNull
|
||||
private ConfigurationSection config;
|
||||
private ConfigurationSection configSect;
|
||||
@NonNull
|
||||
private @Getter
|
||||
IHaveConfig config;
|
||||
|
||||
public ConfigData<Boolean> shouldBeEnabled() {
|
||||
return 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);
|
||||
return config.getData("enabled", true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -95,8 +81,10 @@ public abstract class Component {
|
|||
component.plugin = plugin;
|
||||
var compconf = plugin.getConfig().getConfigurationSection("components");
|
||||
if (compconf == null) compconf = plugin.getConfig().createSection("components");
|
||||
component.config = compconf.getConfigurationSection(component.getClassName());
|
||||
if (component.config == null) component.config = compconf.createSection(component.getClassName());
|
||||
component.configSect = compconf.getConfigurationSection(component.getClassName());
|
||||
if (component.configSect == null)
|
||||
component.configSect = compconf.createSection(component.getClassName());
|
||||
component.config = new IHaveConfig(component.configSect);
|
||||
component.register(plugin);
|
||||
components.put(component.getClass(), component);
|
||||
if (ComponentManager.areComponentsEnabled() && component.shouldBeEnabled().get()) {
|
||||
|
@ -108,12 +96,11 @@ public abstract class Component {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return true; //Component shouldn't be enabled
|
||||
} else {
|
||||
if (component.enabled) {
|
||||
try {
|
||||
component.disable();
|
||||
component.enabled = false;
|
||||
setComponentEnabled(component, false);
|
||||
} catch (Exception | NoClassDefFoundError e) {
|
||||
TBMCCoreAPI.SendException("Failed to disable component " + component.getClassName() + "!", e);
|
||||
return false; //If failed to disable, won't unregister either
|
||||
|
@ -140,8 +127,11 @@ public abstract class Component {
|
|||
throw new UnregisteredComponentException(component);
|
||||
if (component.enabled = enabled)
|
||||
component.enable();
|
||||
else
|
||||
else {
|
||||
component.disable();
|
||||
component.plugin.saveConfig();
|
||||
component.config.resetConfigurationCache();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -159,6 +149,7 @@ public abstract class Component {
|
|||
*
|
||||
* @param plugin Plugin object
|
||||
*/
|
||||
@SuppressWarnings({"unused", "WeakerAccess"})
|
||||
protected void register(JavaPlugin plugin) {
|
||||
}
|
||||
|
||||
|
@ -169,6 +160,7 @@ public abstract class Component {
|
|||
*
|
||||
* @param plugin Plugin object
|
||||
*/
|
||||
@SuppressWarnings({"WeakerAccess", "unused"})
|
||||
protected void unregister(JavaPlugin plugin) {
|
||||
}
|
||||
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
package buttondevteam.lib.architecture;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 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)
|
||||
@AllArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
//@AllArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
public class ConfigData<T> { //TODO: Save after a while
|
||||
private final ConfigurationSection config;
|
||||
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)}
|
||||
*/
|
||||
|
@ -27,9 +28,35 @@ public class ConfigData<T> { //TODO: Save after a while
|
|||
*/
|
||||
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")
|
||||
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) {
|
||||
T hmm = getter.apply(val);
|
||||
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);
|
||||
else val = value;
|
||||
config.set(path, val);
|
||||
this.value =value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,14 +2,19 @@ package buttondevteam.lib.architecture;
|
|||
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Members of this interface should be protected (access level)
|
||||
*/
|
||||
final class IHaveConfig {
|
||||
private IHaveConfig() {}
|
||||
public final class 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.
|
||||
|
@ -20,9 +25,9 @@ final class IHaveConfig {
|
|||
* @return The data object that can be used to get or set the value
|
||||
*/
|
||||
@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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -37,9 +42,35 @@ final class IHaveConfig {
|
|||
* @return The data object that can be used to get or set the value
|
||||
*/
|
||||
@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);
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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