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})
public void cagePlayer(final CommandSender sender, final Player player, final String string)
{
switch (string.toLowerCase())
{
case "on" ->
if (string.equalsIgnoreCase("on"))
{
((Datura) getPlugin()).getCager()
.cagePlayer(player.getUniqueId());
sender.sendPlainMessage("Caged " + player.getName() + ".");
}
case "off" ->
} else if (string.equalsIgnoreCase("off"))
{
((Datura) getPlugin()).getCager()
.uncagePlayer(player.getUniqueId());
sender.sendPlainMessage("Liberated " + player.getName() + ".");
}
}
}
@Completion(args = {"[material]"}, index = 2)
@Subcommand(permission = "datura.cage.custom", args = {Player.class, String.class, Material.class})
public void cagePlayer(final CommandSender sender, final Player player, final String string,
final Material material)
{
switch (string.toLowerCase())
{
case "on" ->
if (string.equalsIgnoreCase("on"))
{
((Datura) getPlugin()).getCager()
.cagePlayer(player.getUniqueId(), material);
sender.sendPlainMessage("Caged " + player.getName() + ".");
}
case "off" ->
} else if (string.equalsIgnoreCase("off"))
{
((Datura) getPlugin()).getCager()
.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);
}
public void stop(final UUID uuid)
{
this.haltedPlayers.remove(uuid);
}
public void clear() {
this.haltedPlayers.clear();
}
@EventHandler
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;
import me.totalfreedom.api.Context;
import me.totalfreedom.command.annotation.Completion;
import me.totalfreedom.command.annotation.Subcommand;
import me.totalfreedom.provider.ContextProvider;
import me.totalfreedom.utils.logging.FreedomLogger;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
@ -120,7 +120,7 @@ public final class BukkitDelegate extends Command implements PluginIdentifiableC
final Subcommand node)
{
final Class<?>[] argTypes = node.args();
if (argTypes.length != args.length)
if (argTypes.length > args.length)
return;
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 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;
}
}
final Context<?> context = () -> provider.fromString(arg, argType);
objects[i] = context.get();
if (argType.equals(Location.class)) {
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
{
@ -183,7 +199,7 @@ public final class BukkitDelegate extends Command implements PluginIdentifiableC
"7",
"8",
"9"));
case "%location%" -> results.add("world,x,y,z");
case "%location%" -> results.add("world x y z");
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
* (current supported arguments can be found in the {@link ContextProvider}), and can also have a custom permission.
* These subcommands can also be annotated with {@link Completions} to provide tab completions for the subcommand. The
* subcommand method must be public, and must be in a class that is registered with the {@link CommandHandler}.
* <br>
* <i>(current supported arguments can be found in the {@link ContextProvider})</i>, and can also have a custom
* permission. These subcommands can also be annotated with {@link Completions} to provide tab completions for the
* subcommand. The subcommand method must be public, and must be in a class that is registered with the
* {@link CommandHandler}.
* <p>
* 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
* function as optional additional arguments for the subcommand, the previously registered arguments will still be
* 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
* 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
* {@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)
@Retention(RetentionPolicy.RUNTIME)

View File

@ -1,5 +1,8 @@
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 org.bukkit.Bukkit;
import org.bukkit.Location;
@ -13,6 +16,26 @@ import org.jetbrains.annotations.Nullable;
import java.util.Objects;
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 <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
* <br>
* <code>worldName,x,y,z</code>
* <br>
* When using this method, the next four arguments must be world, x, y, z.
* The world must be a valid world name, and x, y, and z must be valid doubles.
* If any of these are invalid, this will return null.
*
* @param string The string to parse
* @return A location object if xyz is valid
* @see BukkitDelegate#processSubCommands(String[], CommandSender, ContextProvider, Subcommand)
*/
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;
try {
final double x = Double.parseDouble(split[1]);
final double y = Double.parseDouble(split[2]);
final double z = Double.parseDouble(split[3]);
return new Location(toWorld(split[0]), x, y, z);
} catch (NumberFormatException ex) {
return null;
}
}
private @Nullable CommandSender toCommandSender(final String string)