Minor fixes

This commit is contained in:
Paul Reilly 2023-06-10 21:41:14 -05:00
parent a22f7fb215
commit e18a0c0808
7 changed files with 203 additions and 47 deletions

View File

@ -48,37 +48,30 @@ public class CageCommand extends Commander
@Subcommand(permission = "datura.cage", args = {Player.class, String.class}) @Subcommand(permission = "datura.cage", args = {Player.class, String.class})
public void cagePlayer(final CommandSender sender, final Player player, final String string) public void cagePlayer(final CommandSender sender, final Player player, final String string)
{ {
switch (string.toLowerCase()) if (string.equalsIgnoreCase("on"))
{
case "on" ->
{ {
((Datura) getPlugin()).getCager() ((Datura) getPlugin()).getCager()
.cagePlayer(player.getUniqueId()); .cagePlayer(player.getUniqueId());
sender.sendPlainMessage("Caged " + player.getName() + "."); sender.sendPlainMessage("Caged " + player.getName() + ".");
} } else if (string.equalsIgnoreCase("off"))
case "off" ->
{ {
((Datura) getPlugin()).getCager() ((Datura) getPlugin()).getCager()
.uncagePlayer(player.getUniqueId()); .uncagePlayer(player.getUniqueId());
sender.sendPlainMessage("Liberated " + player.getName() + "."); sender.sendPlainMessage("Liberated " + player.getName() + ".");
} }
} }
}
@Completion(args = {"[material]"}, index = 2) @Completion(args = {"[material]"}, index = 2)
@Subcommand(permission = "datura.cage.custom", args = {Player.class, String.class, Material.class}) @Subcommand(permission = "datura.cage.custom", args = {Player.class, String.class, Material.class})
public void cagePlayer(final CommandSender sender, final Player player, final String string, public void cagePlayer(final CommandSender sender, final Player player, final String string,
final Material material) final Material material)
{ {
switch (string.toLowerCase()) if (string.equalsIgnoreCase("on"))
{
case "on" ->
{ {
((Datura) getPlugin()).getCager() ((Datura) getPlugin()).getCager()
.cagePlayer(player.getUniqueId(), material); .cagePlayer(player.getUniqueId(), material);
sender.sendPlainMessage("Caged " + player.getName() + "."); sender.sendPlainMessage("Caged " + player.getName() + ".");
} } else if (string.equalsIgnoreCase("off"))
case "off" ->
{ {
((Datura) getPlugin()).getCager() ((Datura) getPlugin()).getCager()
.uncagePlayer(player.getUniqueId()); .uncagePlayer(player.getUniqueId());
@ -86,4 +79,3 @@ public class CageCommand extends Commander
} }
} }
} }
}

View File

@ -0,0 +1,90 @@
package me.totalfreedom.datura.cmd;
import me.totalfreedom.base.Shortcuts;
import me.totalfreedom.command.Commander;
import me.totalfreedom.command.annotation.Info;
import me.totalfreedom.command.annotation.Permissive;
import me.totalfreedom.command.annotation.Subcommand;
import me.totalfreedom.datura.Datura;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
@Info(name = "halt", description = "Halt a single player, or every player.", usage = "/<command> <player | all> <on, off>")
@Permissive(perm = "datura.halt")
public class HaltCommand extends Commander
{
private final Datura plugin = Shortcuts.provideModule(Datura.class)
.getModule();
/**
* Initializes this command object. The provided {@link JavaPlugin} should be the plugin which contains the
* command.
* <p>
* This constructor will automatically register all subcommands and completions for this command. It will also
* automatically infer all required information from the provided {@link Info} and {@link Permissive} annotations.
*
* @param plugin The plugin which contains this command.
*/
protected HaltCommand(@NotNull final JavaPlugin plugin)
{
super(plugin);
}
@Subcommand(permission = "datura.halt", args = {Player.class, String.class})
public void haltPlayer(final CommandSender sender, final Player target, final String toggle)
{
if (toggle.equalsIgnoreCase("on"))
{
plugin.getHalter()
.halt(target.getUniqueId());
target.sendPlainMessage("You have been frozen!");
sender.sendPlainMessage("You have halted " + target.getName() + ".");
} else if (toggle.equalsIgnoreCase("off"))
{
plugin.getHalter()
.stop(target.getUniqueId());
target.sendPlainMessage("You have been unfrozen!");
sender.sendPlainMessage("You have unhalted " + target.getName() + ".");
}
}
@Subcommand(permission = "datura.halt.all", args = {String.class, String.class})
public void haltAll(final CommandSender sender, final String all, final String toggle)
{
if (all.equalsIgnoreCase("all"))
{
if (toggle.equalsIgnoreCase("on"))
{
Bukkit.getServer()
.getOnlinePlayers()
.forEach(player ->
{
plugin.getHalter()
.halt(player.getUniqueId());
});
final Component message = sender.name()
.append(Component.text(": Freezing all players"))
.color(NamedTextColor.AQUA);
Bukkit.broadcast(message);
sender.sendPlainMessage("All players have been halted.");
} else if (toggle.equalsIgnoreCase("off"))
{
plugin.getHalter()
.clear();
Bukkit.broadcast(Component.text("All players have been unfrozen!", NamedTextColor.AQUA));
sender.sendPlainMessage("All players have been unhalted.");
}
}
}
}

View File

@ -22,6 +22,15 @@ public class Halter implements Listener
this.haltedPlayers.add(uuid); this.haltedPlayers.add(uuid);
} }
public void stop(final UUID uuid)
{
this.haltedPlayers.remove(uuid);
}
public void clear() {
this.haltedPlayers.clear();
}
@EventHandler @EventHandler
public void playerMove(final PlayerMoveEvent event) public void playerMove(final PlayerMoveEvent event)
{ {

View File

@ -0,0 +1,15 @@
package me.totalfreedom.base;
import me.totalfreedom.provider.ModuleProvider;
import org.bukkit.plugin.java.JavaPlugin;
public final class Shortcuts
{
private Shortcuts() {
throw new AssertionError();
}
public static <T extends JavaPlugin> ModuleProvider<T> provideModule(final Class<T> pluginClass) {
return CommonsBase.getInstance().getRegistrations().getModuleRegistry().getProvider(pluginClass);
}
}

View File

@ -1,12 +1,12 @@
package me.totalfreedom.command; package me.totalfreedom.command;
import me.totalfreedom.api.Context;
import me.totalfreedom.command.annotation.Completion; import me.totalfreedom.command.annotation.Completion;
import me.totalfreedom.command.annotation.Subcommand; import me.totalfreedom.command.annotation.Subcommand;
import me.totalfreedom.provider.ContextProvider; import me.totalfreedom.provider.ContextProvider;
import me.totalfreedom.utils.logging.FreedomLogger; import me.totalfreedom.utils.logging.FreedomLogger;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -120,7 +120,7 @@ public final class BukkitDelegate extends Command implements PluginIdentifiableC
final Subcommand node) final Subcommand node)
{ {
final Class<?>[] argTypes = node.args(); final Class<?>[] argTypes = node.args();
if (argTypes.length != args.length) if (argTypes.length > args.length)
return; return;
final Object[] objects = new Object[argTypes.length + 1]; final Object[] objects = new Object[argTypes.length + 1];
@ -130,11 +130,27 @@ public final class BukkitDelegate extends Command implements PluginIdentifiableC
final Class<?> argType = argTypes[i]; final Class<?> argType = argTypes[i];
final String arg = args[i]; final String arg = args[i];
if (argType == String.class) if (argType.equals(String.class))
{
if (i == argTypes.length - 1)
{
final String[] reasonArgs = Arrays.copyOfRange(args, i, args.length - 1);
final String reason = String.join(" ", reasonArgs);
objects[i] = reason;
} else
{
continue; continue;
}
}
final Context<?> context = () -> provider.fromString(arg, argType); if (argType.equals(Location.class)) {
objects[i] = context.get(); final String[] locationArgs = Arrays.copyOfRange(args, i, i + 3);
final String location = String.join(" ", locationArgs);
objects[i] = location;
}
final Object obj = provider.fromString(arg, argType);
objects[i] = obj;
} }
try try
{ {
@ -183,7 +199,7 @@ public final class BukkitDelegate extends Command implements PluginIdentifiableC
"7", "7",
"8", "8",
"9")); "9"));
case "%location%" -> results.add("world,x,y,z"); case "%location%" -> results.add("world x y z");
default -> results.add(p); default -> results.add(p);
} }
} }

View File

@ -10,19 +10,26 @@ import java.lang.annotation.Target;
/** /**
* This annotation should be used to mark methods as subcommand methods. Subcommand methods can have custom arguments * This annotation should be used to mark methods as subcommand methods. Subcommand methods can have custom arguments
* (current supported arguments can be found in the {@link ContextProvider}), and can also have a custom permission. * <i>(current supported arguments can be found in the {@link ContextProvider})</i>, and can also have a custom
* These subcommands can also be annotated with {@link Completions} to provide tab completions for the subcommand. The * permission. These subcommands can also be annotated with {@link Completions} to provide tab completions for the
* subcommand method must be public, and must be in a class that is registered with the {@link CommandHandler}. * subcommand. The subcommand method must be public, and must be in a class that is registered with the
* <br> * {@link CommandHandler}.
* <p>
* Tab completions with the {@link Completions} annotation are only supported for subcommands. When registering * Tab completions with the {@link Completions} annotation are only supported for subcommands. When registering
* completions, you only need to define the completion arguments a single time. If there are other methods which * completions, you only need to define the completion arguments a single time. If there are other methods which
* function as optional additional arguments for the subcommand, the previously registered arguments will still be * function as optional additional arguments for the subcommand, the previously registered arguments will still be
* present when the user does their tab completion. * present when the user does their tab completion.
* <br> * <p>
* For example, if you have a subcommand method with the arguments {@code (Player, String)}, and another method which * For example, if you have a subcommand method with the arguments {@code (Player, String)}, and another method which
* has the arguments {@code (Player, String, String)}, the tab completions for the second method will still have the * has the arguments {@code (Player, String, String)}, the tab completions for the second method will still have the
* {@code Player} and {@code String} arguments registered from the first method. You will only need to provide a * {@code Player} and {@code String} arguments registered from the first method. You will only need to provide a
* {@link Completion} for the additional 3rd argument. * {@link Completion} for the additional 3rd argument.
* <p>
* Additionally, if the final argument is a String object, the BukkitDelegate will automatically append any additional
* arguments to the end of the String. For example, if you have a subcommand method with the arguments
* {@code (Player, String)}, and the user executes the command with the arguments {@code /command playerName arg2 arg3},
* the {@code String} argument will be {@code "arg2 arg3"}. This allows for us to use a String at the end of our
* subcommand arguments to allow for the user to input a reason.
*/ */
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)

View File

@ -1,5 +1,8 @@
package me.totalfreedom.provider; package me.totalfreedom.provider;
import me.totalfreedom.api.Context;
import me.totalfreedom.command.BukkitDelegate;
import me.totalfreedom.command.annotation.Subcommand;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
@ -13,6 +16,26 @@ import org.jetbrains.annotations.Nullable;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Stream; import java.util.stream.Stream;
/**
* This class is used to provide context to subcommand methods. This class is used by the BukkitDelegate to parse
* arguments for subcommands. The following types are supported:
* <ul>
* <li>Boolean</li>
* <li>Double</li>
* <li>Integer</li>
* <li>Long</li>
* <li>Float</li>
* <li>Material</li>
* <li>Player</li>
* <li>World</li>
* <li>Location</li>
* <li>CommandSender</li>
* <li>Component</li>
* </ul>
* All of these types can be parsed from a String input. If the String cannot be parsed into any of
* these types, then null will be returned.
* @see #fromString(String, Class)
*/
public class ContextProvider public class ContextProvider
{ {
public <T> T fromString(final String string, final Class<T> clazz) public <T> T fromString(final String string, final Class<T> clazz)
@ -104,25 +127,29 @@ public class ContextProvider
} }
/** /**
* When using this method, the input string must be formatted as * When using this method, the next four arguments must be world, x, y, z.
* <br> * The world must be a valid world name, and x, y, and z must be valid doubles.
* <code>worldName,x,y,z</code> * If any of these are invalid, this will return null.
* <br>
* *
* @param string The string to parse * @param string The string to parse
* @return A location object if xyz is valid * @return A location object if xyz is valid
* @see BukkitDelegate#processSubCommands(String[], CommandSender, ContextProvider, Subcommand)
*/ */
private @Nullable Location toLocation(final String string) private @Nullable Location toLocation(final String string)
{ {
final String[] split = string.split(","); final String[] split = string.split(" ");
if (split.length != 4 || toWorld(split[0]) == null) return null; if (split.length != 4 || toWorld(split[0]) == null) return null;
try {
final double x = Double.parseDouble(split[1]); final double x = Double.parseDouble(split[1]);
final double y = Double.parseDouble(split[2]); final double y = Double.parseDouble(split[2]);
final double z = Double.parseDouble(split[3]); final double z = Double.parseDouble(split[3]);
return new Location(toWorld(split[0]), x, y, z); return new Location(toWorld(split[0]), x, y, z);
} catch (NumberFormatException ex) {
return null;
}
} }
private @Nullable CommandSender toCommandSender(final String string) private @Nullable CommandSender toCommandSender(final String string)