Merge pull request #2895 from Multiverse/revamp-config

Revamp config
This commit is contained in:
Jeremy Wood 2023-03-30 01:05:27 -04:00 committed by GitHub
commit b8c95dc71a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 2159 additions and 716 deletions

View File

@ -91,7 +91,7 @@ dependencies {
relocatedApi('me.main__.util:SerializationConfig:1.7') {
exclude group: 'org.bukkit', module: 'bukkit'
}
relocatedApi('io.github.townyadvanced.commentedconfiguration:CommentedConfiguration:1.0.0') {
relocatedApi('io.github.townyadvanced.commentedconfiguration:CommentedConfiguration:1.0.1') {
exclude group: 'org.spigotmc', module: 'spigot-api'
}

View File

@ -12,6 +12,7 @@ import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import com.dumptruckman.minecraft.util.Logging;
@ -23,7 +24,7 @@ import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.commandtools.PluginLocales;
import com.onarandombox.MultiverseCore.config.MVCoreConfigProvider;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.destination.DestinationsProvider;
import com.onarandombox.MultiverseCore.economy.MVEconomist;
import com.onarandombox.MultiverseCore.inject.InjectableListener;
@ -55,7 +56,7 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
private ServiceLocator serviceLocator;
@Inject
private MVCoreConfigProvider configProvider;
private MVCoreConfig config;
@Inject
private Provider<MVWorldManager> worldManagerProvider;
@Inject
@ -90,7 +91,6 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
Logging.init(this);
// Register our config classes
SerializationConfig.registerAll(MultiverseCoreConfiguration.class);
SerializationConfig.registerAll(WorldProperties.class);
SerializationConfig.initLogging(Logging.getLogger());
}
@ -103,8 +103,7 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
initializeDependencyInjection();
// Load our configs first as we need them for everything else.
this.loadConfigs();
if (!getConfigProvider().isConfigLoaded()) {
if (config == null || !config.isLoaded()) {
Logging.severe("Your configs were not loaded.");
Logging.severe("Please check your configs and restart the server.");
this.getServer().getPluginManager().disablePlugin(this);
@ -115,15 +114,16 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
var worldManager = worldManagerProvider.get();
worldManager.loadWorldsConfig();
worldManager.getDefaultWorldGenerators();
worldManager.loadDefaultWorlds();
worldManager.loadWorlds(true);
// Now set the firstspawnworld (after the worlds are loaded):
worldManager.setFirstSpawnWorld(getConfigProvider().getConfig().getFirstSpawnWorld());
worldManager.setFirstSpawnWorld(config.getFirstSpawnLocation());
MVWorld firstSpawnWorld = worldManager.getFirstSpawnWorld();
if (firstSpawnWorld != null) {
getConfigProvider().getConfig().setFirstSpawnWorld(firstSpawnWorld.getName());
config.setFirstSpawnLocation(firstSpawnWorld.getName());
}
//Setup economy here so vault is loaded
@ -137,7 +137,7 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
this.registerDestinations();
this.setupMetrics();
this.loadPlaceholderAPIIntegration();
this.saveMVConfig();
this.saveAllConfigs();
this.logEnableMessage();
}
@ -171,7 +171,7 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
}
private boolean shouldShowConfig() {
return !getConfigProvider().getConfig().getSilentStart();
return !config.getSilentStart();
}
private void loadEconomist() {
@ -275,14 +275,15 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
private void logEnableMessage() {
Logging.config("Version %s (API v%s) Enabled - By %s", this.getDescription().getVersion(), PROTOCOL, getAuthors());
if (getConfigProvider().getConfig().isShowingDonateMessage()) {
getLogger().config("Help dumptruckman keep this project alive. Become a patron! https://www.patreon.com/dumptruckman");
getLogger().config("One time donations are also appreciated: https://www.paypal.me/dumptruckman");
if (config.isShowingDonateMessage()) {
Logging.config("Help dumptruckman keep this project alive. Become a patron! https://www.patreon.com/dumptruckman");
Logging.config("One time donations are also appreciated: https://www.paypal.me/dumptruckman");
}
}
private void loadPlaceholderAPIIntegration() {
if(getServer().getPluginManager().getPlugin("PlaceholderAPI") != null) {
if (config.isRegisterPapiHook()
&& getServer().getPluginManager().getPlugin("PlaceholderAPI") != null) {
Try.run(() -> serviceLocator.createAndInitialize(MultiverseCorePlaceholders.class))
.onFailure(e -> {
Logging.severe("Failed to load PlaceholderAPI integration.");
@ -291,10 +292,6 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
}
}
private MVCoreConfigProvider getConfigProvider() {
return configProvider;
}
/**
* {@inheritDoc}
*/
@ -343,6 +340,12 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
return this.pluginCount;
}
@NotNull
@Override
public Logger getLogger() {
return Logging.getLogger();
}
/**
* {@inheritDoc}
*/
@ -359,35 +362,14 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
this.pluginCount -= 1;
}
/**
* {@inheritDoc}
*/
@Override
public void loadConfigs() {
getConfigProvider().loadConfigs();
}
/**
* {@inheritDoc}
*/
@Override
public boolean saveMVConfig() {
return getConfigProvider().saveConfig()
.map(v -> true)
.recover(e -> {
Logging.severe(e.getMessage());
e.printStackTrace();
return false;
})
.get();
}
/**
* {@inheritDoc}
*/
@Override
public boolean saveAllConfigs() {
return this.saveMVConfig() && worldManagerProvider.get().saveWorldsConfig();
return config.save()
&& worldManagerProvider.get().saveWorldsConfig()
&& anchorManagerProvider.get().saveAnchors();
}
//TODO: REMOVE THIS STATIC CRAP - START

View File

@ -1,317 +0,0 @@
package com.onarandombox.MultiverseCore;
import java.util.Map;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.api.MVConfig;
import com.onarandombox.MultiverseCore.event.MVDebugModeEvent;
import me.main__.util.SerializationConfig.NoSuchPropertyException;
import me.main__.util.SerializationConfig.Property;
import me.main__.util.SerializationConfig.SerializationConfig;
import org.bukkit.Bukkit;
import org.jvnet.hk2.annotations.Service;
/**
* Our configuration.
*/
public class MultiverseCoreConfiguration extends SerializationConfig implements MVConfig {
private static MultiverseCoreConfiguration instance;
/**
* Sets the statically saved instance.
* @param instance The new instance.
*/
public static void setInstance(MultiverseCoreConfiguration instance) {
MultiverseCoreConfiguration.instance = instance;
}
/**
* @return True if the static instance of config is set.
*/
public static boolean isSet() {
return instance != null;
}
/**
* Gets the statically saved instance.
* @return The statically saved instance.
*/
@Deprecated
public static MultiverseCoreConfiguration getInstance() {
if (instance == null)
throw new IllegalStateException("The instance wasn't set!");
return instance;
}
@Property
private volatile boolean enforceaccess;
@Property
private volatile boolean prefixchat;
@Property
private volatile String prefixchatformat;
@Property
private volatile boolean teleportintercept;
@Property
private volatile boolean firstspawnoverride;
@Property
private volatile boolean displaypermerrors;
@Property
private volatile int globaldebug;
@Property
private volatile boolean silentstart;
@Property
private volatile double version;
@Property
private volatile String firstspawnworld;
@Property
private volatile boolean defaultportalsearch;
@Property
private volatile int portalsearchradius;
@Property
private volatile boolean autopurge;
@Property
private volatile boolean idonotwanttodonate;
public MultiverseCoreConfiguration() {
super();
MultiverseCoreConfiguration.setInstance(this);
}
public MultiverseCoreConfiguration(Map<String, Object> values) {
super(values);
MultiverseCoreConfiguration.setInstance(this);
}
/**
* {@inheritDoc}
*/
@Override
protected void setDefaults() {
// BEGIN CHECKSTYLE-SUPPRESSION: MagicNumberCheck
enforceaccess = false;
prefixchat = false;
prefixchatformat = "[%world%]%chat%";
teleportintercept = true;
firstspawnoverride = true;
displaypermerrors = true;
globaldebug = 0;
this.version = 2.9;
silentstart = false;
defaultportalsearch = true;
portalsearchradius = 128;
autopurge = true;
idonotwanttodonate = false;
// END CHECKSTYLE-SUPPRESSION: MagicNumberCheck
}
/**
* {@inheritDoc}
*/
@Override
public boolean setConfigProperty(String property, String value) {
try {
return this.setProperty(property, value, true);
} catch (NoSuchPropertyException e) {
return false;
}
}
// And here we go:
/**
* {@inheritDoc}
*/
@Override
public boolean getEnforceAccess() {
return this.enforceaccess;
}
/**
* {@inheritDoc}
*/
@Override
public void setEnforceAccess(boolean enforceAccess) {
this.enforceaccess = enforceAccess;
}
/**
* {@inheritDoc}
*/
@Override
public boolean getPrefixChat() {
return this.prefixchat;
}
/**
* {@inheritDoc}
*/
@Override
public void setPrefixChat(boolean prefixChat) {
this.prefixchat = prefixChat;
}
/**
* {@inheritDoc}
*/
@Override
public String getPrefixChatFormat() {
return this.prefixchatformat;
}
/**
* {@inheritDoc}
*/
@Override
public void setPrefixChatFormat(String prefixChatFormat) {
this.prefixchatformat = prefixChatFormat;
}
/**
* {@inheritDoc}
*/
@Override
public boolean getTeleportIntercept() {
return this.teleportintercept;
}
/**
* {@inheritDoc}
*/
@Override
public void setTeleportIntercept(boolean teleportIntercept) {
this.teleportintercept = teleportIntercept;
}
/**
* {@inheritDoc}
*/
@Override
public boolean getFirstSpawnOverride() {
return this.firstspawnoverride;
}
/**
* {@inheritDoc}
*/
@Override
public void setFirstSpawnOverride(boolean firstSpawnOverride) {
this.firstspawnoverride = firstSpawnOverride;
}
/**
* {@inheritDoc}
*/
@Override
public boolean getDisplayPermErrors() {
return this.displaypermerrors;
}
/**
* {@inheritDoc}
*/
@Override
public void setDisplayPermErrors(boolean displayPermErrors) {
this.displaypermerrors = displayPermErrors;
}
/**
* {@inheritDoc}
*/
@Override
public int getGlobalDebug() {
return this.globaldebug;
}
/**
* {@inheritDoc}
*/
@Override
public void setGlobalDebug(int globalDebug) {
this.globaldebug = globalDebug;
Logging.setDebugLevel(globalDebug);
Bukkit.getPluginManager().callEvent(new MVDebugModeEvent(globalDebug));
}
/**
* {@inheritDoc}
*/
@Override
public double getVersion() {
return this.version;
}
/**
* {@inheritDoc}
*/
@Override
public void setVersion(int version) {
this.version = version;
}
/**
* {@inheritDoc}
*/
@Override
public String getFirstSpawnWorld() {
return this.firstspawnworld;
}
/**
* {@inheritDoc}
*/
@Override
public void setFirstSpawnWorld(String firstSpawnWorld) {
this.firstspawnworld = firstSpawnWorld;
}
@Override
public void setSilentStart(boolean silentStart) {
Logging.setShowingConfig(!silentStart);
this.silentstart = silentStart;
}
@Override
public boolean getSilentStart() {
return silentstart;
}
@Override
public void setUseDefaultPortalSearch(boolean useDefaultPortalSearch) {
defaultportalsearch = useDefaultPortalSearch;
}
@Override
public boolean isUsingDefaultPortalSearch() {
return defaultportalsearch;
}
@Override
public void setPortalSearchRadius(int searchRadius) {
this.portalsearchradius = searchRadius;
}
@Override
public int getPortalSearchRadius() {
return portalsearchradius;
}
@Override
public boolean isAutoPurgeEnabled() {
return autopurge;
}
@Override
public void setAutoPurgeEnabled(boolean autopurge) {
this.autopurge = autopurge;
}
@Override
public boolean isShowingDonateMessage() {
return !idonotwanttodonate;
}
@Override
public void setShowDonateMessage(boolean showDonateMessage) {
this.idonotwanttodonate = !showDonateMessage;
}
}

View File

@ -10,7 +10,7 @@ package com.onarandombox.MultiverseCore.anchor;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.LocationManipulation;
import com.onarandombox.MultiverseCore.config.MVCoreConfigProvider;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import jakarta.inject.Inject;
import org.bukkit.Location;
import org.bukkit.configuration.ConfigurationSection;
@ -38,17 +38,17 @@ public class AnchorManager {
private final Plugin plugin;
private final LocationManipulation locationManipulation;
private final MVCoreConfigProvider configProvider;
private final MVCoreConfig config;
@Inject
public AnchorManager(
MultiverseCore plugin,
LocationManipulation locationManipulation,
MVCoreConfigProvider configProvider
MVCoreConfig config
) {
this.plugin = plugin;
this.locationManipulation = locationManipulation;
this.configProvider = configProvider;
this.config = config;
this.anchors = new HashMap<String, Location>();
}
@ -160,8 +160,8 @@ public class AnchorManager {
// Add to the list if we're not enforcing access
// OR
// We are enforcing access and the user has the permission.
if (!this.configProvider.getConfig().getEnforceAccess() ||
(this.configProvider.getConfig().getEnforceAccess() && p.hasPermission(worldPerm))) {
if (!config.getEnforceAccess() ||
(config.getEnforceAccess() && p.hasPermission(worldPerm))) {
myAnchors.add(anchor);
} else {
Logging.finer(String.format("Not adding anchor %s to the list, user %s doesn't have the %s " +

View File

@ -1,79 +1,90 @@
package com.onarandombox.MultiverseCore.api;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import com.onarandombox.MultiverseCore.configuration.node.NodeGroup;
import com.onarandombox.MultiverseCore.placeholders.MultiverseCorePlaceholders;
import org.jvnet.hk2.annotations.Contract;
/**
* The configuration of MultiverseCore.
*/
public interface MVConfig extends ConfigurationSerializable {
/**
* Sets a property using a {@link String}.
* @param property The name of the property.
* @param value The value.
* @return True on success, false if the operation failed.
*/
boolean setConfigProperty(String property, String value);
@Contract
public interface MVConfig {
/**
* Sets firstSpawnWorld.
* @param firstSpawnWorld The new value.
* Loads the config from disk.
* @return True if the config was loaded successfully.
*/
void setFirstSpawnWorld(String firstSpawnWorld);
boolean load();
/**
* Gets firstSpawnWorld.
* @return firstSpawnWorld.
* Whether the config has been loaded.
* @return True if the config has been loaded.
*/
String getFirstSpawnWorld();
boolean isLoaded();
/**
* Sets version.
* @param version The new value.
* Saves the config to disk.
*/
void setVersion(int version);
boolean save();
/**
* Gets version.
* @return version.
* Gets the nodes for the config.
*
* @return The nodes for the config.
*/
double getVersion();
NodeGroup getNodes();
/**
* Sets globalDebug.
* @param globalDebug The new value.
* Gets a property from the config.
*
* @param name The name of the property.
* @return The value of the property.
*/
void setGlobalDebug(int globalDebug);
Object getProperty(String name);
/**
* Gets globalDebug.
* @return globalDebug.
* Sets a property in the config.
*
* @param name The name of the property.
* @param value The value of the property.
* @return True if the property was set successfully.
*/
int getGlobalDebug();
boolean setProperty(String name, Object value);
/**
* Sets displayPermErrors.
* @param displayPermErrors The new value.
* Sets world access permissions should be enforced.
* @param enforceAccess The new value.
*/
void setDisplayPermErrors(boolean displayPermErrors);
void setEnforceAccess(boolean enforceAccess);
/**
* Gets displayPermErrors.
* @return displayPermErrors.
* Gets enforceAccess.
* @return enforceAccess.
*/
boolean getDisplayPermErrors();
boolean getEnforceAccess();
/**
* Sets firstSpawnOverride.
* @param firstSpawnOverride The new value.
* Sets whether the game mode should be enforced.
* @param enforceGameMode The new value.
*/
void setFirstSpawnOverride(boolean firstSpawnOverride);
void setEnforceGameMode(boolean enforceGameMode);
/**
* Gets firstSpawnOverride.
* @return firstSpawnOverride.
* Gets enforceGameMode value.
* @return True if game mode should be enforced.
*/
boolean getFirstSpawnOverride();
boolean getEnforceGameMode();
/**
* Sets whether or not the automatic purge of entities is enabled.
*
* @param autopurge True if automatic purge should be enabled.
*/
void setAutoPurgeEntities(boolean autopurge);
/**
* Gets whether or not the automatic purge of entities is enabled.
*
* @return True if automatic purge is enabled.
*/
boolean isAutoPurgeEntities();
/**
* Sets teleportIntercept.
@ -87,18 +98,70 @@ public interface MVConfig extends ConfigurationSerializable {
*/
boolean getTeleportIntercept();
/**
* Sets firstSpawnOverride.
* @param firstSpawnOverride The new value.
*/
void setFirstSpawnOverride(boolean firstSpawnOverride);
/**
* Gets firstSpawnOverride.
* @return firstSpawnOverride.
*/
boolean getFirstSpawnOverride();
/**
* Sets firstSpawnWorld.
* @param firstSpawnWorld The new value.
*/
void setFirstSpawnLocation(String firstSpawnWorld);
/**
* Gets firstSpawnWorld.
* @return firstSpawnWorld.
*/
String getFirstSpawnLocation();
/**
* 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 setUseCustomPortalSearch(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 isUsingCustomPortalSearch();
/**
* Sets the radius at which vanilla style portals will be searched for to connect to worlds together.
*
* @param searchRadius The portal search radius.
*/
void setCustomPortalSearchRadius(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 getCustomPortalSearchRadius();
/**
* Sets prefixChat.
* @param prefixChat The new value.
*/
void setPrefixChat(boolean prefixChat);
void setEnablePrefixChat(boolean prefixChat);
/**
* Gets prefixChat.
* @return prefixChat.
*/
boolean getPrefixChat();
boolean isEnablePrefixChat();
/**
* Sets prefixChatFormat.
* @param prefixChatFormat The new value.
@ -112,16 +175,28 @@ public interface MVConfig extends ConfigurationSerializable {
String getPrefixChatFormat();
/**
* Sets enforceAccess.
* @param enforceAccess The new value.
* Sets whether to register the {@link MultiverseCorePlaceholders} class with PlaceholderAPI plugin.
* @param registerPapiHook The new value.
*/
void setEnforceAccess(boolean enforceAccess);
void setRegisterPapiHook(boolean registerPapiHook);
/**
* Gets enforceAccess.
* @return enforceAccess.
* Gets whether to register the {@link MultiverseCorePlaceholders} class with PlaceholderAPI plugin.
* @return registerPapiHook.
*/
boolean getEnforceAccess();
boolean isRegisterPapiHook();
/**
* Sets globalDebug.
* @param globalDebug The new value.
*/
void setGlobalDebug(int globalDebug);
/**
* Gets globalDebug.
* @return globalDebug.
*/
int getGlobalDebug();
/**
* Sets whether to suppress startup messages.
@ -138,46 +213,11 @@ public interface MVConfig extends ConfigurationSerializable {
boolean getSilentStart();
/**
* Sets whether or not to let Bukkit determine portal search radius on its own or if Multiverse should give input.
* Sets whether or not the donation/patreon messages are shown.
*
* @param useDefaultPortalSearch True to let Bukkit determine portal search radius on its own.
* @param idonotwanttodonate True if donation/patreon messages should be shown.
*/
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);
void setShowDonateMessage(boolean idonotwanttodonate);
/**
* Gets whether or not the donation/patreon messages are shown.
@ -185,11 +225,4 @@ public interface MVConfig extends ConfigurationSerializable {
* @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

@ -14,19 +14,6 @@ package com.onarandombox.MultiverseCore.api;
*/
public interface MVCore extends MVPlugin {
/**
* Reloads the Multiverse Configuration files:
* worlds.yml and config.yml.
*/
void loadConfigs();
/**
* Saves the Multiverse-Config.
*
* @return Whether the Multiverse-Config was successfully saved
*/
boolean saveMVConfig();
/**
* Saves all configs.
*

View File

@ -7,11 +7,9 @@
package com.onarandombox.MultiverseCore.api;
import java.io.File;
import java.util.Collection;
import java.util.List;
import com.onarandombox.MultiverseCore.world.SimpleWorldPurger;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.WorldType;
@ -246,10 +244,9 @@ public interface MVWorldManager {
/**
* Load the config from a file.
*
* @param file The file to load.
* @return A loaded configuration.
*/
FileConfiguration loadWorldConfig(File file);
FileConfiguration loadWorldsConfig();
/**
* Saves the world config to disk.

View File

@ -0,0 +1,74 @@
package com.onarandombox.MultiverseCore.commands;
import co.aikar.commands.BukkitCommandIssuer;
import co.aikar.commands.annotation.CommandAlias;
import co.aikar.commands.annotation.CommandCompletion;
import co.aikar.commands.annotation.CommandPermission;
import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Optional;
import co.aikar.commands.annotation.Single;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.Syntax;
import com.onarandombox.MultiverseCore.api.MVConfig;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.commandtools.context.MVConfigValue;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import jakarta.inject.Inject;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
@Service
@CommandAlias("mv")
public class ConfigCommand extends MultiverseCommand {
private final MVCoreConfig config;
@Inject
public ConfigCommand(@NotNull MVCommandManager commandManager, @NotNull MVCoreConfig config) {
super(commandManager);
this.config = config;
}
@Subcommand("config")
@CommandPermission("multiverse.core.config")
@CommandCompletion("@mvconfigs")
@Syntax("<name> [new-value]")
@Description("") //TODO
public void onConfigCommand(BukkitCommandIssuer issuer,
@Syntax("<name>")
@Description("") //TODO
String name,
@Optional
@Single
@Syntax("[new-value]")
@Description("") //TODO
MVConfigValue value
) {
if (value == null) {
showConfigValue(issuer, name);
return;
}
updateConfigValue(issuer, name, value.getValue());
}
private void showConfigValue(BukkitCommandIssuer issuer, String name) {
Object currentValue = config.getProperty(name);
if (currentValue == null) {
issuer.sendMessage("No such config option: " + name);
return;
}
issuer.sendMessage(name + "is currently set to " + config.getProperty(name));
}
private void updateConfigValue(BukkitCommandIssuer issuer, String name, Object value) {
if (!config.setProperty(name, value)) {
issuer.sendMessage("Unable to set " + name + " to " + value);
return;
}
config.save();
issuer.sendMessage("Successfully set " + name + " to " + value);
}
}

View File

@ -8,10 +8,9 @@ import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.Syntax;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.config.MVCoreConfigProvider;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.utils.MVCorei18n;
import jakarta.inject.Inject;
import org.jetbrains.annotations.NotNull;
@ -21,18 +20,12 @@ import org.jvnet.hk2.annotations.Service;
@CommandAlias("mv")
public class DebugCommand extends MultiverseCommand {
private final MVCoreConfigProvider configProvider;
private final MultiverseCore plugin;
private final MVCoreConfig config;
@Inject
public DebugCommand(
@NotNull MVCommandManager commandManager,
@NotNull MVCoreConfigProvider configProvider,
@NotNull MultiverseCore plugin
) {
public DebugCommand(@NotNull MVCommandManager commandManager, @NotNull MVCoreConfig config) {
super(commandManager);
this.configProvider = configProvider;
this.plugin = plugin;
this.config = config;
}
@Subcommand("debug")
@ -53,13 +46,13 @@ public class DebugCommand extends MultiverseCommand {
@Description("{@@mv-core.debug.change.level.description}")
int level) {
this.configProvider.getConfig().setGlobalDebug(level);
this.plugin.saveAllConfigs();
config.setGlobalDebug(level);
config.save();
this.displayDebugMode(issuer);
}
private void displayDebugMode(BukkitCommandIssuer issuer) {
final int debugLevel = this.configProvider.getConfig().getGlobalDebug();
final int debugLevel = config.getGlobalDebug();
if (debugLevel == 0) {
issuer.sendInfo(MVCorei18n.DEBUG_INFO_OFF);
return;

View File

@ -10,9 +10,11 @@ import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Subcommand;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.anchor.AnchorManager;
import com.onarandombox.MultiverseCore.api.MVCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.event.MVConfigReloadEvent;
import com.onarandombox.MultiverseCore.utils.MVCorei18n;
import jakarta.inject.Inject;
@ -24,7 +26,7 @@ import org.jvnet.hk2.annotations.Service;
@CommandAlias("mv")
public class ReloadCommand extends MultiverseCommand {
private final MultiverseCore plugin;
private final MVCoreConfig config;
private final AnchorManager anchorManager;
private final MVWorldManager worldManager;
private final PluginManager pluginManager;
@ -32,13 +34,13 @@ public class ReloadCommand extends MultiverseCommand {
@Inject
public ReloadCommand(
@NotNull MVCommandManager commandManager,
@NotNull MultiverseCore plugin,
@NotNull MVCoreConfig config,
@NotNull AnchorManager anchorManager,
@NotNull MVWorldManager worldManager,
@NotNull PluginManager pluginManager
) {
super(commandManager);
this.plugin = plugin;
this.config = config;
this.anchorManager = anchorManager;
this.worldManager = worldManager;
this.pluginManager = pluginManager;
@ -49,9 +51,10 @@ public class ReloadCommand extends MultiverseCommand {
@Description("{@@mv-core.reload.description}")
public void onReloadCommand(@NotNull BukkitCommandIssuer issuer) {
issuer.sendInfo(MVCorei18n.RELOAD_RELOADING);
this.plugin.loadConfigs();
this.anchorManager.loadAnchors();
this.config.load();
this.worldManager.loadWorldsConfig();
this.worldManager.loadWorlds(true);
this.anchorManager.loadAnchors();
List<String> configsLoaded = new ArrayList<>();
configsLoaded.add("Multiverse-Core - config.yml");

View File

@ -18,6 +18,7 @@ import co.aikar.commands.RootCommand;
import com.google.common.collect.Sets;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.destination.DestinationsProvider;
import com.onarandombox.MultiverseCore.destination.ParsedDestination;
import jakarta.inject.Inject;
@ -36,8 +37,9 @@ public class MVCommandCompletions extends PaperCommandCompletions {
public MVCommandCompletions(
@NotNull MVCommandManager mvCommandManager,
@NotNull MVWorldManager worldManager,
@NotNull DestinationsProvider destinationsProvider
) {
@NotNull DestinationsProvider destinationsProvider,
@NotNull MVCoreConfig config
) {
super(mvCommandManager);
this.commandManager = mvCommandManager;
this.worldManager = worldManager;
@ -47,6 +49,7 @@ public class MVCommandCompletions extends PaperCommandCompletions {
registerAsyncCompletion("destinations", this::suggestDestinations);
registerAsyncCompletion("flags", this::suggestFlags);
registerStaticCompletion("gamerules", this::suggestGamerules);
registerStaticCompletion("mvconfigs", config.getNodes().getNames());
registerAsyncCompletion("mvworlds", this::suggestMVWorlds);
setDefaultCompletion("destinations", ParsedDestination.class);

View File

@ -1,6 +1,7 @@
package com.onarandombox.MultiverseCore.commandtools;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import co.aikar.commands.BukkitCommandExecutionContext;
@ -9,16 +10,19 @@ import co.aikar.commands.InvalidCommandArgument;
import co.aikar.commands.PaperCommandContexts;
import co.aikar.commands.contexts.ContextResolver;
import com.google.common.base.Strings;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.commandtools.context.GameRuleValue;
import com.onarandombox.MultiverseCore.commandtools.context.MVConfigValue;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.destination.DestinationsProvider;
import com.onarandombox.MultiverseCore.destination.ParsedDestination;
import com.onarandombox.MultiverseCore.display.filters.ContentFilter;
import com.onarandombox.MultiverseCore.display.filters.DefaultContentFilter;
import com.onarandombox.MultiverseCore.display.filters.RegexContentFilter;
import com.onarandombox.MultiverseCore.utils.PlayerFinder;
import io.github.townyadvanced.commentedconfiguration.setting.CommentedNode;
import io.github.townyadvanced.commentedconfiguration.setting.TypedValueNode;
import jakarta.inject.Inject;
import org.bukkit.GameRule;
import org.bukkit.entity.Player;
@ -29,22 +33,26 @@ public class MVCommandContexts extends PaperCommandContexts {
private final DestinationsProvider destinationsProvider;
private final MVWorldManager worldManager;
private final MVCoreConfig config;
@Inject
public MVCommandContexts(
MVCommandManager mvCommandManager,
DestinationsProvider destinationsProvider,
MVWorldManager worldManager
MVWorldManager worldManager,
MVCoreConfig config
) {
super(mvCommandManager);
this.destinationsProvider = destinationsProvider;
this.worldManager = worldManager;
this.config = config;
registerIssuerOnlyContext(BukkitCommandIssuer.class, BukkitCommandExecutionContext::getIssuer);
registerOptionalContext(ContentFilter.class, this::parseContentFilter);
registerContext(ParsedDestination.class, this::parseDestination);
registerContext(GameRule.class, this::parseGameRule);
registerContext(GameRuleValue.class, this::parseGameRuleValue);
registerContext(MVConfigValue.class, this::parseMVConfigValue);
registerIssuerAwareContext(MVWorld.class, this::parseMVWorld);
registerIssuerAwareContext(MVWorld[].class, this::parseMVWorldArray);
registerIssuerAwareContext(Player.class, this::parsePlayer);
@ -110,6 +118,39 @@ public class MVCommandContexts extends PaperCommandContexts {
return new GameRuleValue(resolvedValue);
}
private MVConfigValue parseMVConfigValue(BukkitCommandExecutionContext context) {
String configName = (String) context.getResolvedArg(String.class);
if (Strings.isNullOrEmpty(configName)) {
throw new InvalidCommandArgument("No config name specified.");
}
Optional<CommentedNode> node = config.getNodes().findNode(configName);
if (node.isEmpty()) {
throw new InvalidCommandArgument("The config " + configName + " is not valid.");
}
String valueString = context.getFirstArg();
if (Strings.isNullOrEmpty(valueString)) {
throw new InvalidCommandArgument("No config value specified.");
}
if (!(node.get() instanceof TypedValueNode)) {
context.popFirstArg();
return new MVConfigValue(valueString);
}
ContextResolver<?, BukkitCommandExecutionContext> resolver = getResolver(((TypedValueNode<?>) node.get()).getType());
if (resolver == null) {
context.popFirstArg();
return new MVConfigValue(valueString);
}
Object resolvedValue = resolver.getContext(context);
if (resolvedValue == null) {
throw new InvalidCommandArgument("The config value " + valueString + " is not valid for config " + configName + ".");
}
return new MVConfigValue(resolvedValue);
}
private MVWorld parseMVWorld(BukkitCommandExecutionContext context) {
String resolve = context.getFlagValue("resolve", "");

View File

@ -0,0 +1,13 @@
package com.onarandombox.MultiverseCore.commandtools.context;
public class MVConfigValue {
private final Object value;
public MVConfigValue(Object value) {
this.value = value;
}
public Object getValue() {
return value;
}
}

View File

@ -0,0 +1,261 @@
package com.onarandombox.MultiverseCore.config;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVConfig;
import com.onarandombox.MultiverseCore.configuration.ConfigHandle;
import com.onarandombox.MultiverseCore.configuration.migration.BooleanMigratorAction;
import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator;
import com.onarandombox.MultiverseCore.configuration.migration.IntegerMigratorAction;
import com.onarandombox.MultiverseCore.configuration.migration.InvertBoolMigratorAction;
import com.onarandombox.MultiverseCore.configuration.migration.MoveMigratorAction;
import com.onarandombox.MultiverseCore.configuration.migration.VersionMigrator;
import com.onarandombox.MultiverseCore.configuration.node.NodeGroup;
import jakarta.inject.Inject;
import org.bukkit.plugin.PluginManager;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
@Service
public class MVCoreConfig implements MVConfig {
public static final String CONFIG_FILENAME = "config.yml";
public static final double CONFIG_VERSION = 5.0;
private final Path configPath;
private final MVCoreConfigNodes configNodes;
private final ConfigHandle configHandle;
@Inject
MVCoreConfig(@NotNull MultiverseCore core, @NotNull PluginManager pluginManager) {
this.configPath = Path.of(core.getDataFolder().getPath(), CONFIG_FILENAME);
this.configNodes = new MVCoreConfigNodes(pluginManager);
this.configHandle = ConfigHandle.builder(configPath)
.logger(Logging.getLogger())
.nodes(configNodes.getNodes())
.migrator(ConfigMigrator.builder(configNodes.VERSION)
.addVersionMigrator(VersionMigrator.builder(5.0)
.addAction(MoveMigratorAction.of("multiverse-configuration.enforceaccess", "world.enforce-access"))
.addAction(BooleanMigratorAction.of("world.enforce-access"))
.addAction(MoveMigratorAction.of("multiverse-configuration.prefixchat", "messaging.enable-chat-prefix"))
.addAction(BooleanMigratorAction.of("messaging.enable-chat-prefix"))
.addAction(MoveMigratorAction.of("multiverse-configuration.prefixchatformat", "messaging.chat-prefix-format"))
.addAction(MoveMigratorAction.of("multiverse-configuration.teleportintercept", "world.teleport-intercept"))
.addAction(BooleanMigratorAction.of("world.teleport-intercept"))
.addAction(MoveMigratorAction.of("multiverse-configuration.firstspawnoverride", "spawn.first-spawn-override"))
.addAction(BooleanMigratorAction.of("spawn.first-spawn-override"))
//.addAction(MoveMigratorAction.of("multiverse-configuration.displaypermerrors", ""))
.addAction(MoveMigratorAction.of("multiverse-configuration.globaldebug", "misc.global-debug"))
.addAction(IntegerMigratorAction.of("misc.global-debug"))
.addAction(MoveMigratorAction.of("multiverse-configuration.silentstart", "misc.silent-start"))
.addAction(BooleanMigratorAction.of("misc.silent-start"))
.addAction(MoveMigratorAction.of("multiverse-configuration.firstspawnworld", "spawn.first-spawn-location"))
.addAction(MoveMigratorAction.of("multiverse-configuration.defaultportalsearch", "portal.use-custom-portal-search"))
.addAction(BooleanMigratorAction.of("portal.use-custom-portal-search"))
.addAction(InvertBoolMigratorAction.of("portal.use-custom-portal-search"))
.addAction(MoveMigratorAction.of("multiverse-configuration.portalsearchradius", "portal.custom-portal-search-radius"))
.addAction(IntegerMigratorAction.of("portal.custom-portal-search-radius"))
.addAction(MoveMigratorAction.of("multiverse-configuration.autopurge", "world.auto-purge-entities"))
.addAction(BooleanMigratorAction.of("world.auto-purge-entities"))
.addAction(MoveMigratorAction.of("multiverse-configuration.idonotwanttodonate", "misc.show-donation-message"))
.addAction(BooleanMigratorAction.of("misc.show-donation-message"))
.addAction(InvertBoolMigratorAction.of("misc.show-donation-message"))
.build())
.build())
.build();
load();
save();
}
private void migrateFromOldConfigFile() {
String content;
try {
content = Files.readString(configPath);
} catch (IOException e) {
return;
}
// Remove the old config section if it is still in the old ConfigurationSerializable.
content = content.replace("==: com.onarandombox.MultiverseCore.MultiverseCoreConfiguration", "");
try {
Files.writeString(configPath, content);
} catch (IOException e) {
// ignore
}
}
@Override
public boolean load() {
migrateFromOldConfigFile();
return configHandle.load();
}
@Override
public boolean isLoaded() {
return configHandle.isLoaded();
}
@Override
public boolean save() {
configHandle.save();
return true;
}
@Override
public NodeGroup getNodes() {
return configNodes.getNodes();
}
@Override
public Object getProperty(String name) {
return configHandle.get(name);
}
@Override
public boolean setProperty(String name, Object value) {
return configHandle.set(name, value);
}
@Override
public void setEnforceAccess(boolean enforceAccess) {
configHandle.set(configNodes.ENFORCE_ACCESS, enforceAccess);
}
@Override
public boolean getEnforceAccess() {
return configHandle.get(configNodes.ENFORCE_ACCESS);
}
@Override
public void setEnforceGameMode(boolean enforceGameMode) {
configHandle.set(configNodes.ENFORCE_GAMEMODE, enforceGameMode);
}
@Override
public boolean getEnforceGameMode() {
return configHandle.get(configNodes.ENFORCE_GAMEMODE);
}
@Override
public void setAutoPurgeEntities(boolean autopurge) {
configHandle.set(configNodes.AUTO_PURGE_ENTITIES, autopurge);
}
@Override
public boolean isAutoPurgeEntities() {
return configHandle.get(configNodes.AUTO_PURGE_ENTITIES);
}
@Override
public void setTeleportIntercept(boolean teleportIntercept) {
configHandle.set(configNodes.TELEPORT_INTERCEPT, teleportIntercept);
}
@Override
public boolean getTeleportIntercept() {
return configHandle.get(configNodes.TELEPORT_INTERCEPT);
}
@Override
public void setFirstSpawnOverride(boolean firstSpawnOverride) {
configHandle.set(configNodes.FIRST_SPAWN_OVERRIDE, firstSpawnOverride);
}
@Override
public boolean getFirstSpawnOverride() {
return configHandle.get(configNodes.FIRST_SPAWN_OVERRIDE);
}
@Override
public void setFirstSpawnLocation(String firstSpawnWorld) {
configHandle.set(configNodes.FIRST_SPAWN_LOCATION, firstSpawnWorld);
}
@Override
public String getFirstSpawnLocation() {
return configHandle.get(configNodes.FIRST_SPAWN_LOCATION);
}
@Override
public void setUseCustomPortalSearch(boolean useDefaultPortalSearch) {
configHandle.set(configNodes.USE_CUSTOM_PORTAL_SEARCH, useDefaultPortalSearch);
}
@Override
public boolean isUsingCustomPortalSearch() {
return configHandle.get(configNodes.USE_CUSTOM_PORTAL_SEARCH);
}
@Override
public void setCustomPortalSearchRadius(int searchRadius) {
configHandle.set(configNodes.CUSTOM_PORTAL_SEARCH_RADIUS, searchRadius);
}
@Override
public int getCustomPortalSearchRadius() {
return configHandle.get(configNodes.CUSTOM_PORTAL_SEARCH_RADIUS);
}
@Override
public void setEnablePrefixChat(boolean prefixChat) {
configHandle.set(configNodes.ENABLE_CHAT_PREFIX, prefixChat);
}
@Override
public boolean isEnablePrefixChat() {
return configHandle.get(configNodes.ENABLE_CHAT_PREFIX);
}
@Override
public void setPrefixChatFormat(String prefixChatFormat) {
configHandle.set(configNodes.CHAT_PREFIX_FORMAT, prefixChatFormat);
}
@Override
public String getPrefixChatFormat() {
return configHandle.get(configNodes.CHAT_PREFIX_FORMAT);
}
@Override
public void setRegisterPapiHook(boolean registerPapiHook) {
configHandle.set(configNodes.REGISTER_PAPI_HOOK, registerPapiHook);
}
@Override
public boolean isRegisterPapiHook() {
return configHandle.get(configNodes.REGISTER_PAPI_HOOK);
}
@Override
public void setGlobalDebug(int globalDebug) {
configHandle.set(configNodes.GLOBAL_DEBUG, globalDebug);
}
@Override
public int getGlobalDebug() {
return configHandle.get(configNodes.GLOBAL_DEBUG);
}
@Override
public void setSilentStart(boolean silentStart) {
configHandle.set(configNodes.SILENT_START, silentStart);
}
@Override
public boolean getSilentStart() {
return configHandle.get(configNodes.SILENT_START);
}
@Override
public void setShowDonateMessage(boolean showDonateMessage) {
configHandle.set(configNodes.SHOW_DONATION_MESSAGE, showDonateMessage);
}
@Override
public boolean isShowingDonateMessage() {
return configHandle.get(configNodes.SHOW_DONATION_MESSAGE);
}
}

View File

@ -0,0 +1,211 @@
package com.onarandombox.MultiverseCore.config;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.configuration.node.MVCommentedNode;
import com.onarandombox.MultiverseCore.configuration.node.MVValueNode;
import com.onarandombox.MultiverseCore.configuration.node.NodeGroup;
import com.onarandombox.MultiverseCore.event.MVDebugModeEvent;
import io.github.townyadvanced.commentedconfiguration.setting.CommentedNode;
import jakarta.inject.Inject;
import org.bukkit.plugin.PluginManager;
import org.jvnet.hk2.annotations.Service;
class MVCoreConfigNodes {
private final NodeGroup nodes = new NodeGroup();
private PluginManager pluginManager;
MVCoreConfigNodes(PluginManager pluginManager) {
this.pluginManager = pluginManager;
}
public NodeGroup getNodes() {
return nodes;
}
private <N extends CommentedNode> N node(N node) {
nodes.add(node);
return node;
}
private 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 final MVCommentedNode WORLD_HEADER = node(MVCommentedNode.builder("world")
// .comment("")
// .comment("")
// .build());
public 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)
.name("enforce-access")
.build());
public 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)
.name("enforce-gamemode")
.build());
public 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)
.name("auto-purge-entities")
.build());
public 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)
.name("teleport-intercept")
.build());
private final MVCommentedNode SPAWN_HEADER = node(MVCommentedNode.builder("spawn")
.comment("")
.comment("")
.build());
public 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)
.name("first-spawn-override")
.build());
public 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("")
.name("first-spawn-location")
.build());
private final MVCommentedNode PORTAL_HEADER = node(MVCommentedNode.builder("portal")
.comment("")
.comment("")
.build());
public 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)
.name("use-custom-portal-search")
.build());
public 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)
.name("custom-portal-search-radius")
.validator(value -> value >= 0)
.build());
private final MVCommentedNode MESSAGING_HEADER = node(MVCommentedNode.builder("messaging")
.comment("")
.comment("")
.build());
public 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)
.name("enable-chat-prefix")
.build());
public 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%")
.name("chat-prefix-format")
.build());
public final MVValueNode<Boolean> REGISTER_PAPI_HOOK = node(MVValueNode.builder("messaging.register-papi-hook", Boolean.class)
.comment("")
.comment("This config option defines whether or not Multiverse should register the PlaceholderAPI hook.")
.comment("This only applies if PlaceholderAPI is installed.")
.defaultValue(true)
.name("register-papi-hook")
.build());
private final MVCommentedNode MISC_HEADER = node(MVCommentedNode.builder("misc")
.comment("")
.comment("")
.build());
public 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)
.name("global-debug")
.validator(value -> value >= 0 && value <= 3)
.onSetValue((oldValue, newValue) -> {
int level = Logging.getDebugLevel();
Logging.setDebugLevel(newValue);
if (level != Logging.getDebugLevel()) {
pluginManager.callEvent(new MVDebugModeEvent(level));
}
})
.build());
public final MVValueNode<Boolean> SILENT_START = node(MVValueNode.builder("misc.silent-start", Boolean.class)
.comment("")
.comment("If true, the startup console messages will no longer show.")
.defaultValue(false)
.name("silent-start")
.onSetValue((oldValue, newValue) -> Logging.setShowingConfig(!newValue))
.build());
public final MVValueNode<Boolean> SHOW_DONATION_MESSAGE = node(MVValueNode.builder("misc.show-donation-message", Boolean.class)
.comment("")
.comment("If you don't want to donate, you can set this to false and Multiverse will stop nagging you.")
.defaultValue(true)
.name("show-donation-message")
.build());
public 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(MVCoreConfig.CONFIG_VERSION)
.name(null)
.build());
}

View File

@ -1,140 +0,0 @@
package com.onarandombox.MultiverseCore.config;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.MultiverseCoreConfiguration;
import com.onarandombox.MultiverseCore.api.MVConfig;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.event.MVDebugModeEvent;
import io.vavr.control.Option;
import io.vavr.control.Try;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
@Service
public final class MVCoreConfigProvider {
private static final String CONFIG_FILE = "config.yml";
private static final String DEFAULTS_CONFIG_FILE = "/defaults/config.yml";
private static final String WORLDS_CONFIG_FILE = "worlds.yml";
private static final String CHARACTER_ENCODING = "UTF-8";
private static final String CONFIG_KEY = "multiverse-configuration";
private FileConfiguration multiverseConfig;
private volatile MultiverseCoreConfiguration config;
private final Plugin plugin;
private final PluginManager pluginManager;
private final Provider<MVWorldManager> worldManagerProvider; // TODO remove this dependency
@Inject
MVCoreConfigProvider(
MultiverseCore plugin,
PluginManager pluginManager,
Provider<MVWorldManager> worldManagerProvider
) {
this.plugin = plugin;
this.pluginManager = pluginManager;
this.worldManagerProvider = worldManagerProvider;
}
/**
* Checks if the config is loaded.
*
* @return True if the config is loaded, false otherwise
*/
public boolean isConfigLoaded() {
return config != null;
}
/**
* Gets the Core configuration instance.
*
* @return The config
* @throws IllegalStateException If the config is not loaded
*/
@NotNull
public MVConfig getConfig() throws IllegalStateException {
if (config == null) {
throw new IllegalStateException("Config is not loaded");
}
return config;
}
public void loadConfigs() {
multiverseConfig = loadConfigWithDefaults();
setConfigOptions(multiverseConfig);
config = getOrCreateConfigObject(multiverseConfig);
loadWorldConfigs();
setDebugLevelFromConfig(config);
}
@NotNull
private FileConfiguration loadConfigWithDefaults() {
var config = YamlConfiguration.loadConfiguration(new File(plugin.getDataFolder(), CONFIG_FILE));
Option.of(plugin.getClass().getResourceAsStream(DEFAULTS_CONFIG_FILE))
.toTry()
.mapTry(defaultsStream -> YamlConfiguration.loadConfiguration(
new BufferedReader(new InputStreamReader(defaultsStream, CHARACTER_ENCODING))))
.andThen(config::setDefaults)
.onFailure(e -> {
Logging.severe("Couldn't load default config with UTF-8 encoding. Details follow:");
e.printStackTrace();
Logging.severe("Default configs NOT loaded.");
});
return config;
}
private void setConfigOptions(@NotNull FileConfiguration config) {
config.options().copyDefaults(false);
config.options().copyHeader(true);
}
@NotNull
private MultiverseCoreConfiguration getOrCreateConfigObject(@NotNull FileConfiguration config) {
return Try.of(() -> (MultiverseCoreConfiguration) config.get(CONFIG_KEY))
.toOption() // Ignore exceptions
.map(c -> c == null ? new MultiverseCoreConfiguration() : c)
.getOrElse(new MultiverseCoreConfiguration());
}
private void loadWorldConfigs() {
worldManagerProvider.get().loadWorldConfig(new File(plugin.getDataFolder(), WORLDS_CONFIG_FILE));
}
private void setDebugLevelFromConfig(@NotNull MVConfig config) {
int level = Logging.getDebugLevel();
Logging.setDebugLevel(config.getGlobalDebug());
if (level != Logging.getDebugLevel()) {
pluginManager.callEvent(new MVDebugModeEvent(level));
}
}
@NotNull
public Try<Void> saveConfig() {
try {
this.multiverseConfig.set(CONFIG_KEY, config);
this.multiverseConfig.save(new File(plugin.getDataFolder(), CONFIG_FILE));
return Try.success(null);
} catch (IOException e) {
return Try.failure(new MultiverseConfigurationException(
"Could not save Multiverse config.yml config. Please check your file permissions.", e));
}
}
}

View File

@ -1,9 +0,0 @@
package com.onarandombox.MultiverseCore.config;
import java.io.IOException;
public class MultiverseConfigurationException extends IOException {
public MultiverseConfigurationException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -0,0 +1,360 @@
package com.onarandombox.MultiverseCore.configuration;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.logging.Logger;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator;
import com.onarandombox.MultiverseCore.configuration.node.EnhancedValueNode;
import com.onarandombox.MultiverseCore.configuration.node.NodeGroup;
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.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* A class that makes use of CommentedConfiguration to provide a simple way to load and save with node objects.
*/
public class ConfigHandle {
/**
* A builder class for creating a ConfigHandle.
*
* @param configPath The path to the configuration file in string.
* @return A new Builder instance.
*/
public static Builder builder(String configPath) {
return new Builder(configPath);
}
/**
* A builder class for creating a ConfigHandle.
*
* @param configPath The path to the configuration file.
* @return A new Builder instance.
*/
public static Builder builder(Path configPath) {
return new Builder(configPath);
}
@NotNull
protected final Path configPath;
@Nullable
protected final Logger logger;
@NotNull
protected final NodeGroup nodes;
protected final ConfigMigrator migrator;
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 nodes All the node path and values for the configuration.
* @param migrator The migrator to use for migrating the configuration.
*/
protected ConfigHandle(@NotNull Path configPath, @Nullable Logger logger, @NotNull NodeGroup nodes, ConfigMigrator migrator) {
this.configPath = configPath;
this.nodes = nodes;
this.logger = logger;
this.migrator = migrator;
}
/**
* 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;
}
migrateConfig();
parseAllNodes();
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;
}
Logging.info("Created new config file: %s", configFile.getName());
} catch (IOException e) {
return false;
}
return true;
}
/**
* Migration of the configuration based on {@link ConfigMigrator}.
*/
protected void migrateConfig() {
migrator.migrate(this);
}
/**
* Adds default node values to the configuration if they are not already present.
*/
protected void parseAllNodes() {
CommentedConfiguration oldConfig = config;
this.config = new CommentedConfiguration(configPath, logger);
for (CommentedNode node : nodes) {
if (node.getComments().length > 0) {
config.addComment(node.getPath(), node.getComments());
}
if (node instanceof TypedValueNode typedNode) {
if (!set(typedNode, oldConfig.getObject(node.getPath(), typedNode.getType(), typedNode.getDefaultValue()))) {
Logging.warning("Invalid value for node: %s, resetting to default...", node.getPath());
setDefault(typedNode);
}
} else if (node instanceof ValueNode valueNode) {
if (!set(valueNode, oldConfig.get(node.getPath(), valueNode.getDefaultValue()))) {
Logging.warning("Invalid value for node: %s, resetting to default...", node.getPath());
setDefault(valueNode);
}
}
}
}
/**
* Saves the configuration.
*/
public void save() {
config.save();
}
/**
* Checks if the configuration is loaded.
*
* @return True if the configuration is loaded, false otherwise.
*/
public boolean isLoaded() {
return config != null;
}
/**
* 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());
}
/**
* Get the value of the node by name.
*
* @param name The name of the node to get the value of.
* @return The value of the node.
*/
public Object get(@NotNull String name) {
return nodes.findNode(name)
.map(node -> (node instanceof ValueNode) ? get((ValueNode) node) : null)
.orElse(null);
}
/**
* 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());
}
/**
* Set the value of the node by name.
*
* @param name The name of the node to set the value of.
* @param value The value to set.
*/
public boolean set(@NotNull String name, Object value) {
return nodes.findNode(name)
.map(node -> node instanceof ValueNode && set((ValueNode) node, value))
.orElse(false);
}
/**
* 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 boolean set(@NotNull ValueNode node, Object value) {
if (node instanceof TypedValueNode typedValueNode) {
return set(typedValueNode, value);
}
config.set(node.getPath(), value);
return true;
}
/**
* 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> boolean set(@NotNull TypedValueNode<T> node, T value) {
if (node instanceof EnhancedValueNode<T> enhancedValueNode) {
return set(enhancedValueNode, value);
}
config.set(node.getPath(), value);
return true;
}
/**
* 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.
* @return True if the value was set, false otherwise.
* @param <T> The type of the node value.
*/
public <T> boolean set(@NotNull EnhancedValueNode<T> node, T value) {
if (!node.isValid(value)) {
return false;
}
T oldValue = get(node);
config.set(node.getPath(), value);
node.onSetValue(oldValue, get(node));
return true;
}
/**
* Sets the default value of a node.
*
* @param node The node to set the default value of.
*/
public void setDefault(@NotNull ValueNode node) {
config.set(node.getPath(), node.getDefaultValue());
}
/**
* Gets the inner configuration object.
*
* @return The configuration object.
*/
public @NotNull CommentedConfiguration getConfig() {
return config;
}
/**
* Gets the path of the configuration file.
*/
public static class Builder {
private final Path configPath;
private Logger logger;
private NodeGroup nodes;
private ConfigMigrator migrator;
/**
* Creates a new builder.
*
* @param configPath The path of the configuration file.
*/
public Builder(String configPath) {
this.configPath = Path.of(configPath);
}
/**
* Creates a new builder.
*
* @param configPath The path of the configuration file.
*/
public Builder(Path configPath) {
this.configPath = configPath;
}
/**
* Sets the logger to use.
*
* @param plugin The plugin to get the logger from.
* @return The builder.
*/
public Builder logger(@NotNull Plugin plugin) {
return logger(plugin.getLogger());
}
/**
* Sets the logger to use.
*
* @param logger The logger to use.
* @return The builder.
*/
public Builder logger(@Nullable Logger logger) {
this.logger = logger;
return this;
}
/**
* Sets the nodes to use.
*
* @param nodes The nodes to use.
* @return The builder.
*/
public Builder nodes(@Nullable NodeGroup nodes) {
this.nodes = nodes;
return this;
}
/**
* Sets the migrator to use.
*
* @param migrator The migrator to use.
* @return The builder.
*/
public Builder migrator(@Nullable ConfigMigrator migrator) {
this.migrator = migrator;
return this;
}
/**
* Builds the settings.
*
* @return The built settings.
*/
public ConfigHandle build() {
return new ConfigHandle(configPath, logger, nodes, migrator);
}
}
}

View File

@ -0,0 +1,28 @@
package com.onarandombox.MultiverseCore.configuration.migration;
import co.aikar.commands.ACFUtil;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.configuration.ConfigHandle;
/**
* Single migrator action that converts a string value to a boolean.
*/
public class BooleanMigratorAction implements MigratorAction {
public static BooleanMigratorAction of(String path) {
return new BooleanMigratorAction(path);
}
private final String path;
protected BooleanMigratorAction(String path) {
this.path = path;
}
@Override
public void migrate(ConfigHandle settings) {
settings.getConfig().set(path, ACFUtil.isTruthy(settings.getConfig().getString(path, "")));
Logging.info("Converted %s to boolean %s", path, settings.getConfig().getBoolean(path));
}
}

View File

@ -0,0 +1,89 @@
package com.onarandombox.MultiverseCore.configuration.migration;
import java.util.ArrayList;
import java.util.List;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.configuration.ConfigHandle;
import io.github.townyadvanced.commentedconfiguration.setting.TypedValueNode;
/**
* Helper class for migrating configs to the latest config version.
*/
public class ConfigMigrator {
/**
* Creates a new builder for a ConfigMigrator.
*
* @param versionNode The node that stores the version number of the config.
* Default value should be the current latest version number.
* @return The builder instance.
*/
public static Builder builder(TypedValueNode<Double> versionNode) {
return new Builder(versionNode);
}
private final TypedValueNode<Double> versionNode;
private final List<VersionMigrator> versionMigrators;
protected ConfigMigrator(TypedValueNode<Double> versionNode, List<VersionMigrator> versionMigrators) {
this.versionNode = versionNode;
this.versionMigrators = versionMigrators;
}
/**
* Migrates the config to the latest version if necessary.
*
* @param settings The target settings instance to migrate.
*/
public void migrate(ConfigHandle settings) {
double versionNumber = settings.getConfig().getDouble(versionNode.getPath());
for (VersionMigrator versionMigrator : versionMigrators) {
if (versionNumber < versionMigrator.getVersion()) {
Logging.info("Migrating config from version %s to %s...", versionNumber, versionMigrator.getVersion());
versionMigrator.migrate(settings);
}
}
// Set the version number to the latest version number
settings.setDefault(versionNode);
}
/**
* A builder for a ConfigMigrator.
*/
public static class Builder {
private final TypedValueNode<Double> versionNode;
private final List<VersionMigrator> versionMigrators;
/**
* Creates a new builder for a ConfigMigrator.
*
* @param versionNode The node that stores the version number of the config.
* Default value should be the current latest version number.
*/
public Builder(TypedValueNode<Double> versionNode) {
this.versionNode = versionNode;
this.versionMigrators = new ArrayList<>();
}
/**
* Adds a version migrator to the list of migrators.
*
* @param versionMigrator The migrator to add.
* @return The builder instance.
*/
public Builder addVersionMigrator(VersionMigrator versionMigrator) {
versionMigrators.add(versionMigrator);
return this;
}
/**
* Builds the ConfigMigrator.
*
* @return The built ConfigMigrator.
*/
public ConfigMigrator build() {
return new ConfigMigrator(versionNode, versionMigrators);
}
}
}

View File

@ -0,0 +1,28 @@
package com.onarandombox.MultiverseCore.configuration.migration;
import co.aikar.commands.ACFUtil;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.configuration.ConfigHandle;
import org.bukkit.util.NumberConversions;
/**
* Single migrator action that converts a string value to an integer.
*/
public class IntegerMigratorAction implements MigratorAction {
public static IntegerMigratorAction of(String path) {
return new IntegerMigratorAction(path);
}
private final String path;
public IntegerMigratorAction(String path) {
this.path = path;
}
@Override
public void migrate(ConfigHandle settings) {
settings.getConfig().set(path, ACFUtil.parseInt(settings.getConfig().getString(path)));
Logging.info("Converted %s to integer %s", path, settings.getConfig().getInt(path));
}
}

View File

@ -0,0 +1,36 @@
package com.onarandombox.MultiverseCore.configuration.migration;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.configuration.ConfigHandle;
/**
* Single migrator action that inverts a boolean value for a given path.
*/
public class InvertBoolMigratorAction implements MigratorAction {
/**
* Creates a new migrator action that inverts a boolean value for a given path.
*
* @param path The path to invert value of.
* @return The new migrator action.
*/
public static InvertBoolMigratorAction of(String path) {
return new InvertBoolMigratorAction(path);
}
private final String path;
protected InvertBoolMigratorAction(String path) {
this.path = path;
}
/**
* {@inheritDoc}
*/
@Override
public void migrate(ConfigHandle settings) {
boolean boolValue = !settings.getConfig().getBoolean(path);
settings.getConfig().set(path, boolValue);
Logging.info("Inverted %s to boolean %s", path, boolValue);
}
}

View File

@ -0,0 +1,16 @@
package com.onarandombox.MultiverseCore.configuration.migration;
import com.onarandombox.MultiverseCore.configuration.ConfigHandle;
/**
* A migrator action is a single action that is performed when migrating a config.
*/
public interface MigratorAction {
/**
* Performs the migration action.
*
* @param settings The target settings instance to migrate.
*/
void migrate(ConfigHandle settings);
}

View File

@ -0,0 +1,44 @@
package com.onarandombox.MultiverseCore.configuration.migration;
import java.util.Optional;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.configuration.ConfigHandle;
/**
* Single migrator action that moves a value from one path to another.
*/
public class MoveMigratorAction implements MigratorAction {
/**
* Creates a new migrator action that moves a value from one path to another.
*
* @param fromPath The path to move value from.
* @param toPath The path to move value to.
* @return The new migrator action.
*/
public static MoveMigratorAction of(String fromPath, String toPath) {
return new MoveMigratorAction(fromPath, toPath);
}
private final String fromPath;
private final String toPath;
protected MoveMigratorAction(String fromPath, String toPath) {
this.fromPath = fromPath;
this.toPath = toPath;
}
/**
* {@inheritDoc}
*/
@Override
public void migrate(ConfigHandle settings) {
Optional.ofNullable(settings.getConfig().get(fromPath))
.ifPresent(value -> {
settings.getConfig().set(toPath, value);
settings.getConfig().set(fromPath, null);
Logging.config("Moved path %s to %s", fromPath, toPath);
});
}
}

View File

@ -0,0 +1,85 @@
package com.onarandombox.MultiverseCore.configuration.migration;
import java.util.ArrayList;
import java.util.List;
import com.onarandombox.MultiverseCore.configuration.ConfigHandle;
/**
* A version migrator is a collection of migrator actions that are performed when migrating a config to a specific version.
*/
public class VersionMigrator {
/**
* Creates a new builder for a VersionMigrator.
*
* @param version The version number of the config that this migrator migrates to.
* @return The builder instance.
*/
public static Builder builder(double version) {
return new Builder(version);
}
private final double version;
private final List<MigratorAction> actions;
protected VersionMigrator(double version, List<MigratorAction> actions) {
this.version = version;
this.actions = actions;
}
/**
* Performs all the migrator actions.
*
* @param settings The target settings instance to migrate.
*/
public void migrate(ConfigHandle settings) {
actions.forEach(action -> action.migrate(settings));
}
/**
* Gets the version number of the config that this migrator migrates to.
*
* @return The version number.
*/
public double getVersion() {
return version;
}
/**
* A builder for a VersionMigrator.
*/
public static class Builder {
private final double version;
private final List<MigratorAction> actions = new ArrayList<>();
/**
* Creates a new builder for a VersionMigrator.
*
* @param version The version number of the config that this migrator migrates to.
*/
public Builder(double version) {
this.version = version;
}
/**
* Adds a migrator action to the list of actions.
*
* @param action The action to add.
* @return The builder instance.
*/
public Builder addAction(MigratorAction action) {
actions.add(action);
return this;
}
/**
* Builds the VersionMigrator.
*
* @return The built VersionMigrator.
*/
public VersionMigrator build() {
return new VersionMigrator(version, actions);
}
}
}

View File

@ -0,0 +1,29 @@
package com.onarandombox.MultiverseCore.configuration.node;
import java.util.Optional;
import io.github.townyadvanced.commentedconfiguration.setting.TypedValueNode;
/**
* A {@link TypedValueNode} that has a name, validation, and action to be performed when the value is set.
*
* @param <T> The type of the node's value.
*/
public interface EnhancedValueNode<T> extends TypedValueNode<T> {
/**
* Gets the name of this node. Used for identifying the node from user input.
*
* @return The name of this node.
*/
Optional<String> getName();
boolean isValid(T value);
/**
* Called when the value of this node is set.
*
* @param oldValue The old value.
* @param newValue The new value.
*/
void onSetValue(T oldValue, T newValue);
}

View File

@ -0,0 +1,91 @@
package com.onarandombox.MultiverseCore.configuration.node;
import java.util.ArrayList;
import java.util.List;
import io.github.townyadvanced.commentedconfiguration.setting.CommentedNode;
import org.jetbrains.annotations.NotNull;
/**
* Implementation of {@link CommentedNode} that allows for comments to be added to the node.
*/
public class MVCommentedNode implements CommentedNode {
/**
* Creates a new builder for a {@link MVCommentedNode}.
*
* @param path The path of the node.
* @return The new builder.
*/
public static 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;
}
/**
* {@inheritDoc}
*/
@Override
public @NotNull String getPath() {
return path;
}
/**
* {@inheritDoc}
*/
@Override
public @NotNull String[] getComments() {
return comments;
}
/**
* Builder for {@link MVCommentedNode}.
*
* @param <B> The type of the builder.
*/
public static class Builder<B extends Builder> {
protected final String path;
protected final List<String> comments;
/**
* Creates a new builder for a {@link MVCommentedNode}.
*
* @param path The path of the node.
*/
protected Builder(String path) {
this.path = path;
this.comments = new ArrayList<>();
}
/**
* Adds a comment line to the node.
*
* @param comment The comment to add.
* @return This builder.
*/
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;
}
/**
* Builds the node.
*
* @return The built node.
*/
public MVCommentedNode build() {
return new MVCommentedNode(path, comments.toArray(new String[0]));
}
}
}

View File

@ -0,0 +1,160 @@
package com.onarandombox.MultiverseCore.configuration.node;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Implementation of {@link EnhancedValueNode}.
* @param <T> The type of the value.
*/
public class MVValueNode<T> extends MVCommentedNode implements EnhancedValueNode<T> {
/**
* Creates a new builder for a {@link MVValueNode}.
*
* @param path The path of the node.
* @param type The type of the value.
* @return The new builder.
* @param <T> The type of the value.
*/
public static <T> Builder<T, ? extends Builder> builder(String path, Class<T> type) {
return new Builder<>(path, type);
}
protected final Class<T> type;
protected final T defaultValue;
protected final String name;
protected final Function<T, Boolean> validator;
protected final BiConsumer<T, T> onSetValue;
protected MVValueNode(String path, String[] comments, Class<T> type, T defaultValue, String name, Function<T, Boolean> validator, BiConsumer<T, T> onSetValue) {
super(path, comments);
this.type = type;
this.defaultValue = defaultValue;
this.name = name;
this.validator = validator;
this.onSetValue = onSetValue;
}
/**
* {@inheritDoc}
*/
@Override
public @NotNull Class<T> getType() {
return type;
}
/**
* {@inheritDoc}
*/
@Override
public @Nullable T getDefaultValue() {
return defaultValue;
}
/**
* {@inheritDoc}
*/
@Override
public Optional<String> getName() {
return Optional.ofNullable(name);
}
/**
* {@inheritDoc}
*/
@Override
public boolean isValid(T value) {
if (validator != null) {
return validator.apply(value);
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public void onSetValue(T oldValue, T newValue) {
if (onSetValue != null) {
onSetValue.accept(oldValue, newValue);
}
}
/**
* Builder for {@link MVValueNode}.
*
* @param <T> The type of the value.
* @param <B> The type of the builder.
*/
public static class Builder<T, B extends Builder<T, B>> extends MVCommentedNode.Builder<B> {
protected final Class<T> type;
protected T defaultValue;
protected String name;
protected Function<T, Boolean> validator;
protected BiConsumer<T, T> onSetValue;
/**
* Creates a new builder.
*
* @param path The path of the node.
* @param type The type of the value.
*/
protected Builder(@NotNull String path, @NotNull Class<T> type) {
super(path);
this.type = type;
this.name = path;
}
/**
* Sets the default value for this node.
*
* @param defaultValue The default value.
* @return This builder.
*/
public B defaultValue(@NotNull T defaultValue) {
this.defaultValue = defaultValue;
return (B) this;
}
/**
* Sets the name of this node. Used for identifying the node from user input.
*
* @param name The name of this node.
* @return This builder.
*/
public B name(@Nullable String name) {
this.name = name;
return (B) this;
}
public B validator(@Nullable Function<T, Boolean> validator) {
this.validator = validator;
return (B) this;
}
/**
* Sets the action to be performed when the value is set.
*
* @param onSetValue The action to be performed.
* @return This builder.
*/
public B onSetValue(@Nullable BiConsumer<T, T> onSetValue) {
this.onSetValue = onSetValue;
return (B) this;
}
/**
* {@inheritDoc}
*/
@Override
public MVValueNode<T> build() {
return new MVValueNode<>(path, comments.toArray(new String[0]), type, defaultValue, name, validator, onSetValue);
}
}
}

View File

@ -0,0 +1,135 @@
package com.onarandombox.MultiverseCore.configuration.node;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Optional;
import io.github.townyadvanced.commentedconfiguration.setting.CommentedNode;
import org.jetbrains.annotations.NotNull;
/**
* A collection of {@link CommentedNode}s, with mappings to nodes by name.
*/
public class NodeGroup implements Collection<CommentedNode> {
private final Collection<CommentedNode> nodes;
private final Map<String, CommentedNode> nodesMap;
public NodeGroup() {
this.nodes = new ArrayList<>();
this.nodesMap = new HashMap<>();
}
public NodeGroup(Collection<CommentedNode> nodes) {
this.nodes = nodes;
this.nodesMap = new HashMap<>(nodes.size());
nodes.forEach(this::addNodeIndex);
}
private void addNodeIndex(CommentedNode node) {
if (node instanceof EnhancedValueNode) {
((EnhancedValueNode<?>) node).getName().ifPresent(name -> nodesMap.put(name, node));
}
}
private void removeNodeIndex(CommentedNode node) {
if (node instanceof EnhancedValueNode) {
((EnhancedValueNode<?>) node).getName().ifPresent(nodesMap::remove);
}
}
/**
* Gets the names of all nodes in this group.
*
* @return The names of all nodes in this group.
*/
public Collection<String> getNames() {
return nodesMap.keySet();
}
/**
* Gets the node with the given name.
*
* @param name The name of the node to get.
* @return The node with the given name, or {@link Optional#empty()} if no node with the given name exists.
*/
public Optional<CommentedNode> findNode(String name) {
return Optional.ofNullable(nodesMap.get(name));
}
@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();
}
@Override
public Object @NotNull [] toArray() {
return nodes.toArray();
}
@Override
public <T> T @NotNull [] toArray(T @NotNull [] ts) {
return nodes.toArray(ts);
}
@Override
public boolean add(CommentedNode commentedNode) {
if (nodes.add(commentedNode)) {
addNodeIndex(commentedNode);
return true;
}
return false;
}
@Override
public boolean remove(Object o) {
if (nodes.remove(o) && o instanceof CommentedNode) {
removeNodeIndex((CommentedNode) o);
return true;
}
return false;
}
@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();
}
}

View File

@ -7,13 +7,11 @@ import java.util.stream.Collectors;
import co.aikar.commands.BukkitCommandIssuer;
import co.aikar.commands.CommandIssuer;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.Destination;
import com.onarandombox.MultiverseCore.api.DestinationInstance;
import com.onarandombox.MultiverseCore.api.SafeTTeleporter;
import com.onarandombox.MultiverseCore.api.Teleporter;
import jakarta.inject.Inject;
import org.bukkit.Server;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permission;

View File

@ -3,7 +3,7 @@ package com.onarandombox.MultiverseCore.listeners;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.config.MVCoreConfigProvider;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.inject.InjectableListener;
import jakarta.inject.Inject;
import org.bukkit.ChatColor;
@ -16,17 +16,17 @@ import org.jvnet.hk2.annotations.Service;
*/
@Service
public class MVChatListener implements InjectableListener {
private final MVCoreConfigProvider configProvider;
private final MVCoreConfig config;
private final MVWorldManager worldManager;
private final MVPlayerListener playerListener;
@Inject
public MVChatListener(
MVCoreConfigProvider configProvider,
MVCoreConfig config,
MVWorldManager worldManager,
MVPlayerListener playerListener
) {
this.configProvider = configProvider;
this.config = config;
this.worldManager = worldManager;
this.playerListener = playerListener;
}
@ -42,7 +42,7 @@ public class MVChatListener implements InjectableListener {
}
// Check whether the Server is set to prefix the chat with the World name.
// If not we do nothing, if so we need to check if the World has an Alias.
if (configProvider.getConfig().getPrefixChat()) {
if (config.isEnablePrefixChat()) {
String world = playerListener.getPlayerWorld().get(event.getPlayer().getName());
if (world == null) {
world = event.getPlayer().getWorld().getName();
@ -60,7 +60,7 @@ public class MVChatListener implements InjectableListener {
prefix = mvworld.getColoredWorldString();
String chat = event.getFormat();
String prefixChatFormat = configProvider.getConfig().getPrefixChatFormat();
String prefixChatFormat = config.getPrefixChatFormat();
prefixChatFormat = prefixChatFormat.replace("%world%", prefix).replace("%chat%", chat);
prefixChatFormat = ChatColor.translateAlternateColorCodes('&', prefixChatFormat);

View File

@ -11,7 +11,7 @@ import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.api.WorldPurger;
import com.onarandombox.MultiverseCore.config.MVCoreConfigProvider;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.inject.InjectableListener;
import jakarta.inject.Inject;
import org.bukkit.World;
@ -33,17 +33,17 @@ import org.jvnet.hk2.annotations.Service;
*/
@Service
public class MVEntityListener implements InjectableListener {
private final MVCoreConfigProvider configProvider;
private final MVCoreConfig config;
private final MVWorldManager worldManager;
private final WorldPurger worldPurger;
@Inject
public MVEntityListener(
@NotNull MVCoreConfigProvider configProvider,
@NotNull MVCoreConfig config,
@NotNull MVWorldManager worldManager,
@NotNull WorldPurger worldPurger
) {
this.configProvider = configProvider;
this.config = config;
this.worldManager = worldManager;
this.worldPurger = worldPurger;
}
@ -128,8 +128,8 @@ public class MVEntityListener implements InjectableListener {
if (event.isCancelled() || event.getTo() == null) {
return;
}
if (!this.configProvider.getConfig().isUsingDefaultPortalSearch()) {
event.setSearchRadius(this.configProvider.getConfig().getPortalSearchRadius());
if (!config.isUsingCustomPortalSearch()) {
event.setSearchRadius(config.getCustomPortalSearchRadius());
}
}
}

View File

@ -15,7 +15,7 @@ import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.SafeTTeleporter;
import com.onarandombox.MultiverseCore.config.MVCoreConfigProvider;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.event.MVRespawnEvent;
import com.onarandombox.MultiverseCore.inject.InjectableListener;
import com.onarandombox.MultiverseCore.utils.MVPermissions;
@ -45,7 +45,7 @@ import org.jvnet.hk2.annotations.Service;
@Service
public class MVPlayerListener implements InjectableListener {
private final Plugin plugin;
private final MVCoreConfigProvider configProvider;
private final MVCoreConfig config;
private final Provider<MVWorldManager> worldManagerProvider;
private final PermissionTools pt;
private final Provider<MVPermissions> mvPermsProvider;
@ -57,7 +57,7 @@ public class MVPlayerListener implements InjectableListener {
@Inject
public MVPlayerListener(
MultiverseCore plugin,
MVCoreConfigProvider configProvider,
MVCoreConfig config,
Provider<MVWorldManager> worldManagerProvider,
PermissionTools permissionTools,
Provider<MVPermissions> mvPermsProvider,
@ -65,7 +65,7 @@ public class MVPlayerListener implements InjectableListener {
Server server
) {
this.plugin = plugin;
this.configProvider = configProvider;
this.config = config;
this.worldManagerProvider = worldManagerProvider;
this.pt = permissionTools;
this.mvPermsProvider = mvPermsProvider;
@ -142,7 +142,7 @@ public class MVPlayerListener implements InjectableListener {
Player p = event.getPlayer();
if (!p.hasPlayedBefore()) {
Logging.finer("Player joined for the FIRST time!");
if (configProvider.getConfig().getFirstSpawnOverride()) {
if (config.getFirstSpawnOverride()) {
Logging.fine("Moving NEW player to(firstspawnoverride): "
+ getWorldManager().getFirstSpawnWorld().getSpawnLocation());
this.sendPlayerToDefaultWorld(p);
@ -150,7 +150,7 @@ public class MVPlayerListener implements InjectableListener {
return;
} else {
Logging.finer("Player joined AGAIN!");
if (this.configProvider.getConfig().getEnforceAccess() // check this only if we're enforcing access!
if (config.getEnforceAccess() // check this only if we're enforcing access!
&& !this.getMVPerms().hasPermission(p, "multiverse.access." + p.getWorld().getName(), false)) {
p.sendMessage("[MV] - Sorry you can't be in this world anymore!");
this.sendPlayerToDefaultWorld(p);
@ -222,7 +222,7 @@ public class MVPlayerListener implements InjectableListener {
}
// Check if player is allowed to enter the world if we're enforcing permissions
if (configProvider.getConfig().getEnforceAccess()) {
if (config.getEnforceAccess()) {
event.setCancelled(!pt.playerCanGoFromTo(fromWorld, toWorld, teleporter, teleportee));
if (event.isCancelled() && teleporter != null) {
Logging.fine("Player '" + teleportee.getName()
@ -314,7 +314,7 @@ public class MVPlayerListener implements InjectableListener {
+ "' because they don't have the FUNDS required to enter.");
return;
}
if (configProvider.getConfig().getEnforceAccess()) {
if (config.getEnforceAccess()) {
event.setCancelled(!pt.playerCanGoFromTo(fromWorld, toWorld, event.getPlayer(), event.getPlayer()));
if (event.isCancelled()) {
Logging.fine("Player '" + event.getPlayer().getName()
@ -326,8 +326,8 @@ public class MVPlayerListener implements InjectableListener {
+ "' was allowed to go to '" + event.getTo().getWorld().getName()
+ "' because enforceaccess is off.");
}
if (!this.configProvider.getConfig().isUsingDefaultPortalSearch()) {
event.setSearchRadius(this.configProvider.getConfig().getPortalSearchRadius());
if (!config.isUsingCustomPortalSearch()) {
event.setSearchRadius(config.getCustomPortalSearchRadius());
}
}

View File

@ -13,7 +13,7 @@ import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.api.MVDestination;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.config.MVCoreConfigProvider;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import jakarta.inject.Inject;
import org.bukkit.ChatColor;
import org.bukkit.Location;
@ -31,17 +31,17 @@ import org.jvnet.hk2.annotations.Service;
public class MVPermissions {
private final PluginManager pluginManager;
private final MVCoreConfigProvider configProvider;
private final MVCoreConfig config;
private final MVWorldManager worldMgr;
@Inject
public MVPermissions(
PluginManager pluginManager,
MVCoreConfigProvider configProvider,
MVCoreConfig config,
MVWorldManager worldManager
) {
this.pluginManager = pluginManager;
this.configProvider = configProvider;
this.config = config;
this.worldMgr = worldManager;
}
@ -108,7 +108,7 @@ public class MVPermissions {
*/
public boolean canEnterWorld(Player p, MVWorld w) {
// If we're not enforcing access, anyone can enter.
if (!configProvider.getConfig().getEnforceAccess()) {
if (!config.getEnforceAccess()) {
Logging.finest("EnforceAccess is OFF. Player was allowed in " + w.getAlias());
return true;
}

View File

@ -9,7 +9,7 @@ package com.onarandombox.MultiverseCore.utils;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.config.MVCoreConfigProvider;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.economy.MVEconomist;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
@ -27,19 +27,19 @@ import org.jvnet.hk2.annotations.Service;
@Service
public class PermissionTools {
private final MVCoreConfigProvider configProvider;
private final MVCoreConfig config;
private final PluginManager pluginManager;
private final Provider<MVPermissions> mvPermsProvider;
private final MVEconomist economist;
@Inject
public PermissionTools(
MVCoreConfigProvider configProvider,
MVCoreConfig config,
PluginManager pluginManager,
Provider<MVPermissions> mvPermsProvider,
MVEconomist economist)
{
this.configProvider = configProvider;
this.config = config;
this.pluginManager = pluginManager;
this.mvPermsProvider = mvPermsProvider;
this.economist = economist;
@ -123,7 +123,7 @@ public class PermissionTools {
*/
public boolean playerHasMoneyToEnter(MVWorld fromWorld, MVWorld toWorld, CommandSender teleporter, Player teleportee, boolean pay) {
Player teleporterPlayer;
if (configProvider.getConfig().getTeleportIntercept()) {
if (config.getTeleportIntercept()) {
if (teleporter instanceof ConsoleCommandSender) {
return true;
}
@ -219,7 +219,7 @@ public class PermissionTools {
Logging.finest("Checking '" + teleporter + "' can send '" + teleportee + "' somewhere");
Player teleporterPlayer;
if (configProvider.getConfig().getTeleportIntercept()) {
if (config.getTeleportIntercept()) {
// The console can send anyone anywhere
if (teleporter instanceof ConsoleCommandSender) {
return true;

View File

@ -1,7 +1,7 @@
package com.onarandombox.MultiverseCore.utils;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.config.MVCoreConfigProvider;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import jakarta.inject.Inject;
import org.jvnet.hk2.annotations.Service;
@ -12,11 +12,11 @@ import java.util.concurrent.Callable;
*/
@Service
public class UnsafeCallWrapper {
private final MVCoreConfigProvider configProvider;
private final MVCoreConfig config;
@Inject
public UnsafeCallWrapper(MVCoreConfigProvider configProvider) {
this.configProvider = configProvider;
public UnsafeCallWrapper(MVCoreConfig configProvider) {
this.config = configProvider;
}
/**
@ -40,7 +40,7 @@ public class UnsafeCallWrapper {
actualFormatArgs[formatArgs.length] = t;
Logging.warning(action, actualFormatArgs);
Logging.warning("This is a bug in %s, NOT a bug in Multiverse!", plugin);
if (configProvider.getConfig().getGlobalDebug() >= 1)
if (config.getGlobalDebug() >= 1)
t.printStackTrace();
return null;
}

View File

@ -13,13 +13,13 @@ import java.util.Map;
import java.util.UUID;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCoreConfiguration;
import com.onarandombox.MultiverseCore.api.BlockSafety;
import com.onarandombox.MultiverseCore.api.LocationManipulation;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.SafeTTeleporter;
import com.onarandombox.MultiverseCore.api.WorldPurger;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.exceptions.PropertyDoesNotExistException;
import com.onarandombox.MultiverseCore.listeners.MVPlayerListener;
import com.onarandombox.MultiverseCore.world.configuration.AllowedPortalType;
@ -55,6 +55,7 @@ public class SimpleMVWorld implements MVWorld {
private static final int SPAWN_LOCATION_SEARCH_RADIUS = 16;
private final MVWorldManager worldManager;
private final MVCoreConfig config;
private final WorldPurger worldPurger;
private final MVPlayerListener playerListener;
private final BlockSafety blockSafety;
@ -67,6 +68,7 @@ public class SimpleMVWorld implements MVWorld {
public SimpleMVWorld(
MVWorldManager worldManager,
MVCoreConfig config,
WorldPurger worldPurger,
MVPlayerListener playerListener,
BlockSafety blockSafety,
@ -76,7 +78,7 @@ public class SimpleMVWorld implements MVWorld {
World world,
WorldProperties properties
) {
this(worldManager, worldPurger, playerListener, blockSafety, safeTTeleporter,
this(worldManager, config, worldPurger, playerListener, blockSafety, safeTTeleporter,
locationManipulation, server, world, properties, true);
}
@ -85,6 +87,7 @@ public class SimpleMVWorld implements MVWorld {
*/
public SimpleMVWorld(
MVWorldManager worldManager,
MVCoreConfig config,
WorldPurger worldPurger,
MVPlayerListener playerListener,
BlockSafety blockSafety,
@ -96,6 +99,7 @@ public class SimpleMVWorld implements MVWorld {
boolean fixSpawn
) {
this.worldManager = worldManager;
this.config = config;
this.worldPurger = worldPurger;
this.playerListener = playerListener;
this.blockSafety = blockSafety;
@ -321,7 +325,7 @@ public class SimpleMVWorld implements MVWorld {
}
world.setSpawnFlags(allowMonsters, allowAnimals);
}
if (MultiverseCoreConfiguration.getInstance().isAutoPurgeEnabled()) {
if (config.isAutoPurgeEntities()) {
worldPurger.purgeWorld(SimpleMVWorld.this);
}
return super.validateChange(property, newValue, oldValue, object);

View File

@ -26,13 +26,13 @@ import java.util.stream.Collectors;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.MultiverseCoreConfiguration;
import com.onarandombox.MultiverseCore.api.BlockSafety;
import com.onarandombox.MultiverseCore.api.LocationManipulation;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.api.SafeTTeleporter;
import com.onarandombox.MultiverseCore.api.WorldPurger;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.event.MVWorldDeleteEvent;
import com.onarandombox.MultiverseCore.listeners.MVPlayerListener;
import com.onarandombox.MultiverseCore.utils.UnsafeCallWrapper;
@ -61,7 +61,10 @@ import org.jvnet.hk2.annotations.Service;
*/
@Service
public class SimpleMVWorldManager implements MVWorldManager {
public static final String WORLD_CONFIG_FILE = "worlds.yml";
private final MultiverseCore plugin;
private final MVCoreConfig config;
private final MVPlayerListener playerListener;
private final BlockSafety blockSafety;
private final SafeTTeleporter safeTTeleporter;
@ -78,6 +81,7 @@ public class SimpleMVWorldManager implements MVWorldManager {
@Inject
public SimpleMVWorldManager(
MultiverseCore plugin,
MVCoreConfig config,
MVPlayerListener playerListener,
BlockSafety blockSafety,
SafeTTeleporter safeTTeleporter,
@ -87,6 +91,7 @@ public class SimpleMVWorldManager implements MVWorldManager {
Server server
) {
this.plugin = plugin;
this.config = config;
this.playerListener = playerListener;
this.blockSafety = blockSafety;
this.safeTTeleporter = safeTTeleporter;
@ -512,9 +517,9 @@ public class SimpleMVWorldManager implements MVWorldManager {
nullWorld(worldName);
return false;
}
SimpleMVWorld world = new SimpleMVWorld(this, worldPurger, playerListener, blockSafety, safeTTeleporter,
locationManipulation, server, cbworld, mvworld);
if (MultiverseCoreConfiguration.getInstance().isAutoPurgeEnabled()) {
SimpleMVWorld world = new SimpleMVWorld(this, config, worldPurger, playerListener, blockSafety,
safeTTeleporter, locationManipulation, server, cbworld, mvworld);
if (config.isAutoPurgeEntities()) {
this.worldPurger.purgeWorld(world);
}
this.worlds.put(worldName, world);
@ -814,11 +819,12 @@ public class SimpleMVWorldManager implements MVWorldManager {
* {@inheritDoc}
*/
@Override
public FileConfiguration loadWorldConfig(File file) {
public FileConfiguration loadWorldsConfig() {
File file = new File(this.plugin.getDataFolder(), WORLD_CONFIG_FILE);
this.configWorlds = YamlConfiguration.loadConfiguration(file);
this.ensureConfigIsPrepared();
try {
this.configWorlds.save(new File(this.plugin.getDataFolder(), "worlds.yml"));
this.configWorlds.save(file);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();

View File

@ -182,10 +182,10 @@ public class TestWorldProperties {
assertFalse(thunderChangeOnEvent.isCancelled());
// call player chat event
core.getMVConfig().setPrefixChat(true);
core.getMVConfig().setEnablePrefixChat(true);
core.getChatListener().playerChat(playerChatEvent);
verify(playerChatEvent).setFormat("[" + mvWorld.getColoredWorldString() + "]" + "format");
core.getMVConfig().setPrefixChat(false);
core.getMVConfig().setEnablePrefixChat(false);
core.getChatListener().playerChat(playerChatEvent);
verify(playerChatEvent, times(1)).setFormat(anyString()); // only ONE TIME (not the 2nd time!)
@ -279,7 +279,7 @@ public class TestWorldProperties {
assertTrue(thunderChangeOnEvent.isCancelled());
// call player chat event
core.getMVConfig().setPrefixChat(true);
core.getMVConfig().setEnablePrefixChat(true);
core.getChatListener().playerChat(playerChatEvent);
// never because it's hidden!
verify(playerChatEvent, never()).setFormat(
@ -287,7 +287,7 @@ public class TestWorldProperties {
mvWorld.setHidden(false);
core.getChatListener().playerChat(playerChatEvent);
verify(playerChatEvent).setFormat("[" + mvWorld.getColoredWorldString() + "]" + "format");
core.getMVConfig().setPrefixChat(false);
core.getMVConfig().setEnablePrefixChat(false);
core.getChatListener().playerChat(playerChatEvent);
verify(playerChatEvent, times(1)).setFormat(anyString()); // only ONE TIME (not the 2nd time!)
mvWorld.setHidden(true); // reset hidden-state

View File

@ -16,14 +16,16 @@ abstract class TestWithMockBukkit {
protected lateinit var multiverseCore: MultiverseCore
@BeforeTest
fun setUp() {
fun setUpMockBukkit() {
TestingMode.enable()
server = MockBukkit.mock()
multiverseCore = MockBukkit.load(MultiverseCore::class.java)
}
@AfterTest
fun tearDown() {
fun tearDownMockBukkit() {
MockBukkit.unmock()
}
protected fun getResourceAsText(path: String): String? = object {}.javaClass.getResource(path)?.readText()
}

View File

@ -0,0 +1,95 @@
package org.mvplugins.multiverse.core.config
import com.onarandombox.MultiverseCore.config.MVCoreConfig
import org.mvplugins.multiverse.core.TestWithMockBukkit
import java.io.File
import java.nio.file.Path
import kotlin.io.path.absolutePathString
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertTrue
class ConfigTest : TestWithMockBukkit() {
private lateinit var config : MVCoreConfig
@BeforeTest
fun setUp() {
config = multiverseCore.getService(MVCoreConfig::class.java).takeIf { it != null } ?: run {
throw IllegalStateException("MVCoreConfig is not available as a service") }
val defaultConfig = getResourceAsText("/default_config.yml")
assertNotNull(defaultConfig)
File(Path.of(multiverseCore.dataFolder.absolutePath, "config.yml").absolutePathString()).writeText(defaultConfig)
assertTrue(config.load())
assertTrue(config.save())
}
@Test
fun `Config is loaded`() {
assertTrue(config.isLoaded)
}
@Test
fun `Old config is migrated`() {
val oldConfig = getResourceAsText("/old_config.yml")
assertNotNull(oldConfig)
File(Path.of(multiverseCore.dataFolder.absolutePath, "config.yml").absolutePathString()).writeText(oldConfig)
assertTrue(config.load())
assertTrue(config.save())
assertEquals(true, config.enforceAccess)
assertEquals(false, config.isEnablePrefixChat)
assertEquals("[%world%]>>%chat%", config.prefixChatFormat)
assertEquals(false, config.teleportIntercept)
assertEquals(true, config.firstSpawnOverride)
assertEquals(2, config.globalDebug)
assertEquals(false, config.silentStart)
assertEquals("world", config.firstSpawnLocation)
assertEquals(false, config.isUsingCustomPortalSearch)
assertEquals(128, config.customPortalSearchRadius)
assertEquals(true, config.isAutoPurgeEntities)
assertEquals(false, config.isShowingDonateMessage)
}
@Test
fun `Getting existing config property with getProperty returns expected value`() {
assertEquals(false, config.getProperty("enforce-access"))
assertEquals("world", config.getProperty("first-spawn-location"))
}
@Test
fun `Getting non-existing config property with getProperty returns null`() {
assertNull(config.getProperty("invalid-property"))
assertNull(config.getProperty("version"))
}
@Test
fun `Getting existing config property by getter returns expected value`() {
assertEquals(false, config.enforceAccess)
assertEquals("world", config.firstSpawnLocation)
}
@Test
fun `Updating an existing config property with setProperty reflects the changes in getProperty`() {
assertTrue(config.setProperty("enforce-access", true))
assertEquals(true, config.getProperty("enforce-access"))
assertTrue(config.setProperty("first-spawn-location", "world2"))
assertEquals("world2", config.getProperty("first-spawn-location"))
assertTrue(config.setProperty("global-debug", 1))
assertEquals(1, config.getProperty("global-debug"))
}
@Test
fun `Updating a non-existing property with setProperty returns false`() {
assertFalse(config.setProperty("invalid-property", false))
assertFalse(config.setProperty("version", 1.1))
}
}

View File

@ -10,7 +10,7 @@ import com.onarandombox.MultiverseCore.api.SafeTTeleporter
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand
import com.onarandombox.MultiverseCore.commandtools.PluginLocales
import com.onarandombox.MultiverseCore.config.MVCoreConfigProvider
import com.onarandombox.MultiverseCore.config.MVCoreConfig
import com.onarandombox.MultiverseCore.economy.MVEconomist
import com.onarandombox.MultiverseCore.listeners.MVChatListener
import com.onarandombox.MultiverseCore.listeners.MVEntityListener
@ -113,15 +113,15 @@ class InjectionTest : TestWithMockBukkit() {
}
@Test
fun `MVCoreConfigProvider is available as a service`() {
assertNotNull(multiverseCore.getService(MVCoreConfigProvider::class.java))
fun `MVCoreConfig is available as a service`() {
assertNotNull(multiverseCore.getService(MVCoreConfig::class.java))
}
@Test
fun `Commands are available as services`() {
val commands = multiverseCore.getAllServices(MultiverseCommand::class.java)
// TODO come up with a better way to test this like via actually testing the effect of calling each command
assertEquals(16, commands.size)
assertEquals(17, commands.size)
}
@Test
@ -131,13 +131,6 @@ class InjectionTest : TestWithMockBukkit() {
assertEquals(6, destinations.size)
}
@Test
fun `MVConfig is not available as a service`() {
// We need one test case for asking for non-services to make sure we don't accidentally make them available
// and that the getService method doesn't throw an exception
assertNull(multiverseCore.getService(MVConfig::class.java))
}
@Test
fun `MetricsConfigurator is not available as a service`() {
// Also making sure this is not loaded automatically since it's supposed to be disabled during tests

View File

@ -0,0 +1,96 @@
####################################################################################################
# #
# █▀▄▀█ █░█ █░░ ▀█▀ █ █░█ █▀▀ █▀█ █▀ █▀▀   █▀▀ █▀█ █▀█ █▀▀ #
# █░▀░█ █▄█ █▄▄ ░█░ █ ▀▄▀ ██▄ █▀▄ ▄█ ██▄   █▄▄ █▄█ █▀▄ ██▄ #
# #
# #
# WIKI: https://github.com/Multiverse/Multiverse-Core/wiki #
# DISCORD: https://discord.gg/NZtfKky #
# BUG REPORTS: https://github.com/Multiverse/Multiverse-Core/issues #
# #
# #
# Each option in this file is documented and explained here: #
# ==> https://github.com/Multiverse/Multiverse-Core/wiki/config.yml #
# #
# #
# New options are added to this file automatically. If you manually made changes #
# to this file while your server is running, please run `/mv reload` command. #
# #
####################################################################################################
world:
# This setting will prevent players from entering worlds they don't have access to.
# If this is set to false, players will be able to enter any world they want.
# If this is set to true, players will only be able to enter worlds they have
# the `mv.access.<worldname>` permission.
enforce-access: false
# Sets whether Multiverse will should enforce gamemode on world change.
# If enabled, players will be forced into the gamemode of the world they are entering, unless they have
# the `mv.bypass.gamemode.<worldname>` permission.
enforce-gamemode: true
# Sets whether Multiverse will purge mobs and entities with be automatically.
auto-purge-entities: true
# If this is set to true, Multiverse will enforce access permissions for all teleportation,
# including teleportation from other plugins.
teleport-intercept: true
spawn:
# Sets whether Multiverse will override the first spawn location of a world.
# If enabled, Multiverse will set the first spawn location of a world to the spawn location of the world.
# If disabled, it will default to server.properties settings.
first-spawn-override: true
# Sets the world that Multiverse will use as the location for players that first join the server.
# This only applies if first-spawn-override is set to true.
first-spawn-location: world
portal:
# This config option defines whether or not Multiverse should interfere with's Bukkit's default portal search radius.
# Setting it to false would mean you want to simply let Bukkit decides the search radius itself.
use-custom-portal-search: false
# This config option defines the search radius Multiverse should use when searching for a portal.
# This only applies if use-custom-portal-search is set to true.
custom-portal-search-radius: 128
messaging:
# This config option defines whether or not Multiverse should prefix the chat with the world name.
# This only applies if use-custom-portal-search is set to true.
enable-chat-prefix: false
# This config option defines the format Multiverse should use when prefixing the chat with the world name.
# This only applies if enable-chat-prefix is set to true.
chat-prefix-format: '[%world%]%chat%'
# This config option defines whether or not Multiverse should register the PlaceholderAPI hook.
# This only applies if PlaceholderAPI is installed.
register-papi-hook: true
misc:
# This is our debug flag to help identify issues with Multiverse.
# If you are having issues with Multiverse, please set this to 3 and then post your log to pastebin.com
# Otherwise, there's no need to touch this. If not instructed by a wiki page or developer.
# 0 = Off, No debug messages
# 1 = fine
# 2 = finer
# 3 = finest
global-debug: 3
# If true, the startup console messages will no longer show.
silent-start: false
# If you don't want to donate, you can set this to false and Multiverse will stop nagging you.
show-donation-message: true
# This just signifies the version number so we can see what version of config you have.
# NEVER TOUCH THIS VALUE
version: 5.0

View File

@ -0,0 +1,16 @@
multiverse-configuration:
==: com.onarandombox.MultiverseCore.MultiverseCoreConfiguration
enforceaccess: 'true'
prefixchat: 'false'
prefixchatformat: '[%world%]>>%chat%'
teleportintercept: 'false'
firstspawnoverride: 'true'
displaypermerrors: 'false'
globaldebug: '2'
silentstart: 'false'
version: '2.9'
firstspawnworld: world
defaultportalsearch: 'true'
portalsearchradius: '128'
autopurge: 'true'
idonotwanttodonate: 'true'