From 9cf2c68fe80a84b172ca57d447073d7c2cdb4ae4 Mon Sep 17 00:00:00 2001 From: Zax71 <67716263+zax71@users.noreply.github.com> Date: Wed, 15 Feb 2023 02:25:53 +0000 Subject: [PATCH] feat: Implement gamerule command (#2840) * Feat: Add /gamerule Signed-off-by: Ben Woo <30431861+benwoo1110@users.noreply.github.com> * Chore: Accept sugguestion Co-authored-by: Ben Woo <30431861+benwoo1110@users.noreply.github.com> * Chore: Implement (most) suggestions from Ben * feat: Implement gamerule context * feat: Implement MVworld[] array context * feat: Implement context for gamerule value --------- Signed-off-by: Ben Woo <30431861+benwoo1110@users.noreply.github.com> Co-authored-by: Ben Woo <30431861+benwoo1110@users.noreply.github.com> --- .../MultiverseCore/MultiverseCore.java | 2 + .../commands/GameruleCommand.java | 63 ++++++++++++ .../commandtools/MVCommandCompletions.java | 13 ++- .../commandtools/MVCommandContexts.java | 96 ++++++++++++++++++- .../commandtools/context/GameRuleValue.java | 13 +++ 5 files changed, 182 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/onarandombox/MultiverseCore/commands/GameruleCommand.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/commandtools/context/GameRuleValue.java diff --git a/src/main/java/com/onarandombox/MultiverseCore/MultiverseCore.java b/src/main/java/com/onarandombox/MultiverseCore/MultiverseCore.java index 08c2b6f7..4f98cfae 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/MultiverseCore.java +++ b/src/main/java/com/onarandombox/MultiverseCore/MultiverseCore.java @@ -33,6 +33,7 @@ import com.onarandombox.MultiverseCore.commands.ConfirmCommand; import com.onarandombox.MultiverseCore.commands.CreateCommand; import com.onarandombox.MultiverseCore.commands.DebugCommand; import com.onarandombox.MultiverseCore.commands.DeleteCommand; +import com.onarandombox.MultiverseCore.commands.GameruleCommand; import com.onarandombox.MultiverseCore.commands.LoadCommand; import com.onarandombox.MultiverseCore.commands.RegenCommand; import com.onarandombox.MultiverseCore.commands.ReloadCommand; @@ -207,6 +208,7 @@ public class MultiverseCore extends JavaPlugin implements MVCore { this.commandManager.registerCommand(new CreateCommand(this)); this.commandManager.registerCommand(new DebugCommand(this)); this.commandManager.registerCommand(new DeleteCommand(this)); + this.commandManager.registerCommand(new GameruleCommand(this)); this.commandManager.registerCommand(new LoadCommand(this)); this.commandManager.registerCommand(new RegenCommand(this)); this.commandManager.registerCommand(new ReloadCommand(this)); diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/GameruleCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/GameruleCommand.java new file mode 100644 index 00000000..b1dadb73 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/GameruleCommand.java @@ -0,0 +1,63 @@ +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.Flags; +import co.aikar.commands.annotation.Subcommand; +import co.aikar.commands.annotation.Syntax; +import com.onarandombox.MultiverseCore.MultiverseCore; +import com.onarandombox.MultiverseCore.api.MVWorld; +import com.onarandombox.MultiverseCore.commandtools.context.GameRuleValue; +import org.bukkit.ChatColor; +import org.bukkit.GameRule; +import org.jetbrains.annotations.NotNull; + +@CommandAlias("mv") +public class GameruleCommand extends MultiverseCoreCommand { + public GameruleCommand(@NotNull MultiverseCore plugin) { + super(plugin); + } + + @Subcommand("gamerule") + @CommandPermission("multiverse.core.gamerule") + @CommandCompletion("@gamerules true|false|@range:1-10 @mvworlds|*") + @Syntax(" [World or *]") + @Description("Changes a gamerule in one or more worlds") + public void onGameruleCommand(BukkitCommandIssuer issuer, + + @Syntax("") + @Description("Gamerule to set") + GameRule gamerule, + + @Syntax("") + @Description("Value of gamerule") + GameRuleValue gameRuleValue, + + @Flags("resolve=issuerAware") + @Syntax("[World or *]") + @Description("World to apply gamerule to, current world by default") + MVWorld[] worlds + ) { + Object value = gameRuleValue.getValue(); + boolean success = true; + for(MVWorld world : worlds) { + // Set gamerules and add false to list if it fails + if (!world.getCBWorld().setGameRule(gamerule, value)) { + issuer.sendMessage(ChatColor.RED + "Failed to set gamerule " + gamerule.getName() + " to " + value + " in " + world.getName() + ". It should be a " + gamerule.getType()); + success = false; + } + } + // Tell user if it was successful + if (success) { + if (worlds.length == 1) { + issuer.sendMessage(ChatColor.GREEN + "Successfully set " + gamerule.getName() + " to " + value + " in " + worlds[0].getName()); + } + else if (worlds.length > 1) { + issuer.sendMessage(ChatColor.GREEN + "Successfully set " + gamerule.getName() + " to " + value + " in " + worlds.length + " worlds."); + } + } + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandCompletions.java b/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandCompletions.java index beb956b2..22e268a4 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandCompletions.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandCompletions.java @@ -1,9 +1,7 @@ package com.onarandombox.MultiverseCore.commandtools; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; import co.aikar.commands.BukkitCommandCompletionContext; import co.aikar.commands.BukkitCommandIssuer; @@ -11,6 +9,7 @@ import co.aikar.commands.PaperCommandCompletions; import com.onarandombox.MultiverseCore.MultiverseCore; import com.onarandombox.MultiverseCore.api.MVWorld; import com.onarandombox.MultiverseCore.api.MVWorldManager; +import org.bukkit.GameRule; import org.jetbrains.annotations.NotNull; public class MVCommandCompletions extends PaperCommandCompletions { @@ -27,6 +26,8 @@ public class MVCommandCompletions extends PaperCommandCompletions { registerAsyncCompletion("destinations", this::suggestDestinations); registerAsyncCompletion("flags", this::suggestFlags); registerAsyncCompletion("mvworlds", this::suggestMVWorlds); + // Only updates on first load, helps with lag + registerStaticCompletion("gamerules", this::suggestGamerules); } private Collection suggestDestinations(BukkitCommandCompletionContext context) { @@ -66,4 +67,8 @@ public class MVCommandCompletions extends PaperCommandCompletions { return worlds; } + + private Collection suggestGamerules() { + return Arrays.stream(GameRule.values()).map(GameRule::getName).collect(Collectors.toList()); + } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandContexts.java b/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandContexts.java index bb23131c..87aa8642 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandContexts.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandContexts.java @@ -4,14 +4,17 @@ import co.aikar.commands.BukkitCommandExecutionContext; import co.aikar.commands.BukkitCommandIssuer; 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.commandtools.context.GameRuleValue; 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 org.bukkit.GameRule; import org.bukkit.entity.Player; public class MVCommandContexts extends PaperCommandContexts { @@ -23,8 +26,11 @@ public class MVCommandContexts extends PaperCommandContexts { registerIssuerOnlyContext(BukkitCommandIssuer.class, BukkitCommandExecutionContext::getIssuer); registerOptionalContext(ContentFilter.class, this::parseContentFilter); - registerIssuerAwareContext(MVWorld.class, this::parseMVWorld); registerContext(ParsedDestination.class, this::parseDestination); + registerContext(GameRule.class, this::parseGameRule); + registerContext(GameRuleValue.class, this::parseGameRuleValue); + registerIssuerAwareContext(MVWorld.class, this::parseMVWorld); + registerIssuerAwareContext(MVWorld[].class, this::parseMVWorldArray); registerIssuerAwareContext(Player.class, this::parsePlayer); registerIssuerAwareContext(Player[].class, this::parsePlayerArray); } @@ -51,6 +57,43 @@ public class MVCommandContexts extends PaperCommandContexts { return parsedDestination; } + private GameRule parseGameRule(BukkitCommandExecutionContext context) { + String gameRuleName = context.popFirstArg(); + if (Strings.isNullOrEmpty(gameRuleName)) { + throw new InvalidCommandArgument("No game rule specified."); + } + + GameRule gameRule = GameRule.getByName(gameRuleName); + if (gameRule == null) { + throw new InvalidCommandArgument("The game rule " + gameRuleName + " is not valid."); + } + + return gameRule; + } + + private GameRuleValue parseGameRuleValue(BukkitCommandExecutionContext context) { + GameRule gameRule = (GameRule) context.getResolvedArg(GameRule.class); + if (gameRule == null) { + throw new InvalidCommandArgument("No game rule specified."); + } + String valueString = context.getFirstArg(); + if (Strings.isNullOrEmpty(valueString)) { + throw new InvalidCommandArgument("No game rule value specified."); + } + + ContextResolver resolver = getResolver(gameRule.getType()); + if (resolver == null) { + return new GameRuleValue(valueString); + } + + Object resolvedValue = resolver.getContext(context); + if (resolvedValue == null) { + throw new InvalidCommandArgument("The game rule value " + valueString + " is not valid for game rule " + gameRule.getName() + "."); + } + + return new GameRuleValue(resolvedValue); + } + private MVWorld parseMVWorld(BukkitCommandExecutionContext context) { String resolve = context.getFlagValue("resolve", ""); @@ -94,6 +137,57 @@ public class MVCommandContexts extends PaperCommandContexts { throw new InvalidCommandArgument("World " + worldName + " is not a loaded multiverse world."); } + private MVWorld[] parseMVWorldArray(BukkitCommandExecutionContext context) { + String resolve = context.getFlagValue("resolve", ""); + + MVWorld playerWorld = null; + if (context.getIssuer().isPlayer()) { + playerWorld = plugin.getMVWorldManager().getMVWorld(context.getIssuer().getPlayer().getWorld()); + } + + // Get world based on sender only + if (resolve.equals("issuerOnly")) { + if (playerWorld != null) { + return new MVWorld[]{playerWorld}; + } + 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(); + MVWorld world = plugin.getMVWorldManager().getMVWorld(worldName); + MVWorld[] worlds = "*".equals(worldName) + ? plugin.getMVWorldManager().getMVWorlds().toArray(new MVWorld[0]) + : (world != null ? new MVWorld[]{world} : null); + + // Get world based on input, fallback to sender if input is not a world + if (resolve.equals("issuerAware")) { + if (worlds != null) { + context.popFirstArg(); + return worlds; + } + if (playerWorld != null) { + return new MVWorld[]{playerWorld}; + } + if (context.isOptional()) { + return null; + } + throw new InvalidCommandArgument("Player is not in a Multiverse World."); + } + + // Get world based on input only + if (worlds != null) { + context.popFirstArg(); + return worlds; + } + if (!context.isOptional()) { + return null; + } + throw new InvalidCommandArgument("World " + worldName + " is not a loaded multiverse world."); + } + private Player parsePlayer(BukkitCommandExecutionContext context) { String resolve = context.getFlagValue("resolve", ""); diff --git a/src/main/java/com/onarandombox/MultiverseCore/commandtools/context/GameRuleValue.java b/src/main/java/com/onarandombox/MultiverseCore/commandtools/context/GameRuleValue.java new file mode 100644 index 00000000..c7fa2bdd --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/commandtools/context/GameRuleValue.java @@ -0,0 +1,13 @@ +package com.onarandombox.MultiverseCore.commandtools.context; + +public class GameRuleValue { + private final Object value; + + public GameRuleValue(Object value) { + this.value = value; + } + + public Object getValue() { + return value; + } +}