Merge branch 'MV5' into world-revamp-continue

# Conflicts:
#	src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandCompletions.java
This commit is contained in:
Ben Woo 2023-09-10 14:05:41 +08:00
commit 1740137d1e
No known key found for this signature in database
GPG Key ID: FB2A3645536E12C8
9 changed files with 238 additions and 7 deletions

View File

@ -0,0 +1,132 @@
package com.onarandombox.MultiverseCore.commands;
import co.aikar.commands.CommandIssuer;
import co.aikar.commands.InvalidCommandArgument;
import co.aikar.commands.MessageType;
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.Flags;
import co.aikar.commands.annotation.Optional;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.Syntax;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.commandtools.MVCommandIssuer;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.commandtools.flags.CommandValueFlag;
import com.onarandombox.MultiverseCore.commandtools.flags.ParsedCommandFlags;
import com.onarandombox.MultiverseCore.display.ContentDisplay;
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.display.handlers.PagedSendHandler;
import com.onarandombox.MultiverseCore.display.parsers.MapContentProvider;
import com.onarandombox.MultiverseCore.utils.MVCorei18n;
import jakarta.inject.Inject;
import org.bukkit.ChatColor;
import org.bukkit.GameRule;
import org.bukkit.World;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
import java.util.HashMap;
import java.util.Map;
/**
* List all gamerules in your current or specified world.
*/
@Service
@CommandAlias("mv")
public class GamerulesCommand extends MultiverseCommand {
private final CommandValueFlag<Integer> PAGE_FLAG = flag(CommandValueFlag
.builder("--page", Integer.class)
.addAlias("-p")
.context(value -> {
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new InvalidCommandArgument("Invalid page number: " + value);
}
})
.build());
private final CommandValueFlag<ContentFilter> FILTER_FLAG = flag(CommandValueFlag
.builder("--filter", ContentFilter.class)
.addAlias("-f")
.context(value -> {
try {
return RegexContentFilter.fromString(value);
} catch (IllegalArgumentException e) {
throw new InvalidCommandArgument("Invalid filter: " + value);
}
})
.build());
@Inject
GamerulesCommand(@NotNull MVCommandManager commandManager) {
super(commandManager);
}
@Subcommand("gamerules|rules")
@CommandPermission("multiverse.core.gamerule.list")
@CommandCompletion("@mvworlds|@flags:groupName=mvgamerulescommand @flags:groupName=mvgamerulescommand")
@Syntax("[world] [--page <page>] [--filter <filter>]")
@Description("{@@mv-core.gamerules.description}")
public void onGamerulesCommand(
@NotNull MVCommandIssuer issuer,
@Flags("resolve=issuerAware")
@Syntax("<world>")
@Description("{@@mv-core.gamerules.description.world}")
MVWorld world,
@Optional
@Syntax("[--page <page>] [--filter <filter>]")
@Description("{@@mv-core.gamerules.description.page}")
String[] flags
) {
ParsedCommandFlags parsedFlags = parseFlags(flags);
ContentDisplay.create()
.addContent(new MapContentProvider<>(getGameRuleMap(world.getCBWorld()))
.withKeyColor(ChatColor.AQUA)
.withValueColor(ChatColor.WHITE))
.withSendHandler(new PagedSendHandler()
.withHeader(this.getTitle(issuer, world.getCBWorld()))
.doPagination(true)
.withTargetPage(parsedFlags.flagValue(PAGE_FLAG, 1))
.withFilter(parsedFlags.flagValue(FILTER_FLAG, DefaultContentFilter.get())))
.send(issuer);
}
/**
* Gets all the gamerules and their values for a given world.
*
* @param world The world to find gamerules for.
* @return A map of the gamerules and their values
*/
private Map<String, String> getGameRuleMap(World world) {
Map<String, String> gameRuleMap = new HashMap<>();
for (GameRule<?> gamerule : GameRule.values()) {
Object gameruleValue = world.getGameRuleValue(gamerule);
if (gameruleValue == null) {
gameRuleMap.put(gamerule.getName(), "null");
continue;
}
gameRuleMap.put(gamerule.getName(), gameruleValue.toString());
}
return gameRuleMap;
}
private String getTitle(CommandIssuer issuer, World world) {
return this.commandManager.formatMessage(
issuer,
MessageType.INFO,
MVCorei18n.GAMERULES_TITLE,
"{world}", world.getName());
}
}

View File

@ -14,6 +14,7 @@ import com.onarandombox.MultiverseCore.destination.ParsedDestination;
import com.onarandombox.MultiverseCore.worldnew.LoadedMultiverseWorld; import com.onarandombox.MultiverseCore.worldnew.LoadedMultiverseWorld;
import com.onarandombox.MultiverseCore.worldnew.MultiverseWorld; import com.onarandombox.MultiverseCore.worldnew.MultiverseWorld;
import com.onarandombox.MultiverseCore.worldnew.WorldManager; import com.onarandombox.MultiverseCore.worldnew.WorldManager;
import io.vavr.control.Try;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import org.bukkit.GameRule; import org.bukkit.GameRule;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -96,8 +97,11 @@ public class MVCommandCompletions extends PaperCommandCompletions {
} }
private Collection<String> suggestFlags(@NotNull BukkitCommandCompletionContext context) { private Collection<String> suggestFlags(@NotNull BukkitCommandCompletionContext context) {
return this.commandManager.getFlagsManager().suggest( String groupName = context.getConfig("groupName", "");
context.getConfig("groupName", ""), context.getContextValue(String[].class));
return Try.of(() -> context.getContextValue(String[].class))
.map(flags -> commandManager.getFlagsManager().suggest(groupName, flags))
.getOrElse(Collections.emptyList());
} }
private Collection<String> suggestGamerules() { private Collection<String> suggestGamerules() {

View File

@ -1,32 +1,54 @@
package com.onarandombox.MultiverseCore.commandtools; package com.onarandombox.MultiverseCore.commandtools;
import co.aikar.commands.BaseCommand; import co.aikar.commands.BaseCommand;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlag;
import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlagGroup; import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlagGroup;
import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlagsManager; import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlagsManager;
import com.onarandombox.MultiverseCore.commandtools.flags.ParsedCommandFlags; import com.onarandombox.MultiverseCore.commandtools.flags.ParsedCommandFlags;
import jakarta.annotation.PostConstruct;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Contract; import org.jvnet.hk2.annotations.Contract;
@Contract @Contract
public abstract class MultiverseCommand extends BaseCommand { public abstract class MultiverseCommand extends BaseCommand {
protected final MVCommandManager commandManager; protected final MVCommandManager commandManager;
private String flagGroupName; private String flagGroupName;
private CommandFlagGroup.Builder flagGroupBuilder;
protected MultiverseCommand(@NotNull MVCommandManager commandManager) { protected MultiverseCommand(@NotNull MVCommandManager commandManager) {
this.commandManager = commandManager; this.commandManager = commandManager;
} }
@PostConstruct
private void postConstruct() {
if (flagGroupBuilder != null) {
registerFlagGroup(flagGroupBuilder.build());
flagGroupBuilder = null;
}
}
protected CommandFlagsManager getFlagsManager() { protected CommandFlagsManager getFlagsManager() {
return commandManager.getFlagsManager(); return commandManager.getFlagsManager();
} }
protected <T extends CommandFlag> T flag(T flag) {
if (flagGroupBuilder == null) {
flagGroupBuilder = CommandFlagGroup.builder("mv" + getClass().getSimpleName().toLowerCase());
}
flagGroupBuilder.add(flag);
Logging.finest("Registered flag: " + flag);
return flag;
}
protected void registerFlagGroup(@NotNull CommandFlagGroup flagGroup) { protected void registerFlagGroup(@NotNull CommandFlagGroup flagGroup) {
if (flagGroupName != null) { if (flagGroupName != null) {
throw new IllegalStateException("Flag group already registered! (name: " + flagGroupName + ")"); throw new IllegalStateException("Flag group already registered! (name: " + flagGroupName + ")");
} }
getFlagsManager().registerFlagGroup(flagGroup); getFlagsManager().registerFlagGroup(flagGroup);
flagGroupName = flagGroup.getName(); flagGroupName = flagGroup.getName();
Logging.fine("Registered flag group: " + flagGroupName);
} }
protected @NotNull ParsedCommandFlags parseFlags(@NotNull String[] flags) { protected @NotNull ParsedCommandFlags parseFlags(@NotNull String[] flags) {

View File

@ -52,6 +52,17 @@ public class CommandFlag {
return aliases; return aliases;
} }
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return "Builder{"
+ "key='" + key + '\''
+ ", aliases=" + aliases
+ '}';
}
/** /**
* A builder for a flag. * A builder for a flag.
* *

View File

@ -190,7 +190,7 @@ public class CommandValueFlag<T> extends CommandFlag {
* @return The flag. * @return The flag.
*/ */
@Override @Override
public @NotNull CommandFlag build() { public @NotNull CommandValueFlag<T> build() {
if (context == null && !String.class.equals(type)) { if (context == null && !String.class.equals(type)) {
throw new IllegalStateException("Context is required for none-string value flags"); throw new IllegalStateException("Context is required for none-string value flags");
} }

View File

@ -15,7 +15,7 @@ public class ParsedCommandFlags
private final Map<String, Object> flagValues; private final Map<String, Object> flagValues;
public ParsedCommandFlags() { ParsedCommandFlags() {
flagValues = new HashMap<>(); flagValues = new HashMap<>();
} }
@ -29,6 +29,16 @@ public class ParsedCommandFlags
flagValues.put(key, value); flagValues.put(key, value);
} }
/**
* Check if a flag is present.
*
* @param flag The flag to check.
* @return True if the flag is present, false otherwise.
*/
public boolean hasFlag(@NotNull CommandFlag flag) {
return hasFlag(flag.getKey());
}
/** /**
* Check if a flag is present. * Check if a flag is present.
* *
@ -39,6 +49,12 @@ public class ParsedCommandFlags
return this.flagValues.containsKey(key); return this.flagValues.containsKey(key);
} }
/**
* Check if a flag is present and has a value.
*
* @param key The key of the flag.
* @return True if the flag is present and has a value, false otherwise.
*/
public boolean hasFlagValue(@Nullable String key) { public boolean hasFlagValue(@Nullable String key) {
return flagValue(key, Object.class) != null; return flagValue(key, Object.class) != null;
} }
@ -46,7 +62,20 @@ public class ParsedCommandFlags
/** /**
* Get the value of a flag. * Get the value of a flag.
* *
* @param key The key of the flag. * @param <T> The type of the value.
* @param flag The flag to get the value of.
* @param type The type of the value.
* @return The value of the flag, null if flag does not exist or no value.
*/
public @Nullable <T> T flagValue(@NotNull CommandFlag flag, @NotNull Class<T> type) {
return flagValue(flag.getKey(), type);
}
/**
* Get the value of a flag.
*
* @param key The key of the flag to get the value of.
* @param type The type of the value.
* @return The value of the flag, null if flag does not exist or no value. * @return The value of the flag, null if flag does not exist or no value.
*/ */
public @Nullable <T> T flagValue(@Nullable String key, @NotNull Class<T> type) { public @Nullable <T> T flagValue(@Nullable String key, @NotNull Class<T> type) {
@ -54,6 +83,27 @@ public class ParsedCommandFlags
return (T) value; return (T) value;
} }
/**
* Get the value of a flag.
*
* @param <T> The type of the value.
* @param flag The flag to get the value of.
* @param defaultValue The default value if flag does not exist or no value.
* @return The value of the flag, default value if flag does not exist or no value.
*/
public @NotNull <T> T flagValue(@NotNull CommandValueFlag<T> flag, @NotNull T defaultValue) {
return flagValue(flag.getKey(), defaultValue, flag.getType());
}
/**
* Get the value of a flag.
*
* @param <T> The type of the value.
* @param key The key of the flag to get the value of.
* @param defaultValue The default value if flag does not exist or no value.
* @param type The type of the value.
* @return The value of the flag, default value if flag does not exist or no value.
*/
public @NotNull <T> T flagValue(@Nullable String key, @NotNull T defaultValue, @NotNull Class<T> type) { public @NotNull <T> T flagValue(@Nullable String key, @NotNull T defaultValue, @NotNull Class<T> type) {
T value = flagValue(key, type); T value = flagValue(key, type);
return value != null ? value : defaultValue; return value != null ? value : defaultValue;

View File

@ -99,7 +99,7 @@ public class PagedSendHandler extends BaseSendHandler<PagedSendHandler> {
/** /**
* Sets whether display output should be paginated if is for console output. * Sets whether display output should be paginated if is for console output.
* This option will be useless of {@link PagedSendHandler#paginate} is set to false. * This option will be useless if {@link PagedSendHandler#paginate} is set to false.
* *
* @param paginateInConsole State of doing pagination in console. * @param paginateInConsole State of doing pagination in console.
* @return Same {@link PagedSendHandler} for method chaining. * @return Same {@link PagedSendHandler} for method chaining.

View File

@ -48,6 +48,12 @@ public enum MVCorei18n implements MessageKeyProvider {
GAMERULE_SUCCESS_SINGLE, GAMERULE_SUCCESS_SINGLE,
GAMERULE_SUCCESS_MULTIPLE, GAMERULE_SUCCESS_MULTIPLE,
// Gamerules command
GAMERULES_DESCRIPTION,
GAMERULES_DESCRIPTION_PAGE,
GAMERULES_DESCRIPTION_WORLD,
GAMERULES_TITLE,
// import command // import command
IMPORT_IMPORTING, IMPORT_IMPORTING,

View File

@ -66,6 +66,12 @@ mv-core.gamerule.failed=Failed to set gamerule {gamerule} to {value} in {world}.
mv-core.gamerule.success.single=&aSuccessfully set {gamerule} to {value} in {world}. mv-core.gamerule.success.single=&aSuccessfully set {gamerule} to {value} in {world}.
mv-core.gamerule.success.multiple=&aSuccessfully set {gamerule} to {value} in {count} worlds. mv-core.gamerule.success.multiple=&aSuccessfully set {gamerule} to {value} in {count} worlds.
# /mv gamerules
mv-core.gamerules.description=Lists gamerules for the specified world
mv-core.gamerules.description.page=The page to view
mv-core.gamerules.description.world=The world to list gamerules in
mv-core.gamerules.title= --- Gamerules for {world} ---
# /mv import # /mv import
mv-core.import.description=Imports an existing world folder. mv-core.import.description=Imports an existing world folder.
mv-core.import.name.description=Name of the world folder. mv-core.import.name.description=Name of the world folder.