feat: Test out new commentedconfiguration

This commit is contained in:
Ben Woo 2023-03-07 23:33:35 +08:00
parent e314539847
commit c76652f0a2
No known key found for this signature in database
GPG Key ID: FB2A3645536E12C8
11 changed files with 843 additions and 0 deletions

View File

@ -41,6 +41,7 @@ import com.onarandombox.MultiverseCore.commands.RemoveCommand;
import com.onarandombox.MultiverseCore.commands.TeleportCommand;
import com.onarandombox.MultiverseCore.commands.UnloadCommand;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.configuration.DefaultMVConfig;
import com.onarandombox.MultiverseCore.destination.DestinationsProvider;
import com.onarandombox.MultiverseCore.destination.core.AnchorDestination;
import com.onarandombox.MultiverseCore.destination.core.BedDestination;
@ -358,6 +359,8 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
*/
@Override
public void loadConfigs() {
new DefaultMVConfig(this);
// Now grab the Configuration Files.
this.multiverseConfig = YamlConfiguration.loadConfiguration(new File(getDataFolder(), "config.yml"));
InputStream resourceURL = this.getClass().getResourceAsStream("/defaults/config.yml");

View File

@ -0,0 +1,182 @@
package com.onarandombox.MultiverseCore.api;
public interface NewNMVConfig {
/**
* Sets firstSpawnWorld.
* @param firstSpawnWorld The new value.
*/
void setFirstSpawnWorld(String firstSpawnWorld);
/**
* Gets firstSpawnWorld.
* @return firstSpawnWorld.
*/
String getFirstSpawnWorld();
/**
* Sets version.
* @param version The new value.
*/
void setVersion(int version);
/**
* Gets version.
* @return version.
*/
double getVersion();
/**
* Sets globalDebug.
* @param globalDebug The new value.
*/
void setGlobalDebug(int globalDebug);
/**
* Gets globalDebug.
* @return globalDebug.
*/
int getGlobalDebug();
/**
* Sets displayPermErrors.
* @param displayPermErrors The new value.
*/
void setDisplayPermErrors(boolean displayPermErrors);
/**
* Gets displayPermErrors.
* @return displayPermErrors.
*/
boolean getDisplayPermErrors();
/**
* Sets firstSpawnOverride.
* @param firstSpawnOverride The new value.
*/
void setFirstSpawnOverride(boolean firstSpawnOverride);
/**
* Gets firstSpawnOverride.
* @return firstSpawnOverride.
*/
boolean getFirstSpawnOverride();
/**
* Sets teleportIntercept.
* @param teleportIntercept The new value.
*/
void setTeleportIntercept(boolean teleportIntercept);
/**
* Gets teleportIntercept.
* @return teleportIntercept.
*/
boolean getTeleportIntercept();
/**
* Sets prefixChat.
* @param prefixChat The new value.
*/
void setPrefixChat(boolean prefixChat);
/**
* Gets prefixChat.
* @return prefixChat.
*/
boolean getPrefixChat();
/**
* Sets prefixChatFormat.
* @param prefixChatFormat The new value.
*/
void setPrefixChatFormat(String prefixChatFormat);
/**
* Gets prefixChatFormat.
* @return prefixChatFormat.
*/
String getPrefixChatFormat();
/**
* Sets enforceAccess.
* @param enforceAccess The new value.
*/
void setEnforceAccess(boolean enforceAccess);
/**
* Gets enforceAccess.
* @return enforceAccess.
*/
boolean getEnforceAccess();
/**
* Sets whether to suppress startup messages.
*
* @param silentStart true to suppress messages.
*/
void setSilentStart(boolean silentStart);
/**
* Whether we are suppressing startup messages.
*
* @return true if we are suppressing startup messages.
*/
boolean getSilentStart();
/**
* Sets whether or not to let Bukkit determine portal search radius on its own or if Multiverse should give input.
*
* @param useDefaultPortalSearch True to let Bukkit determine portal search radius on its own.
*/
void setUseDefaultPortalSearch(boolean useDefaultPortalSearch);
/**
* Gets whether or not Bukkit will be determining portal search radius on its own or if Multiverse should help.
*
* @return True means Bukkit will use its own default values.
*/
boolean isUsingDefaultPortalSearch();
/**
* Sets the radius at which vanilla style portals will be searched for to connect to worlds together.
*
* @param searchRadius The portal search radius.
*/
void setPortalSearchRadius(int searchRadius);
/**
* Gets the radius at which vanilla style portals will be searched for to connect to worlds together.
*
* @return The portal search radius.
*/
int getPortalSearchRadius();
/**
* Gets whether or not the automatic purge of entities is enabled.
*
* @return True if automatic purge is enabled.
*/
boolean isAutoPurgeEnabled();
/**
* Sets whether or not the automatic purge of entities is enabled.
*
* @param autopurge True if automatic purge should be enabled.
*/
void setAutoPurgeEnabled(boolean autopurge);
/**
* Gets whether or not the donation/patreon messages are shown.
*
* @return True if donation/patreon messages should be shown.
*/
boolean isShowingDonateMessage();
/**
* Sets whether or not the donation/patreon messages are shown.
*
* @param idonotwanttodonate True if donation/patreon messages should be shown.
*/
void setShowDonateMessage(boolean idonotwanttodonate);
}

View File

@ -0,0 +1,21 @@
package com.onarandombox.MultiverseCore.configuration;
import java.nio.file.Path;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.utils.settings.MVSettings;
public class DefaultMVConfig {
private final MVSettings settings;
public DefaultMVConfig(MultiverseCore core) {
Path configPath = Path.of(core.getDataFolder().getPath(), "config2.yml");
settings = MVSettings.builder(configPath)
.logger(core.getLogger())
.defaultNodes(MVConfigNodes.getNodes())
.build();
settings.load();
settings.save();
}
}

View File

@ -0,0 +1,170 @@
package com.onarandombox.MultiverseCore.configuration;
import java.util.ArrayList;
import java.util.List;
import com.onarandombox.MultiverseCore.utils.settings.node.MVCommentedNode;
import com.onarandombox.MultiverseCore.utils.settings.node.MVValueNode;
import io.github.townyadvanced.commentedconfiguration.setting.CommentedNode;
public class MVConfigNodes {
private static final List<CommentedNode> nodes = new ArrayList<>();
public static List<CommentedNode> getNodes() {
return nodes;
}
private static <N extends CommentedNode> N node(N node) {
nodes.add(node);
return node;
}
private static final MVCommentedNode HEADER = node(MVCommentedNode.builder("world") // TODO hacky way to get the header to the top of the file
.comment("####################################################################################################")
.comment("# #")
.comment("# █▀▄▀█ █░█ █░░ ▀█▀ █ █░█ █▀▀ █▀█ █▀ █▀▀   █▀▀ █▀█ █▀█ █▀▀ #")
.comment("# █░▀░█ █▄█ █▄▄ ░█░ █ ▀▄▀ ██▄ █▀▄ ▄█ ██▄   █▄▄ █▄█ █▀▄ ██▄ #")
.comment("# #")
.comment("# #")
.comment("# WIKI: https://github.com/Multiverse/Multiverse-Core/wiki #")
.comment("# DISCORD: https://discord.gg/NZtfKky #")
.comment("# BUG REPORTS: https://github.com/Multiverse/Multiverse-Core/issues #")
.comment("# #")
.comment("# #")
.comment("# Each option in this file is documented and explained here: #")
.comment("# ==> https://github.com/Multiverse/Multiverse-Core/wiki/config.yml #")
.comment("# #")
.comment("# #")
.comment("# New options are added to this file automatically. If you manually made changes #")
.comment("# to this file while your server is running, please run `/mv reload` command. #")
.comment("# #")
.comment("####################################################################################################")
.comment("")
.comment("")
.build());
// private static final MVCommentedNode WORLD_HEADER = node(MVCommentedNode.builder("world")
// .comment("")
// .comment("")
// .build());
public static final MVValueNode<Boolean> ENFORCE_ACCESS = node(MVValueNode.builder("world.enforce-access", Boolean.class)
.comment("This setting will prevent players from entering worlds they don't have access to.")
.comment("If this is set to false, players will be able to enter any world they want.")
.comment("If this is set to true, players will only be able to enter worlds they have")
.comment("the `mv.access.<worldname>` permission.")
.defaultValue(false)
.build());
public static final MVValueNode<Boolean> ENFORCE_GAMEMODE = node(MVValueNode.builder("world.enforce-gamemode", Boolean.class)
.comment("")
.comment("Sets whether Multiverse will should enforce gamemode on world change.")
.comment("If enabled, players will be forced into the gamemode of the world they are entering, unless they have")
.comment("the `mv.bypass.gamemode.<worldname>` permission.")
.defaultValue(true)
.build());
public static final MVValueNode<Boolean> AUTO_PURGE_ENTITIES = node(MVValueNode.builder("world.auto-purge-entities", Boolean.class)
.comment("")
.comment("Sets whether Multiverse will purge mobs and entities with be automatically.")
.defaultValue(false)
.build());
public static final MVValueNode<Boolean> TELEPORT_INTERCEPT = node(MVValueNode.builder("world.teleport-intercept", Boolean.class)
.comment("")
.comment("If this is set to true, Multiverse will enforce access permissions for all teleportation,")
.comment("including teleportation from other plugins.")
.defaultValue(true)
.build());
private static final MVCommentedNode SPAWN_HEADER = node(MVCommentedNode.builder("spawn")
.comment("")
.comment("")
.build());
public static final MVValueNode<Boolean> FIRST_SPAWN_OVERRIDE = node(MVValueNode.builder("spawn.first-spawn-override", Boolean.class)
.comment("Sets whether Multiverse will override the first spawn location of a world.")
.comment("If enabled, Multiverse will set the first spawn location of a world to the spawn location of the world.")
.comment("If disabled, it will default to server.properties settings.")
.defaultValue(true)
.build());
public static final MVValueNode<String> FIRST_SPAWN_LOCATION = node(MVValueNode.builder("spawn.first-spawn-location", String.class)
.comment("")
.comment("Sets the world that Multiverse will use as the location for players that first join the server.")
.comment("This only applies if first-spawn-override is set to true.")
.defaultValue("")
.build());
private static final MVCommentedNode PORTAL_HEADER = node(MVCommentedNode.builder("portal")
.comment("")
.comment("")
.build());
public static final MVValueNode<Boolean> USE_CUSTOM_PORTAL_SEARCH = node(MVValueNode.builder("portal.use-custom-portal-search", Boolean.class)
.comment("This config option defines whether or not Multiverse should interfere with's Bukkit's default portal search radius.")
.comment("Setting it to false would mean you want to simply let Bukkit decides the search radius itself.")
.defaultValue(false)
.build());
public static final MVValueNode<Integer> CUSTOM_PORTAL_SEARCH_RADIUS = node(MVValueNode.builder("portal.custom-portal-search-radius", Integer.class)
.comment("")
.comment("This config option defines the search radius Multiverse should use when searching for a portal.")
.comment("This only applies if use-custom-portal-search is set to true.")
.defaultValue(128)
.build());
private static final MVCommentedNode MESSAGING_HEADER = node(MVCommentedNode.builder("messaging")
.comment("")
.comment("")
.build());
public static final MVValueNode<Boolean> ENABLE_CHAT_PREFIX = node(MVValueNode.builder("messaging.enable-chat-prefix", Boolean.class)
.comment("This config option defines whether or not Multiverse should prefix the chat with the world name.")
.comment("This only applies if use-custom-portal-search is set to true.")
.defaultValue(false)
.build());
public static final MVValueNode<String> CHAT_PREFIX_FORMAT = node(MVValueNode.builder("messaging.chat-prefix-format", String.class)
.comment("")
.comment("This config option defines the format Multiverse should use when prefixing the chat with the world name.")
.comment("This only applies if enable-chat-prefix is set to true.")
.defaultValue("[%world%]%chat%")
.build());
private static final MVCommentedNode MISC_HEADER = node(MVCommentedNode.builder("misc")
.comment("")
.comment("")
.build());
public static final MVValueNode<Integer> GLOBAL_DEBUG = node(MVValueNode.builder("misc.global-debug", Integer.class)
.comment("This is our debug flag to help identify issues with Multiverse.")
.comment("If you are having issues with Multiverse, please set this to 3 and then post your log to pastebin.com")
.comment("Otherwise, there's no need to touch this. If not instructed by a wiki page or developer.")
.comment(" 0 = Off, No debug messages")
.comment(" 1 = fine")
.comment(" 2 = finer")
.comment(" 3 = finest")
.defaultValue(0)
.build());
public static final MVValueNode<Boolean> SLIENT_START = node(MVValueNode.builder("misc.silent-start", Boolean.class)
.comment("")
.comment("If true, the startup console messages will no longer show.")
.defaultValue(false)
.build());
public static final MVValueNode<Boolean> I_DONT_WANT_TO_DONATE = node(MVValueNode.builder("misc.i-dont-want-to-donate", Boolean.class)
.comment("")
.comment("If you don't want to donate, you can set this to true and Multiverse will stop nagging you.")
.defaultValue(false)
.build());
public static final MVValueNode<Double> VERSION = node(MVValueNode.builder("version", Double.class)
.comment("")
.comment("")
.comment("This just signifies the version number so we can see what version of config you have.")
.comment("NEVER TOUCH THIS VALUE")
.defaultValue(5.0D)
.build());
}

View File

@ -0,0 +1,209 @@
package com.onarandombox.MultiverseCore.utils.settings;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;
import com.dumptruckman.minecraft.util.Logging;
import com.google.common.base.Strings;
import io.github.townyadvanced.commentedconfiguration.CommentedConfiguration;
import io.github.townyadvanced.commentedconfiguration.setting.CommentedNode;
import io.github.townyadvanced.commentedconfiguration.setting.TypedValueNode;
import io.github.townyadvanced.commentedconfiguration.setting.ValueNode;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.FileConfigurationOptions;
import org.bukkit.configuration.file.YamlConfigurationOptions;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class MVSettings {
public static Builder builder(String configPath) {
return new Builder(configPath);
}
public static Builder builder(Path configPath) {
return new Builder(configPath);
}
protected final Path configPath;
protected final Logger logger;
protected final List<CommentedNode> defaultNodes;
protected CommentedConfiguration config;
/**
* Creates a new MVSettings instance that makes use of CommentedConfiguration.
*
* @param configPath The path to the configuration file.
* @param logger The Logger to use for error messages.
* @param defaultNodes The default node values to add to the configuration.
*/
protected MVSettings(@NotNull Path configPath, @Nullable Logger logger, @Nullable List<CommentedNode> defaultNodes) {
this.configPath = configPath;
this.defaultNodes = defaultNodes;
this.logger = logger;
}
/**
* Loads the configuration.
*
* @return True if the configuration was loaded successfully, false otherwise.
*/
public boolean load() {
if (!createConfigFile()) {
return false;
}
this.config = new CommentedConfiguration(configPath, logger);
if (!config.load()) {
return false;
}
addDefaultNodes();
return true;
}
/**
* Create a new config file if file does not exist
*
* @return True if file exist or created successfully, otherwise false.
*/
protected boolean createConfigFile() {
File configFile = configPath.toFile();
if (configFile.exists()) {
return true;
}
try {
if (!configFile.createNewFile()) {
return false;
}
} catch (IOException e) {
return false;
}
return true;
}
/**
* Adds default node values to the configuration if they are not already present.
*/
protected void addDefaultNodes() {
if (defaultNodes == null || defaultNodes.isEmpty()) {
return;
}
CommentedConfiguration tempConfig = new CommentedConfiguration(configPath, logger);
for (CommentedNode node : defaultNodes) {
if (node.getComments().length > 0) {
tempConfig.addComment(node.getPath(), node.getComments());
}
if (node instanceof ValueNode) {
ValueNode valueNode = (ValueNode) node;
tempConfig.set(node.getPath(), get(valueNode));
}
}
this.config = tempConfig;
}
/**
* Saves the configuration.
*/
public void save() {
config.save();
}
/**
* Gets the value of a node, if the node has a default value, it will be returned if the node is not found.
*
* @param node The node to get the value of.
* @return The value of the node.
*/
public Object get(@NotNull ValueNode node) {
return config.get(node.getPath(), node.getDefaultValue());
}
/**
* Gets the value of a node, if the node has a default value, it will be returned if the node is not found.
*
* @param node The node to get the value of.
* @param type The type of the node value.
* @param <T> The type of the node value.
* @return The value of the node.
*/
public <T> T get(@NotNull ValueNode node, Class<T> type) {
return config.getObject(node.getPath(), type, (T) node.getDefaultValue());
}
/**
* Gets the value of a node, if the node has a default value, it will be returned if the node is not found.
*
* @param node The node to get the value of.
* @param <T> The type of the node value.
* @return The value of the node.
*/
public <T> T get(@NotNull TypedValueNode<T> node) {
return config.getObject(node.getPath(), node.getType(), node.getDefaultValue());
}
/**
* Sets the value of a node, if the validator is not null, it will be tested first.
*
* @param node The node to set the value of.
* @param value The value to set.
*/
public void set(@NotNull ValueNode node, Object value) {
config.set(node.getPath(), value);
}
/**
* Sets the value of a node, if the validator is not null, it will be tested first.
*
* @param node The node to set the value of.
* @param value The value to set.
* @param <T> The type of the node value.
*/
public <T> void set(@NotNull TypedValueNode<T> node, T value) {
config.set(node.getPath(), value);
}
/**
* Gets the configuration object.
*
* @return The configuration object.
*/
public @NotNull CommentedConfiguration getConfig() {
return config;
}
public static class Builder {
private final Path configPath;
private Logger logger;
private List<CommentedNode> defaultNodes;
public Builder(String configPath) {
this.configPath = Path.of(configPath);
}
public Builder(Path configPath) {
this.configPath = configPath;
}
public Builder logger(@Nullable Logger logger) {
this.logger = logger;
return this;
}
public Builder defaultNodes(@Nullable List<CommentedNode> defaultNodes) {
this.defaultNodes = defaultNodes;
return this;
}
public MVSettings build() {
return new MVSettings(configPath, logger, defaultNodes);
}
}
}

View File

@ -0,0 +1,38 @@
package com.onarandombox.MultiverseCore.utils.settings.migration;
import java.util.ArrayList;
import java.util.List;
import com.onarandombox.MultiverseCore.utils.settings.MVSettings;
public class MigrateVersion {
private final double version;
private final List<MigratorAction> actions;
protected MigrateVersion(double version, List<MigratorAction> actions) {
this.version = version;
this.actions = actions;
}
public void migrate(MVSettings settings) {
actions.forEach(action -> action.migrate(settings));
}
public static class Builder {
private final double version;
private final List<MigratorAction> actions = new ArrayList<>();
public Builder(double version) {
this.version = version;
}
public Builder addAction(MigratorAction action) {
actions.add(action);
return this;
}
public MigrateVersion build() {
return new MigrateVersion(version, actions);
}
}
}

View File

@ -0,0 +1,7 @@
package com.onarandombox.MultiverseCore.utils.settings.migration;
import com.onarandombox.MultiverseCore.utils.settings.MVSettings;
public interface MigratorAction {
void migrate(MVSettings settings);
}

View File

@ -0,0 +1,21 @@
package com.onarandombox.MultiverseCore.utils.settings.migration;
import com.onarandombox.MultiverseCore.utils.settings.MVSettings;
public class MoveMigratorAction implements MigratorAction {
private final String fromPath;
private final String toPath;
public MoveMigratorAction(String fromPath, String toPath) {
this.fromPath = fromPath;
this.toPath = toPath;
}
@Override
public void migrate(MVSettings settings) {
Object value = settings.getConfig().get(fromPath);
if (value != null) {
settings.getConfig().set(toPath, value);
}
}
}

View File

@ -0,0 +1,55 @@
package com.onarandombox.MultiverseCore.utils.settings.node;
import java.util.ArrayList;
import java.util.List;
import io.github.townyadvanced.commentedconfiguration.setting.CommentedNode;
import org.jetbrains.annotations.NotNull;
public class MVCommentedNode implements CommentedNode {
public static <T> Builder<Builder> builder(String path) {
return new Builder<>(path);
}
protected final String path;
protected final String[] comments;
protected MVCommentedNode(String path, String[] comments) {
this.path = path;
this.comments = comments;
}
@Override
public @NotNull String getPath() {
return path;
}
@Override
public @NotNull String[] getComments() {
return comments;
}
public static class Builder<B extends Builder> {
protected final String path;
protected final List<String> comments;
protected Builder(String path) {
this.path = path;
this.comments = new ArrayList<>();
}
public B comment(@NotNull String comment) {
if (!comment.isEmpty() && !comment.trim().startsWith("#")) {
// Automatically add a comment prefix if the comment doesn't start with one.
comment = "# " + comment;
}
this.comments.add(comment);
return (B) this;
}
public MVCommentedNode build() {
return new MVCommentedNode(path, comments.toArray(new String[0]));
}
}
}

View File

@ -0,0 +1,53 @@
package com.onarandombox.MultiverseCore.utils.settings.node;
import io.github.townyadvanced.commentedconfiguration.setting.TypedValueNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class MVValueNode<T> extends MVCommentedNode implements TypedValueNode<T> {
public static <T> Builder<T, ? extends Builder> builder(String path, Class<T> type) {
return new Builder<>(path, type);
}
protected final Class<T> type;
private final T defaultValue;
protected MVValueNode(String path, String[] comments, Class<T> type, T defaultValue) {
super(path, comments);
this.type = type;
this.defaultValue = defaultValue;
}
@Override
public @NotNull Class<T> getType() {
return type;
}
@Override
public @Nullable T getDefaultValue() {
return defaultValue;
}
public static class Builder<T, B extends Builder<T, B>> extends MVCommentedNode.Builder<B> {
protected final Class<T> type;
protected T defaultValue;
public Builder(String path, Class<T> type) {
super(path);
this.type = type;
}
public B defaultValue(T defaultValue) {
this.defaultValue = defaultValue;
return (B) this;
}
@Override
public MVValueNode<T> build() {
return new MVValueNode<>(path, comments.toArray(new String[0]), type, defaultValue);
}
}
}

View File

@ -0,0 +1,84 @@
package com.onarandombox.MultiverseCore.utils.settings.node;
import java.util.Collection;
import java.util.Iterator;
import io.github.townyadvanced.commentedconfiguration.setting.CommentedNode;
import org.jetbrains.annotations.NotNull;
public class NodesCollection implements Collection<CommentedNode> {
private final Collection<CommentedNode> nodes;
public NodesCollection(Collection<CommentedNode> nodes) {
this.nodes = nodes;
}
@Override
public int size() {
return nodes.size();
}
@Override
public boolean isEmpty() {
return nodes.isEmpty();
}
@Override
public boolean contains(Object o) {
return nodes.contains(o);
}
@NotNull
@Override
public Iterator<CommentedNode> iterator() {
return nodes.iterator();
}
@NotNull
@Override
public Object[] toArray() {
return nodes.toArray();
}
@NotNull
@Override
public <T> T[] toArray(@NotNull T[] ts) {
return nodes.toArray(ts);
}
@Override
public boolean add(CommentedNode commentedNode) {
return nodes.add(commentedNode);
}
@Override
public boolean remove(Object o) {
return nodes.remove(o);
}
@Override
public boolean containsAll(@NotNull Collection<?> collection) {
return nodes.containsAll(collection);
}
@Override
public boolean addAll(@NotNull Collection<? extends CommentedNode> collection) {
return nodes.addAll(collection);
}
@Override
public boolean removeAll(@NotNull Collection<?> collection) {
return nodes.removeAll(collection);
}
@Override
public boolean retainAll(@NotNull Collection<?> collection) {
return nodes.retainAll(collection);
}
@Override
public void clear() {
nodes.clear();
}
}