Merge branch 'MV5' into ben/mv5/teleporter

# Conflicts:
#	src/main/java/org/mvplugins/multiverse/core/commands/RemoveCommand.java
This commit is contained in:
Ben Woo 2023-09-21 11:23:05 +08:00
commit 980d6784df
No known key found for this signature in database
GPG Key ID: FB2A3645536E12C8
13 changed files with 240 additions and 109 deletions

View File

@ -71,7 +71,7 @@ class CreateCommand extends MultiverseCommand {
@Subcommand("create") @Subcommand("create")
@CommandPermission("multiverse.core.create") @CommandPermission("multiverse.core.create")
@CommandCompletion("@empty @flags:groupName=mvcreatecommand") @CommandCompletion("@empty @environments @flags:groupName=mvcreatecommand")
@Syntax("<name> <environment> --seed [seed] --generator [generator[:id]] --world-type [worldtype] --adjust-spawn --no-structures") @Syntax("<name> <environment> --seed [seed] --generator [generator[:id]] --world-type [worldtype] --adjust-spawn --no-structures")
@Description("{@@mv-core.create.description}") @Description("{@@mv-core.create.description}")
void onCreateCommand( void onCreateCommand(

View File

@ -54,7 +54,7 @@ class ImportCommand extends MultiverseCommand {
@Subcommand("import") @Subcommand("import")
@CommandPermission("multiverse.core.import") @CommandPermission("multiverse.core.import")
@CommandCompletion("@mvworlds:scope=potential @flags:groupName=mvimportcommand") @CommandCompletion("@mvworlds:scope=potential @environments @flags:groupName=mvimportcommand")
@Syntax("<name> <env> --generator [generator[:id]] --adjust-spawn") @Syntax("<name> <env> --generator [generator[:id]] --adjust-spawn")
@Description("{@@mv-core.import.description") @Description("{@@mv-core.import.description")
void onImportCommand( void onImportCommand(

View File

@ -23,6 +23,7 @@ import org.mvplugins.multiverse.core.commandtools.flags.CommandFlag;
import org.mvplugins.multiverse.core.commandtools.flags.ParsedCommandFlags; import org.mvplugins.multiverse.core.commandtools.flags.ParsedCommandFlags;
import org.mvplugins.multiverse.core.utils.MVCorei18n; import org.mvplugins.multiverse.core.utils.MVCorei18n;
import org.mvplugins.multiverse.core.utils.result.Async; import org.mvplugins.multiverse.core.utils.result.Async;
import org.mvplugins.multiverse.core.world.MultiverseWorld;
import org.mvplugins.multiverse.core.world.WorldManager; import org.mvplugins.multiverse.core.world.WorldManager;
import org.mvplugins.multiverse.core.world.helpers.PlayerWorldTeleporter; import org.mvplugins.multiverse.core.world.helpers.PlayerWorldTeleporter;
@ -59,7 +60,7 @@ class RemoveCommand extends MultiverseCommand {
@Conditions("mvworlds:scope=both @flags:groupName=mvremovecommand") @Conditions("mvworlds:scope=both @flags:groupName=mvremovecommand")
@Syntax("<world>") @Syntax("<world>")
@Description("{@@mv-core.remove.world.description}") @Description("{@@mv-core.remove.world.description}")
String worldName, MultiverseWorld world,
@Optional @Optional
@Syntax("[--remove-players]") @Syntax("[--remove-players]")
@ -68,19 +69,19 @@ class RemoveCommand extends MultiverseCommand {
ParsedCommandFlags parsedFlags = parseFlags(flags); ParsedCommandFlags parsedFlags = parseFlags(flags);
var future = parsedFlags.hasFlag(REMOVE_PLAYERS_FLAG) var future = parsedFlags.hasFlag(REMOVE_PLAYERS_FLAG)
? worldManager.getLoadedWorld(worldName) ? worldManager.getLoadedWorld(world)
.map(playerWorldTeleporter::removeFromWorld) .map(playerWorldTeleporter::removeFromWorld)
.getOrElse(Async.completedFuture(Collections.emptyList())) .getOrElse(Async.completedFuture(Collections.emptyList()))
: Async.completedFuture(Collections.emptyList()); : Async.completedFuture(Collections.emptyList());
future.thenRun(() -> doWorldRemoving(issuer, worldName)); future.thenRun(() -> doWorldRemoving(issuer, world));
} }
private void doWorldRemoving(MVCommandIssuer issuer, String worldName) { private void doWorldRemoving(MVCommandIssuer issuer, MultiverseWorld world) {
worldManager.removeWorld(worldName) worldManager.removeWorld(world)
.onSuccess(removedWorldName -> { .onSuccess(removedWorldName -> {
Logging.fine("World remove success: " + removedWorldName); Logging.fine("World remove success: " + removedWorldName);
issuer.sendInfo(MVCorei18n.REMOVEWORLD_REMOVED, "{world}", removedWorldName); issuer.sendInfo(MVCorei18n.REMOVE_SUCCESS, "{world}", removedWorldName);
}).onFailure(failure -> { }).onFailure(failure -> {
Logging.fine("World remove failure: " + failure); Logging.fine("World remove failure: " + failure);
issuer.sendError(failure.getFailureMessage()); issuer.sendError(failure.getFailureMessage());

View File

@ -3,6 +3,7 @@ package org.mvplugins.multiverse.core.commandtools;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -18,7 +19,10 @@ import com.dumptruckman.minecraft.util.Logging;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import io.vavr.control.Try; import io.vavr.control.Try;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import org.bukkit.Difficulty;
import org.bukkit.GameMode;
import org.bukkit.GameRule; import org.bukkit.GameRule;
import org.bukkit.World;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service; import org.jvnet.hk2.annotations.Service;
@ -30,19 +34,18 @@ import org.mvplugins.multiverse.core.world.MultiverseWorld;
import org.mvplugins.multiverse.core.world.WorldManager; import org.mvplugins.multiverse.core.world.WorldManager;
@Service @Service
public class MVCommandCompletions extends PaperCommandCompletions { class MVCommandCompletions extends PaperCommandCompletions {
protected final MVCommandManager commandManager; private final MVCommandManager commandManager;
private final WorldManager worldManager; private final WorldManager worldManager;
private final DestinationsProvider destinationsProvider; private final DestinationsProvider destinationsProvider;
@Inject @Inject
public MVCommandCompletions( MVCommandCompletions(
@NotNull MVCommandManager mvCommandManager, @NotNull MVCommandManager mvCommandManager,
@NotNull WorldManager worldManager, @NotNull WorldManager worldManager,
@NotNull DestinationsProvider destinationsProvider, @NotNull DestinationsProvider destinationsProvider,
@NotNull MVCoreConfig config @NotNull MVCoreConfig config) {
) {
super(mvCommandManager); super(mvCommandManager);
this.commandManager = mvCommandManager; this.commandManager = mvCommandManager;
this.worldManager = worldManager; this.worldManager = worldManager;
@ -50,13 +53,19 @@ public class MVCommandCompletions extends PaperCommandCompletions {
registerAsyncCompletion("commands", this::suggestCommands); registerAsyncCompletion("commands", this::suggestCommands);
registerAsyncCompletion("destinations", this::suggestDestinations); registerAsyncCompletion("destinations", this::suggestDestinations);
registerStaticCompletion("difficulties", suggestEnums(Difficulty.class));
registerStaticCompletion("environments", suggestEnums(World.Environment.class));
registerAsyncCompletion("flags", this::suggestFlags); registerAsyncCompletion("flags", this::suggestFlags);
registerStaticCompletion("gamemodes", suggestEnums(GameMode.class));
registerStaticCompletion("gamerules", this::suggestGamerules); registerStaticCompletion("gamerules", this::suggestGamerules);
registerStaticCompletion("mvconfigs", config.getNodes().getNames()); registerStaticCompletion("mvconfigs", config.getNodes().getNames());
registerAsyncCompletion("mvworlds", this::suggestMVWorlds); registerAsyncCompletion("mvworlds", this::suggestMVWorlds);
setDefaultCompletion("destinations", ParsedDestination.class); setDefaultCompletion("destinations", ParsedDestination.class);
setDefaultCompletion("difficulties", Difficulty.class);
setDefaultCompletion("environments", World.Environment.class);
setDefaultCompletion("flags", String[].class); setDefaultCompletion("flags", String[].class);
setDefaultCompletion("gamemodes", GameMode.class);
setDefaultCompletion("gamerules", GameRule.class); setDefaultCompletion("gamerules", GameRule.class);
setDefaultCompletion("mvworlds", LoadedMultiverseWorld.class); setDefaultCompletion("mvworlds", LoadedMultiverseWorld.class);
} }
@ -152,4 +161,11 @@ public class MVCommandCompletions extends PaperCommandCompletions {
Logging.severe("Invalid MVWorld scope: " + scope); Logging.severe("Invalid MVWorld scope: " + scope);
return Collections.emptyList(); return Collections.emptyList();
} }
private <T extends Enum<T>> Collection<String> suggestEnums(Class<T> enumClass) {
return EnumSet.allOf(enumClass).stream()
.map(Enum::name)
.map(String::toLowerCase)
.toList();
}
} }

View File

@ -27,10 +27,11 @@ import org.mvplugins.multiverse.core.display.filters.DefaultContentFilter;
import org.mvplugins.multiverse.core.display.filters.RegexContentFilter; import org.mvplugins.multiverse.core.display.filters.RegexContentFilter;
import org.mvplugins.multiverse.core.utils.PlayerFinder; import org.mvplugins.multiverse.core.utils.PlayerFinder;
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld; import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
import org.mvplugins.multiverse.core.world.MultiverseWorld;
import org.mvplugins.multiverse.core.world.WorldManager; import org.mvplugins.multiverse.core.world.WorldManager;
@Service @Service
public class MVCommandContexts extends PaperCommandContexts { class MVCommandContexts extends PaperCommandContexts {
private final MVCommandManager mvCommandManager; private final MVCommandManager mvCommandManager;
private final DestinationsProvider destinationsProvider; private final DestinationsProvider destinationsProvider;
@ -38,12 +39,11 @@ public class MVCommandContexts extends PaperCommandContexts {
private final MVCoreConfig config; private final MVCoreConfig config;
@Inject @Inject
public MVCommandContexts( MVCommandContexts(
MVCommandManager mvCommandManager, MVCommandManager mvCommandManager,
DestinationsProvider destinationsProvider, DestinationsProvider destinationsProvider,
WorldManager worldManager, WorldManager worldManager,
MVCoreConfig config MVCoreConfig config) {
) {
super(mvCommandManager); super(mvCommandManager);
this.mvCommandManager = mvCommandManager; this.mvCommandManager = mvCommandManager;
this.destinationsProvider = destinationsProvider; this.destinationsProvider = destinationsProvider;
@ -56,9 +56,10 @@ public class MVCommandContexts extends PaperCommandContexts {
registerContext(ParsedDestination.class, this::parseDestination); registerContext(ParsedDestination.class, this::parseDestination);
registerContext(GameRule.class, this::parseGameRule); registerContext(GameRule.class, this::parseGameRule);
registerContext(GameRuleValue.class, this::parseGameRuleValue); registerContext(GameRuleValue.class, this::parseGameRuleValue);
registerIssuerAwareContext(LoadedMultiverseWorld.class, this::parseLoadedMultiverseWorld);
registerIssuerAwareContext(LoadedMultiverseWorld[].class, this::parseLoadedMultiverseWorldArray);
registerIssuerAwareContext(MultiverseWorld.class, this::parseMultiverseWorld);
registerContext(MVConfigValue.class, this::parseMVConfigValue); registerContext(MVConfigValue.class, this::parseMVConfigValue);
registerIssuerAwareContext(LoadedMultiverseWorld.class, this::parseMVWorld);
registerIssuerAwareContext(LoadedMultiverseWorld[].class, this::parseMVWorldArray);
registerIssuerAwareContext(Player.class, this::parsePlayer); registerIssuerAwareContext(Player.class, this::parsePlayer);
registerIssuerAwareContext(Player[].class, this::parsePlayerArray); registerIssuerAwareContext(Player[].class, this::parsePlayerArray);
} }
@ -129,40 +130,7 @@ public class MVCommandContexts extends PaperCommandContexts {
return new GameRuleValue(resolvedValue); return new GameRuleValue(resolvedValue);
} }
private MVConfigValue parseMVConfigValue(BukkitCommandExecutionContext context) { private LoadedMultiverseWorld parseLoadedMultiverseWorld(BukkitCommandExecutionContext context) {
String configName = (String) context.getResolvedArg(String.class);
if (Strings.isNullOrEmpty(configName)) {
throw new InvalidCommandArgument("No config name specified.");
}
Option<Node> 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 ValueNode)) {
context.popFirstArg();
return new MVConfigValue(valueString);
}
ContextResolver<?, BukkitCommandExecutionContext> resolver = getResolver(((ValueNode<?>) 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 LoadedMultiverseWorld parseMVWorld(BukkitCommandExecutionContext context) {
String resolve = context.getFlagValue("resolve", ""); String resolve = context.getFlagValue("resolve", "");
// Get world based on sender only // Get world based on sender only
@ -205,7 +173,7 @@ public class MVCommandContexts extends PaperCommandContexts {
throw new InvalidCommandArgument("World " + worldName + " is not a loaded multiverse world."); throw new InvalidCommandArgument("World " + worldName + " is not a loaded multiverse world.");
} }
private LoadedMultiverseWorld[] parseMVWorldArray(BukkitCommandExecutionContext context) { private LoadedMultiverseWorld[] parseLoadedMultiverseWorldArray(BukkitCommandExecutionContext context) {
String resolve = context.getFlagValue("resolve", ""); String resolve = context.getFlagValue("resolve", "");
LoadedMultiverseWorld playerWorld = null; LoadedMultiverseWorld playerWorld = null;
@ -265,6 +233,82 @@ public class MVCommandContexts extends PaperCommandContexts {
throw new InvalidCommandArgument("World " + worldStrings + " is not a loaded multiverse world."); throw new InvalidCommandArgument("World " + worldStrings + " is not a loaded multiverse world.");
} }
private MultiverseWorld parseMultiverseWorld(BukkitCommandExecutionContext context) {
String resolve = context.getFlagValue("resolve", "");
// Get world based on sender only
if (resolve.equals("issuerOnly")) {
if (context.getIssuer().isPlayer()) {
return worldManager.getWorld(context.getIssuer().getPlayer().getWorld()).getOrNull();
}
if (context.isOptional()) {
return null;
}
throw new InvalidCommandArgument("This command can only be used by a player in a Multiverse World.");
}
String worldName = context.getFirstArg();
MultiverseWorld world = worldManager.getWorld(worldName).getOrNull();
// Get world based on input, fallback to sender if input is not a world
if (resolve.equals("issuerAware")) {
if (world != null) {
context.popFirstArg();
return world;
}
if (context.getIssuer().isPlayer()) {
return worldManager.getLoadedWorld(context.getIssuer().getPlayer().getWorld()).getOrNull();
}
if (context.isOptional()) {
return null;
}
throw new InvalidCommandArgument("Player is not in a Multiverse World.");
}
// Get world based on input only
if (world != null) {
context.popFirstArg();
return world;
}
if (context.isOptional()) {
return null;
}
throw new InvalidCommandArgument("World " + worldName + " is not a loaded multiverse world.");
}
private MVConfigValue parseMVConfigValue(BukkitCommandExecutionContext context) {
String configName = (String) context.getResolvedArg(String.class);
if (Strings.isNullOrEmpty(configName)) {
throw new InvalidCommandArgument("No config name specified.");
}
Option<Node> 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 ValueNode)) {
context.popFirstArg();
return new MVConfigValue(valueString);
}
ContextResolver<?, BukkitCommandExecutionContext> resolver = getResolver(((ValueNode<?>) 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 Player parsePlayer(BukkitCommandExecutionContext context) { private Player parsePlayer(BukkitCommandExecutionContext context) {
String resolve = context.getFlagValue("resolve", ""); String resolve = context.getFlagValue("resolve", "");

View File

@ -11,15 +11,26 @@ import org.mvplugins.multiverse.core.commandtools.flags.CommandFlagGroup;
import org.mvplugins.multiverse.core.commandtools.flags.CommandFlagsManager; import org.mvplugins.multiverse.core.commandtools.flags.CommandFlagsManager;
import org.mvplugins.multiverse.core.commandtools.flags.ParsedCommandFlags; import org.mvplugins.multiverse.core.commandtools.flags.ParsedCommandFlags;
/**
* Base class for all Multiverse commands.
*/
@Contract @Contract
public abstract class MultiverseCommand extends BaseCommand { public abstract class MultiverseCommand extends BaseCommand {
/**
* The command manager with multiverse specific methods.
*/
protected final MVCommandManager commandManager; protected final MVCommandManager commandManager;
/**
* The flags manager for the above command manager.
*/
protected final CommandFlagsManager flagsManager;
private String flagGroupName; private String flagGroupName;
private CommandFlagGroup.Builder flagGroupBuilder; private CommandFlagGroup.Builder flagGroupBuilder;
protected MultiverseCommand(@NotNull MVCommandManager commandManager) { protected MultiverseCommand(@NotNull MVCommandManager commandManager) {
this.commandManager = commandManager; this.commandManager = commandManager;
this.flagsManager = commandManager.getFlagsManager();
} }
@PostConstruct @PostConstruct
@ -30,10 +41,22 @@ public abstract class MultiverseCommand extends BaseCommand {
} }
} }
protected CommandFlagsManager getFlagsManager() { private void registerFlagGroup(@NotNull CommandFlagGroup flagGroup) {
return commandManager.getFlagsManager(); if (flagGroupName != null) {
throw new IllegalStateException("Flag group already registered! (name: " + flagGroupName + ")");
}
flagsManager.registerFlagGroup(flagGroup);
flagGroupName = flagGroup.getName();
Logging.finest("Registered flag group: " + flagGroupName);
} }
/**
* Add a new flag to the flag builder.
*
* @param flag The flag to add.
* @param <T> The type of the flag.
* @return The flag.
*/
protected <T extends CommandFlag> T flag(T flag) { protected <T extends CommandFlag> T flag(T flag) {
if (flagGroupBuilder == null) { if (flagGroupBuilder == null) {
flagGroupBuilder = CommandFlagGroup.builder("mv" + getClass().getSimpleName().toLowerCase()); flagGroupBuilder = CommandFlagGroup.builder("mv" + getClass().getSimpleName().toLowerCase());
@ -43,16 +66,13 @@ public abstract class MultiverseCommand extends BaseCommand {
return flag; return flag;
} }
protected void registerFlagGroup(@NotNull CommandFlagGroup flagGroup) { /**
if (flagGroupName != null) { * Parses flags.
throw new IllegalStateException("Flag group already registered! (name: " + flagGroupName + ")"); *
} * @param flags The raw string array to parse into flags.
getFlagsManager().registerFlagGroup(flagGroup); * @return The parsed flags.
flagGroupName = flagGroup.getName(); */
Logging.fine("Registered flag group: " + flagGroupName);
}
protected @NotNull ParsedCommandFlags parseFlags(@NotNull String[] flags) { protected @NotNull ParsedCommandFlags parseFlags(@NotNull String[] flags) {
return getFlagsManager().parse(flagGroupName, flags); return flagsManager.parse(flagGroupName, flags);
} }
} }

View File

@ -2,6 +2,7 @@ package org.mvplugins.multiverse.core.configuration.node;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier;
import io.vavr.control.Option; import io.vavr.control.Option;
import io.vavr.control.Try; import io.vavr.control.Try;
@ -10,6 +11,7 @@ import org.jetbrains.annotations.Nullable;
/** /**
* A node that contains a value. * A node that contains a value.
*
* @param <T> The type of the value. * @param <T> The type of the value.
*/ */
public class ConfigNode<T> extends ConfigHeaderNode implements ValueNode<T> { public class ConfigNode<T> extends ConfigHeaderNode implements ValueNode<T> {
@ -19,19 +21,18 @@ public class ConfigNode<T> extends ConfigHeaderNode implements ValueNode<T> {
* *
* @param path The path of the node. * @param path The path of the node.
* @param type The type of the value. * @param type The type of the value.
* @return The new builder.
* @param <T> The type of the value. * @param <T> The type of the value.
* @return The new builder.
*/ */
public static @NotNull <T> ConfigNode.Builder<T, ? extends ConfigNode.Builder<T, ?>> builder( public static @NotNull <T> ConfigNode.Builder<T, ? extends ConfigNode.Builder<T, ?>> builder(
@NotNull String path, @NotNull String path,
@NotNull Class<T> type @NotNull Class<T> type) {
) {
return new ConfigNode.Builder<>(path, type); return new ConfigNode.Builder<>(path, type);
} }
protected final @Nullable String name; protected final @Nullable String name;
protected final @NotNull Class<T> type; protected final @NotNull Class<T> type;
protected final @Nullable T defaultValue; protected final @Nullable Supplier<T> defaultValue;
protected final @Nullable NodeSerializer<T> serializer; protected final @Nullable NodeSerializer<T> serializer;
protected final @Nullable Function<T, Try<Void>> validator; protected final @Nullable Function<T, Try<Void>> validator;
protected final @Nullable BiConsumer<T, T> onSetValue; protected final @Nullable BiConsumer<T, T> onSetValue;
@ -41,11 +42,10 @@ public class ConfigNode<T> extends ConfigHeaderNode implements ValueNode<T> {
@NotNull String[] comments, @NotNull String[] comments,
@Nullable String name, @Nullable String name,
@NotNull Class<T> type, @NotNull Class<T> type,
@Nullable T defaultValue, @Nullable Supplier<T> defaultValue,
@Nullable NodeSerializer<T> serializer, @Nullable NodeSerializer<T> serializer,
@Nullable Function<T, Try<Void>> validator, @Nullable Function<T, Try<Void>> validator,
@Nullable BiConsumer<T, T> onSetValue @Nullable BiConsumer<T, T> onSetValue) {
) {
super(path, comments); super(path, comments);
this.name = name; this.name = name;
this.type = type; this.type = type;
@ -76,7 +76,10 @@ public class ConfigNode<T> extends ConfigHeaderNode implements ValueNode<T> {
*/ */
@Override @Override
public @Nullable T getDefaultValue() { public @Nullable T getDefaultValue() {
return defaultValue; if (defaultValue != null) {
return defaultValue.get();
}
return null;
} }
public @Nullable NodeSerializer<T> getSerializer() { public @Nullable NodeSerializer<T> getSerializer() {
@ -115,7 +118,7 @@ public class ConfigNode<T> extends ConfigHeaderNode implements ValueNode<T> {
protected @Nullable String name; protected @Nullable String name;
protected @NotNull final Class<T> type; protected @NotNull final Class<T> type;
protected @Nullable T defaultValue; protected @Nullable Supplier<T> defaultValue;
protected @Nullable NodeSerializer<T> serializer; protected @Nullable NodeSerializer<T> serializer;
protected @Nullable Function<T, Try<Void>> validator; protected @Nullable Function<T, Try<Void>> validator;
protected @Nullable BiConsumer<T, T> onSetValue; protected @Nullable BiConsumer<T, T> onSetValue;
@ -142,8 +145,19 @@ public class ConfigNode<T> extends ConfigHeaderNode implements ValueNode<T> {
* @return This builder. * @return This builder.
*/ */
public @NotNull B defaultValue(@NotNull T defaultValue) { public @NotNull B defaultValue(@NotNull T defaultValue) {
this.defaultValue = () -> defaultValue;
return self();
}
/**
* Sets the default value for this node.
*
* @param defaultValue The default value supplier.
* @return This builder.
*/
public @NotNull B defaultValue(@NotNull Supplier<T> defaultValue) {
this.defaultValue = defaultValue; this.defaultValue = defaultValue;
return (B) this; return self();
} }
/** /**
@ -154,17 +168,29 @@ public class ConfigNode<T> extends ConfigHeaderNode implements ValueNode<T> {
*/ */
public @NotNull B name(@Nullable String name) { public @NotNull B name(@Nullable String name) {
this.name = name; this.name = name;
return (B) this; return self();
} }
/**
* Sets the serializer for this node.
*
* @param serializer The serializer for this node.
* @return This builder.
*/
public @NotNull B serializer(@NotNull NodeSerializer<T> serializer) { public @NotNull B serializer(@NotNull NodeSerializer<T> serializer) {
this.serializer = serializer; this.serializer = serializer;
return (B) this; return self();
} }
/**
* Sets the validator for this node.
*
* @param validator The validator for this node.
* @return This builder.
*/
public @NotNull B validator(@NotNull Function<T, Try<Void>> validator) { public @NotNull B validator(@NotNull Function<T, Try<Void>> validator) {
this.validator = validator; this.validator = validator;
return (B) this; return self();
} }
/** /**
@ -175,7 +201,7 @@ public class ConfigNode<T> extends ConfigHeaderNode implements ValueNode<T> {
*/ */
public @NotNull B onSetValue(@NotNull BiConsumer<T, T> onSetValue) { public @NotNull B onSetValue(@NotNull BiConsumer<T, T> onSetValue) {
this.onSetValue = onSetValue; this.onSetValue = onSetValue;
return (B) this; return self();
} }
/** /**
@ -183,7 +209,13 @@ public class ConfigNode<T> extends ConfigHeaderNode implements ValueNode<T> {
*/ */
@Override @Override
public @NotNull ConfigNode<T> build() { public @NotNull ConfigNode<T> build() {
return new ConfigNode<>(path, comments.toArray(new String[0]), name, type, defaultValue, serializer, validator, onSetValue); return new ConfigNode<>(path, comments.toArray(new String[0]),
name, type, defaultValue,serializer, validator, onSetValue);
}
protected @NotNull B self() {
//noinspection unchecked
return (B) this;
} }
} }
} }

View File

@ -9,6 +9,7 @@ import java.util.Map;
import io.github.townyadvanced.commentedconfiguration.setting.CommentedNode; import io.github.townyadvanced.commentedconfiguration.setting.CommentedNode;
import io.vavr.control.Option; import io.vavr.control.Option;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* A collection of {@link CommentedNode}s, with mappings to nodes by name. * A collection of {@link CommentedNode}s, with mappings to nodes by name.
@ -17,24 +18,32 @@ public class NodeGroup implements Collection<Node> {
private final Collection<Node> nodes; private final Collection<Node> nodes;
private final Map<String, Node> nodesMap; private final Map<String, Node> nodesMap;
/**
* Creates a new empty node group.
*/
public NodeGroup() { public NodeGroup() {
this.nodes = new ArrayList<>(); this.nodes = new ArrayList<>();
this.nodesMap = new HashMap<>(); this.nodesMap = new HashMap<>();
} }
public NodeGroup(Collection<Node> nodes) { /**
* Creates a new node group with the given nodes.
*
* @param nodes The nodes to make up the group.
*/
public NodeGroup(@NotNull Collection<Node> nodes) {
this.nodes = nodes; this.nodes = nodes;
this.nodesMap = new HashMap<>(nodes.size()); this.nodesMap = new HashMap<>(nodes.size());
nodes.forEach(this::addNodeIndex); nodes.forEach(this::addNodeIndex);
} }
private void addNodeIndex(Node node) { private void addNodeIndex(@NotNull Node node) {
if (node instanceof ValueNode) { if (node instanceof ValueNode) {
((ValueNode<?>) node).getName().peek(name -> nodesMap.put(name, node)); ((ValueNode<?>) node).getName().peek(name -> nodesMap.put(name, node));
} }
} }
private void removeNodeIndex(Node node) { private void removeNodeIndex(@NotNull Node node) {
if (node instanceof ValueNode) { if (node instanceof ValueNode) {
((ValueNode<?>) node).getName().peek(nodesMap::remove); ((ValueNode<?>) node).getName().peek(nodesMap::remove);
} }
@ -45,32 +54,29 @@ public class NodeGroup implements Collection<Node> {
* *
* @return The names of all nodes in this group. * @return The names of all nodes in this group.
*/ */
public Collection<String> getNames() { public @NotNull Collection<String> getNames() {
return nodesMap.keySet(); return nodesMap.keySet();
} }
public Map<String, Node> getNodesMap() {
return nodesMap;
}
/** /**
* Gets the node with the given name. * Gets the node with the given name.
* *
* @param name The name of the node to get. * @param name The name of the node to get.
* @return The node with the given name, or {@link Option.None} if no node with the given name exists. * @return The node with the given name, or {@link Option.None} if no node with the given name exists.
*/ */
public Option<Node> findNode(String name) { public @NotNull Option<Node> findNode(@Nullable String name) {
return Option.of(nodesMap.get(name)); return Option.of(nodesMap.get(name));
} }
/** /**
* Gets the node with the given name. * Gets the node with the given name.
* *
* @param name The name of the node to get. * @param name The name of node to get.
* @param type The type of the node to get. * @param type The type of node to get.
* @param <T> The type of node.
* @return The node with the given name, or {@link Option.None} if no node with the given name exists. * @return The node with the given name, or {@link Option.None} if no node with the given name exists.
*/ */
public <T extends Node> Option<T> findNode(String name, Class<T> type) { public <T extends Node> @NotNull Option<T> findNode(@Nullable String name, @NotNull Class<T> type) {
return Option.of(nodesMap.get(name)).map(node -> type.isAssignableFrom(node.getClass()) ? (T) node : null); return Option.of(nodesMap.get(name)).map(node -> type.isAssignableFrom(node.getClass()) ? (T) node : null);
} }

View File

@ -43,6 +43,7 @@ public enum MVCorei18n implements MessageKeyProvider {
// delete command // delete command
DELETE_DELETING, DELETE_DELETING,
DELETE_PROMPT, DELETE_PROMPT,
DELETE_SUCCESS,
// Dumps command // Dumps command
DUMPS_DESCRIPTION, DUMPS_DESCRIPTION,
@ -76,6 +77,9 @@ public enum MVCorei18n implements MessageKeyProvider {
RELOAD_RELOADING, RELOAD_RELOADING,
RELOAD_SUCCESS, RELOAD_SUCCESS,
// remove command
REMOVE_SUCCESS,
// root MV command // root MV command
ROOT_TITLE, ROOT_TITLE,
ROOT_HELP, ROOT_HELP,
@ -115,7 +119,6 @@ public enum MVCorei18n implements MessageKeyProvider {
CREATEWORLD_WORLDEXISTLOADED, CREATEWORLD_WORLDEXISTLOADED,
CREATEWORLD_BUKKITCREATIONFAILED, CREATEWORLD_BUKKITCREATIONFAILED,
DELETE_SUCCESS,
DELETEWORLD_WORLDNONEXISTENT, DELETEWORLD_WORLDNONEXISTENT,
DELETEWORLD_LOADFAILED, DELETEWORLD_LOADFAILED,
DELETEWORLD_WORLDFOLDERNOTFOUND, DELETEWORLD_WORLDFOLDERNOTFOUND,
@ -133,7 +136,6 @@ public enum MVCorei18n implements MessageKeyProvider {
LOADWORLD_WORLDEXISTLOADED, LOADWORLD_WORLDEXISTLOADED,
LOADWORLD_BUKKITCREATIONFAILED, LOADWORLD_BUKKITCREATIONFAILED,
REMOVEWORLD_REMOVED,
REMOVEWORLD_WORLDNONEXISTENT, REMOVEWORLD_WORLDNONEXISTENT,
UNLOADWORLD_WORLDALREADYUNLOADING, UNLOADWORLD_WORLDALREADYUNLOADING,

View File

@ -726,6 +726,17 @@ public class WorldManager {
return !isLoadedWorld(worldName) && isWorld(worldName); return !isLoadedWorld(worldName) && isWorld(worldName);
} }
/**
* Get a world that may or may not be loaded. It will an {@link LoadedMultiverseWorld} if the world is loaded,
* otherwise returns an {@link MultiverseWorld} instance.
*
* @param world The bukkit world to get.
* @return The world if it exists.
*/
public Option<MultiverseWorld> getWorld(@Nullable World world) {
return Option.of(world).flatMap(this::getWorld);
}
/** /**
* Get a world that may or may not be loaded. It will an {@link LoadedMultiverseWorld} if the world is loaded, * Get a world that may or may not be loaded. It will an {@link LoadedMultiverseWorld} if the world is loaded,
* otherwise returns an {@link MultiverseWorld} instance. * otherwise returns an {@link MultiverseWorld} instance.

View File

@ -14,6 +14,7 @@ import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.mvplugins.multiverse.core.MultiverseCore;
import org.mvplugins.multiverse.core.configuration.handle.ConfigurationSectionHandle; import org.mvplugins.multiverse.core.configuration.handle.ConfigurationSectionHandle;
import org.mvplugins.multiverse.core.configuration.migration.BooleanMigratorAction; import org.mvplugins.multiverse.core.configuration.migration.BooleanMigratorAction;
import org.mvplugins.multiverse.core.configuration.migration.ConfigMigrator; import org.mvplugins.multiverse.core.configuration.migration.ConfigMigrator;
@ -23,7 +24,6 @@ import org.mvplugins.multiverse.core.configuration.migration.MoveMigratorAction;
import org.mvplugins.multiverse.core.configuration.migration.NullStringMigratorAction; import org.mvplugins.multiverse.core.configuration.migration.NullStringMigratorAction;
import org.mvplugins.multiverse.core.configuration.migration.VersionMigrator; import org.mvplugins.multiverse.core.configuration.migration.VersionMigrator;
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld; import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
import org.mvplugins.multiverse.core.world.helpers.EnforcementHandler;
/** /**
* Represents a world configuration. * Represents a world configuration.
@ -37,9 +37,9 @@ public final class WorldConfig {
WorldConfig( WorldConfig(
@NotNull String worldName, @NotNull String worldName,
@NotNull ConfigurationSection configSection, @NotNull ConfigurationSection configSection,
@NotNull EnforcementHandler enforcementHandler) { @NotNull MultiverseCore multiverseCore) {
this.worldName = worldName; this.worldName = worldName;
this.configNodes = new WorldConfigNodes(enforcementHandler); this.configNodes = new WorldConfigNodes(multiverseCore);
this.configHandle = ConfigurationSectionHandle.builder(configSection) this.configHandle = ConfigurationSectionHandle.builder(configSection)
.logger(Logging.getLogger()) .logger(Logging.getLogger())
.nodes(configNodes.getNodes()) .nodes(configNodes.getNodes())

View File

@ -10,10 +10,10 @@ import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.mvplugins.multiverse.core.MultiverseCore;
import org.mvplugins.multiverse.core.configuration.node.ConfigNode; import org.mvplugins.multiverse.core.configuration.node.ConfigNode;
import org.mvplugins.multiverse.core.configuration.node.Node; import org.mvplugins.multiverse.core.configuration.node.Node;
import org.mvplugins.multiverse.core.configuration.node.NodeGroup; import org.mvplugins.multiverse.core.configuration.node.NodeGroup;
import org.mvplugins.multiverse.core.world.config.AllowedPortalType;
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld; import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
import org.mvplugins.multiverse.core.world.helpers.EnforcementHandler; import org.mvplugins.multiverse.core.world.helpers.EnforcementHandler;
@ -27,8 +27,8 @@ public class WorldConfigNodes {
private EnforcementHandler enforcementHandler; private EnforcementHandler enforcementHandler;
private LoadedMultiverseWorld world = null; private LoadedMultiverseWorld world = null;
WorldConfigNodes(@NotNull EnforcementHandler enforcementHandler) { WorldConfigNodes(@NotNull MultiverseCore multiverseCore) {
this.enforcementHandler = enforcementHandler; this.enforcementHandler = multiverseCore.getService(EnforcementHandler.class);
} }
LoadedMultiverseWorld getWorld() { LoadedMultiverseWorld getWorld() {

View File

@ -21,7 +21,6 @@ import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service; import org.jvnet.hk2.annotations.Service;
import org.mvplugins.multiverse.core.MultiverseCore; import org.mvplugins.multiverse.core.MultiverseCore;
import org.mvplugins.multiverse.core.world.helpers.EnforcementHandler;
/** /**
* Manages the worlds.yml file. * Manages the worlds.yml file.
@ -35,14 +34,14 @@ public final class WorldsConfigManager {
private final File worldConfigFile; private final File worldConfigFile;
private YamlConfiguration worldsConfig; private YamlConfiguration worldsConfig;
private final EnforcementHandler enforcementHandler; private final MultiverseCore multiverseCore;
@Inject @Inject
WorldsConfigManager(@NotNull MultiverseCore core, @NotNull EnforcementHandler enforcementHandler) { WorldsConfigManager(@NotNull MultiverseCore core, @NotNull MultiverseCore multiverseCore) {
worldConfigMap = new HashMap<>(); worldConfigMap = new HashMap<>();
worldConfigFile = core.getDataFolder().toPath().resolve(CONFIG_FILENAME).toFile(); worldConfigFile = core.getDataFolder().toPath().resolve(CONFIG_FILENAME).toFile();
this.enforcementHandler = enforcementHandler; this.multiverseCore = multiverseCore;
} }
/** /**
@ -128,7 +127,7 @@ public final class WorldsConfigManager {
WorldConfig newWorldConfig = new WorldConfig( WorldConfig newWorldConfig = new WorldConfig(
worldName, worldName,
getWorldConfigSection(worldName), getWorldConfigSection(worldName),
enforcementHandler); multiverseCore);
worldConfigMap.put(worldName, newWorldConfig); worldConfigMap.put(worldName, newWorldConfig);
newWorldsAdded.add(newWorldConfig); newWorldsAdded.add(newWorldConfig);
}); });
@ -183,7 +182,7 @@ public final class WorldsConfigManager {
if (worldConfigMap.containsKey(worldName)) { if (worldConfigMap.containsKey(worldName)) {
throw new IllegalArgumentException("WorldConfig for world " + worldName + " already exists."); throw new IllegalArgumentException("WorldConfig for world " + worldName + " already exists.");
} }
WorldConfig worldConfig = new WorldConfig(worldName, getWorldConfigSection(worldName), enforcementHandler); WorldConfig worldConfig = new WorldConfig(worldName, getWorldConfigSection(worldName), multiverseCore);
worldConfigMap.put(worldName, worldConfig); worldConfigMap.put(worldName, worldConfig);
return worldConfig; return worldConfig;
} }