From 91a116ced2075030ecde9bd08102d0cd7dba31a4 Mon Sep 17 00:00:00 2001 From: Ben Woo <30431861+benwoo1110@users.noreply.github.com> Date: Fri, 31 Jan 2025 21:07:42 +0800 Subject: [PATCH] Move inventories config to use new config api --- .../inventories/MultiverseInventories.java | 7 +- .../inventories/commands/ToggleCommand.java | 8 +- .../inventories/config/InventoriesConfig.java | 265 ++++-------------- .../config/InventoriesConfigNodes.java | 119 ++++++++ 4 files changed, 186 insertions(+), 213 deletions(-) create mode 100644 src/main/java/org/mvplugins/multiverse/inventories/config/InventoriesConfigNodes.java diff --git a/src/main/java/org/mvplugins/multiverse/inventories/MultiverseInventories.java b/src/main/java/org/mvplugins/multiverse/inventories/MultiverseInventories.java index 8e5f5645..f4ade941 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/MultiverseInventories.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/MultiverseInventories.java @@ -86,6 +86,7 @@ public void onLoad() { public final void onEnable() { super.onEnable(); initializeDependencyInjection(); + inventoriesConfig.get().load().onFailure(e -> Logging.severe(e.getMessage())); Logging.setDebugLevel(mvCoreConfig.get().getGlobalDebug()); this.onMVPluginEnable(); @@ -206,6 +207,10 @@ public PluginServiceLocator getServiceLocator() { @Override public void reloadConfig() { try { + inventoriesConfig.get().load().onFailure(e -> { + Logging.severe("Failed to load config file!"); + Logging.severe(e.getMessage()); + }); worldGroupManager.get().load().onFailure(e -> { Logging.severe("Failed to load world groups!"); Logging.severe(e.getMessage()); @@ -216,7 +221,7 @@ public void reloadConfig() { profileDataSource.get().clearAllCache(); } - Logging.fine("Loaded config file!"); + Logging.fine("Reloaded all config and groups!"); } catch (Exception e) { // Catch errors loading the config file and exit out if found. Logging.severe(this.getMessager().getMessage(Message.ERROR_CONFIG_LOAD)); Logging.severe(e.getMessage()); diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/ToggleCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/ToggleCommand.java index 1348a895..414a41bc 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/commands/ToggleCommand.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/ToggleCommand.java @@ -56,19 +56,21 @@ void onToggleCommand( return; } boolean foundOpt = false; + Shares optionalShares = inventoriesConfig.getOptionalShares(); for (Sharable sharable : shares) { if (sharable.isOptional()) { foundOpt = true; - if (inventoriesConfig.getOptionalShares().contains(sharable)) { - inventoriesConfig.getOptionalShares().remove(sharable); + if (optionalShares.contains(sharable)) { + optionalShares.remove(sharable); this.plugin.getMessager().normal(Message.NOW_NOT_USING_OPTIONAL, sender, sharable.getNames()[0]); } else { - inventoriesConfig.getOptionalShares().add(sharable); + optionalShares.add(sharable); this.plugin.getMessager().normal(Message.NOW_USING_OPTIONAL, sender, sharable.getNames()[0]); } } } if (foundOpt) { + inventoriesConfig.setOptionalShares(optionalShares); inventoriesConfig.save(); } else { this.plugin.getMessager().normal(Message.NO_OPTIONAL_SHARES, sender, shareName); diff --git a/src/main/java/org/mvplugins/multiverse/inventories/config/InventoriesConfig.java b/src/main/java/org/mvplugins/multiverse/inventories/config/InventoriesConfig.java index 0c0ef631..616c4298 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/config/InventoriesConfig.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/config/InventoriesConfig.java @@ -2,20 +2,17 @@ import com.dumptruckman.minecraft.util.Logging; import org.jvnet.hk2.annotations.Service; -import org.mvplugins.multiverse.core.config.MVCoreConfig; -import org.mvplugins.multiverse.external.commentedconfiguration.CommentedConfiguration; +import org.mvplugins.multiverse.core.configuration.handle.CommentedConfigurationHandle; +import org.mvplugins.multiverse.core.configuration.handle.StringPropertyHandle; import org.mvplugins.multiverse.external.jakarta.inject.Inject; +import org.mvplugins.multiverse.external.vavr.control.Try; import org.mvplugins.multiverse.inventories.MultiverseInventories; import org.mvplugins.multiverse.inventories.share.Sharable; -import org.mvplugins.multiverse.inventories.share.Sharables; import org.mvplugins.multiverse.inventories.share.Shares; import org.bukkit.configuration.file.FileConfiguration; -import java.io.File; import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.nio.file.Path; /** * Provides methods for interacting with the configuration of Multiverse-Inventories. @@ -23,180 +20,32 @@ @Service public final class InventoriesConfig { - /** - * Enum for easily keeping track of config paths, defaults and comments. - */ - public enum Path { - /** - * Locale name config path, default and comments. - */ - LANGUAGE_FILE_NAME("settings.locale", "en", "# This is the locale you wish to use."), - /** - * First Run flag config path, default and comments. - */ - FIRST_RUN("settings.first_run", true, "# If this is true it will generate world groups for you based on MV worlds."), - /** - * First Run flag config path, default and comments. - */ - USE_BYPASS("settings.use_bypass", false, "# If this is set to true, it will enable bypass permissions (Check the wiki for more info.)"), - - /** - * Whether or not to make ungrouped worlds use the default group. - */ - DEFAULT_UNGROUPED_WORLDS("settings.default_ungrouped_worlds", false, "# If set to true, any world not listed in a group will automatically use the settings for the default group!"), - - /** - * Whether or not to save/load player data on log out/in. - */ - LOGGING_SAVE_LOAD("settings.save_load_on_log_in_out", false, - "# The default and suggested setting for this is FALSE.", - "# False means Multiverse-Inventories will not attempt to load or save any player data when they log in and out.", - "# That means that MINECRAFT will handle that exact thing JUST LIKE IT DOES NORMALLY.", - "# Changing this to TRUE will have Multiverse-Inventories save player data when they log out and load it when they log in.", - "# The biggest potential drawback here is that if your server crashes, player stats/inventories may be lost/rolled back!"), - - USE_OPTIONALS_UNGROUPED("shares.optionals_for_ungrouped_worlds", true, - "# When set to true, optional shares WILL be utilized in cases where a group does not cover their uses for a world.", - "# An example of this in action would be an ungrouped world using last_location. When this is true, players will return to their last location in that world.", - "# When set to false, optional shares WILL NOt be utilized in these cases, effectively disabling it for ungrouped worlds."), - /** - * First Run flag config path, default and comments. - */ - OPTIONAL_SHARES("shares.use_optionals", new ArrayList(), - "# You must specify optional shares you wish to use here or they will be ignored.", - "# The only built in optional shares are \"economy\" and \"last_location\"."), - /** - * Whether or not to split data based on game modes. - */ - USE_GAME_MODE_PROFILES("settings.use_game_mode_profiles", false, - "# If this is set to true, players will have different inventories/stats for each game mode.", - "# Please note that old data migrated to the version that has this feature will have their data copied for both game modes."); - - private String path; - private Object def; - private List comments; - - Path(String path, Object def, String... comments) { - this.path = path; - this.def = def; - this.comments = Arrays.asList(comments); - } - - /** - * Retrieves the path for a config option. - * - * @return The path for a config option. - */ - private String getPath() { - return this.path; - } - - /** - * Retrieves the default value for a config path. - * - * @return The default value for a config path. - */ - private Object getDefault() { - return this.def; - } - - /** - * Retrieves the comment for a config path. - * - * @return The comments for a config path. - */ - private List getComments() { - return this.comments; - } - } + public static final String CONFIG_FILENAME = "config.yml"; - private final CommentedConfiguration config; - private final MultiverseInventories plugin; - private final MVCoreConfig mvCoreConfig; + private final InventoriesConfigNodes configNodes; + private final CommentedConfigurationHandle configHandle; + private final StringPropertyHandle stringPropertyHandle; @Inject - InventoriesConfig(MultiverseInventories plugin, MVCoreConfig mvCoreConfig) throws IOException { - this.plugin = plugin; - this.mvCoreConfig = mvCoreConfig; - // Make the data folders - if (plugin.getDataFolder().mkdirs()) { - Logging.fine("Created data folder."); - } - - // Check if the config file exists. If not, create it. - File configFile = new File(plugin.getDataFolder(), "config.yml"); - boolean configFileExists = configFile.exists(); - if (!configFileExists) { - Logging.fine("Created config file."); - configFile.createNewFile(); - } - - // Load the configuration file into memory - config = new CommentedConfiguration(configFile.toPath()); - config.load(); - - // Sets defaults config values - this.setDefaults(); - - config.addComment("settings", "# Multiverse-Inventories Settings", ""); - - // Saves the configuration from memory to file - config.save(); - - Logging.setDebugLevel(this.getGlobalDebug()); + InventoriesConfig(MultiverseInventories inventories) throws IOException { + this.configNodes = new InventoriesConfigNodes(); + var configPath = Path.of(inventories.getDataFolder().getPath(), CONFIG_FILENAME); + this.configHandle = CommentedConfigurationHandle.builder(configPath, this.configNodes.getNodes()) + .logger(Logging.getLogger()) + .build(); + this.stringPropertyHandle = new StringPropertyHandle(this.configHandle); } - - /** - * Loads default settings for any missing config values. - */ - private void setDefaults() { - for (InventoriesConfig.Path path : InventoriesConfig.Path.values()) { - config.addComment(path.getPath(), path.getComments().toArray(new String[0])); - if (this.getConfig().get(path.getPath()) == null) { - if (path.getDefault() != null) { - Logging.fine("Config: Defaulting '" + path.getPath() + "' to " + path.getDefault()); - this.getConfig().set(path.getPath(), path.getDefault()); - } else { - this.getConfig().createSection(path.getPath()); - } - } - } - - } - - private Boolean getBoolean(Path path) { - return this.getConfig().getBoolean(path.getPath(), (Boolean) path.getDefault()); - } - - private Integer getInt(Path path) { - return this.getConfig().getInt(path.getPath(), (Integer) path.getDefault()); - } - - private String getString(Path path) { - return this.getConfig().getString(path.getPath(), (String) path.getDefault()); + public Try load() { + return this.configHandle.load(); } public FileConfiguration getConfig() { - return this.config; + return this.configHandle.getConfig(); } - /** - * Sets globalDebug level. - * - * @param globalDebug The new value. 0 = off. - */ - public void setGlobalDebug(int globalDebug) { - mvCoreConfig.setGlobalDebug(globalDebug); - } - - /** - * Gets globalDebug level. - * - * @return globalDebug. - */ - public int getGlobalDebug() { - return mvCoreConfig.getGlobalDebug(); + public StringPropertyHandle getStringPropertyHandle() { + return stringPropertyHandle; } /** @@ -205,7 +54,11 @@ public int getGlobalDebug() { * @return The locale string. */ public String getLocale() { - return this.getString(Path.LANGUAGE_FILE_NAME); + return this.configHandle.get(configNodes.locale); + } + + public Try setLocale(String locale) { + return this.configHandle.set(configNodes.locale, locale); } /** @@ -214,7 +67,7 @@ public String getLocale() { * @return True if first_run is set to true in config. */ public boolean isFirstRun() { - return this.getBoolean(Path.FIRST_RUN); + return this.configHandle.get(configNodes.firstRun); } /** @@ -222,22 +75,22 @@ public boolean isFirstRun() { * * @param firstRun What to set the flag to in the config. */ - public void setFirstRun(boolean firstRun) { - this.getConfig().set(Path.FIRST_RUN.getPath(), firstRun); + public Try setFirstRun(boolean firstRun) { + return this.configHandle.set(configNodes.firstRun, firstRun); } /** * @return True if we should check for bypass permissions. */ public boolean isUsingBypass() { - return this.getBoolean(Path.USE_BYPASS); + return this.configHandle.get(configNodes.useBypass); } /** * @param useBypass Whether or not to check for bypass permissions. */ - public void setUsingBypass(boolean useBypass) { - this.getConfig().set(Path.USE_BYPASS.getPath(), useBypass); + public Try setUsingBypass(boolean useBypass) { + return this.configHandle.set(configNodes.useBypass, useBypass); } /** @@ -246,7 +99,7 @@ public void setUsingBypass(boolean useBypass) { * @return True if should save and load on player log out and in. */ public boolean usingLoggingSaveLoad() { - return this.getBoolean(Path.LOGGING_SAVE_LOAD); + return this.configHandle.get(configNodes.loggingSaveLoad); } /** @@ -254,12 +107,10 @@ public boolean usingLoggingSaveLoad() { * * @param useLoggingSaveLoad true if should save and load on player log out and in. */ - public void setUsingLoggingSaveLoad(boolean useLoggingSaveLoad) { - this.getConfig().set(Path.LOGGING_SAVE_LOAD.getPath(), useLoggingSaveLoad); + public Try setUsingLoggingSaveLoad(boolean useLoggingSaveLoad) { + return this.configHandle.set(configNodes.loggingSaveLoad, useLoggingSaveLoad); } - private Shares optionalSharables = null; - /** * @return A list of optional {@link Sharable}s to be treated as * regular {@link Sharable}s throughout the code. @@ -267,44 +118,45 @@ public void setUsingLoggingSaveLoad(boolean useLoggingSaveLoad) { * contained in this list. */ public Shares getOptionalShares() { - if (this.optionalSharables == null) { - List list = this.getConfig().getList(Path.OPTIONAL_SHARES.getPath()); - if (list != null) { - this.optionalSharables = Sharables.fromList(list); - } else { - Logging.warning("'" + Path.OPTIONAL_SHARES.getPath() + "' is setup incorrectly!"); - this.optionalSharables = Sharables.noneOf(); - } - } - return this.optionalSharables; + return this.configHandle.get(configNodes.optionalShares); + } + + /** + * Sets the optional shares to be used. + * + * @param shares The optional shares to be used. + * @return True if successful. + */ + public Try setOptionalShares(Shares shares) { + return this.configHandle.set(configNodes.optionalShares, shares); } /** * @return true if worlds with no group should be considered part of the default group. */ public boolean isDefaultingUngroupedWorlds() { - return this.getBoolean(Path.DEFAULT_UNGROUPED_WORLDS); + return this.configHandle.get(configNodes.defaultUngroupedWorlds); } /** * @param useDefaultGroup Set this to true to use the default group for ungrouped worlds. */ - public void setDefaultingUngroupedWorlds(boolean useDefaultGroup) { - this.getConfig().set(Path.FIRST_RUN.getPath(), useDefaultGroup); + public Try setDefaultingUngroupedWorlds(boolean useDefaultGroup) { + return this.configHandle.set(configNodes.defaultUngroupedWorlds, useDefaultGroup); } /** * @return True if using separate data for game modes. */ public boolean isUsingGameModeProfiles() { - return this.getBoolean(Path.USE_GAME_MODE_PROFILES); + return this.configHandle.get(configNodes.useGameModeProfiles); } /** * @param useGameModeProfile whether to use separate data for game modes. */ - public void setUsingGameModeProfiles(boolean useGameModeProfile) { - this.getConfig().set(Path.USE_GAME_MODE_PROFILES.getPath(), useGameModeProfile); + public Try setUsingGameModeProfiles(boolean useGameModeProfile) { + return this.configHandle.set(configNodes.useGameModeProfiles, useGameModeProfile); } /** @@ -313,7 +165,7 @@ public void setUsingGameModeProfiles(boolean useGameModeProfile) { * @return true if should utilize optional shares in worlds that are not grouped. */ public boolean usingOptionalsForUngrouped() { - return this.getBoolean(Path.USE_OPTIONALS_UNGROUPED); + return this.configHandle.get(configNodes.useOptionalsForUngrouped); } /** @@ -321,20 +173,15 @@ public boolean usingOptionalsForUngrouped() { * * @param usingOptionalsForUngrouped true if should utilize optional shares in worlds that are not grouped. */ - public void setUsingOptionalsForUngrouped(final boolean usingOptionalsForUngrouped) { - this.getConfig().set(Path.USE_OPTIONALS_UNGROUPED.getPath(), usingOptionalsForUngrouped); + public Try setUsingOptionalsForUngrouped(final boolean usingOptionalsForUngrouped) { + return this.configHandle.set(configNodes.useOptionalsForUngrouped, usingOptionalsForUngrouped); } /** * Saves the configuration file to disk. */ - // TODO remove need for this method. - // TODO Figure out what I meant by the above todo message... - public void save() { - if (this.optionalSharables != null) { - this.getConfig().set(Path.OPTIONAL_SHARES.getPath(), this.optionalSharables.toStringList()); - } - this.config.save(); + public Try save() { + return this.configHandle.save(); } } diff --git a/src/main/java/org/mvplugins/multiverse/inventories/config/InventoriesConfigNodes.java b/src/main/java/org/mvplugins/multiverse/inventories/config/InventoriesConfigNodes.java new file mode 100644 index 00000000..8f701531 --- /dev/null +++ b/src/main/java/org/mvplugins/multiverse/inventories/config/InventoriesConfigNodes.java @@ -0,0 +1,119 @@ +package org.mvplugins.multiverse.inventories.config; + +import org.mvplugins.multiverse.core.configuration.functions.NodeSerializer; +import org.mvplugins.multiverse.core.configuration.node.ConfigHeaderNode; +import org.mvplugins.multiverse.core.configuration.node.ConfigNode; +import org.mvplugins.multiverse.core.configuration.node.Node; +import org.mvplugins.multiverse.core.configuration.node.NodeGroup; +import org.mvplugins.multiverse.inventories.share.Sharables; +import org.mvplugins.multiverse.inventories.share.Shares; + +import java.util.List; +import java.util.Objects; + +final class InventoriesConfigNodes { + + private final NodeGroup nodes = new NodeGroup(); + + InventoriesConfigNodes() { + } + + NodeGroup getNodes() { + return nodes; + } + + private N node(N node) { + nodes.add(node); + return node; + } + + private final ConfigHeaderNode settingsHeader = node(ConfigHeaderNode.builder("settings") + .comment("#######################################") + .comment("# Settings for Multiverse-Inventories #") + .comment("#######################################") + .comment("") + .comment("") + .build()); + + final ConfigNode locale = node(ConfigNode.builder("settings.locale", String.class) + .comment("This is the locale you wish to use.") + .defaultValue("en") + .name("locale") + .build()); + + final ConfigNode firstRun = node(ConfigNode.builder("settings.first_run", Boolean.class) + .comment("") + .comment("If this is true it will generate world groups for you based on MV worlds.") + .defaultValue(true) + .name(null) + .build()); + + final ConfigNode useBypass = node(ConfigNode.builder("settings.use_bypass", Boolean.class) + .comment("") + .comment("If this is set to true, it will enable bypass permissions (Check the wiki for more info.)") + .defaultValue(false) + .name("use-bypass") + .build()); + + final ConfigNode defaultUngroupedWorlds = node(ConfigNode.builder("settings.default_ungrouped_worlds", Boolean.class) + .comment("") + .comment("If set to true, any world not listed in a group will automatically use the settings for the default group!") + .defaultValue(false) + .name("default-ungrouped-worlds") + .build()); + + final ConfigNode loggingSaveLoad = node(ConfigNode.builder("settings.save_load_on_log_in_out", Boolean.class) + .comment("") + .comment("The default and suggested setting for this is FALSE.") + .comment("False means Multiverse-Inventories will not attempt to load or save any player data when they log in and out.") + .comment("That means that MINECRAFT will handle that exact thing JUST LIKE IT DOES NORMALLY.") + .comment("Changing this to TRUE will have Multiverse-Inventories save player data when they log out and load it when they log in.") + .comment("The biggest potential drawback here is that if your server crashes, player stats/inventories may be lost/rolled back!") + .defaultValue(false) + .name("save-load-on-log-in-out") + .build()); + + private final ConfigHeaderNode sharesHeader = node(ConfigHeaderNode.builder("shares") + .comment("") + .comment("") + .build()); + + + final ConfigNode useOptionalsForUngrouped = node(ConfigNode.builder("shares.optionals_for_ungrouped_worlds", Boolean.class) + .comment("When set to true, optional shares WILL be utilized in cases where a group does not cover their uses for a world.") + .comment("An example of this in action would be an ungrouped world using last_location. When this is true, players will return to their last location in that world.") + .comment("When set to false, optional shares WILL NOT be utilized in these cases, effectively disabling it for ungrouped worlds.") + .defaultValue(true) + .name("optionals-for-ungrouped-worlds") + .build()); + + final ConfigNode optionalShares = node(ConfigNode.builder("shares.use_optionals", Shares.class) + .comment("") + .comment("You must specify optional shares you wish to use here or they will be ignored.") + .comment("The only built-in optional shares are \"economy\" and \"last_location\".") + .defaultValue(Sharables.noneOf()) + .name(null) + .serializer(new NodeSerializer<>() { + @Override + public Shares deserialize(Object o, Class aClass) { + if (o instanceof List) { + return Sharables.fromList((List) o); + } + return Sharables.fromList(List.of(Objects.toString(o))); + } + + @Override + public Object serialize(Shares sharables, Class aClass) { + return sharables.toStringList(); + } + }) + .build()); + + final ConfigNode useGameModeProfiles = node(ConfigNode.builder("settings.use_game_mode_profiles", Boolean.class) + .comment("") + .comment("If this is set to true, players will have different inventories/stats for each game mode.") + .comment("Please note that old data migrated to the version that has this feature will have their data copied for both game modes.") + .defaultValue(false) + .name("use-game-mode-profiles") + .build()); +}