1
0
Fork 0
mirror of https://github.com/xHyroM/lighteco.git synced 2024-11-22 15:01:05 +01:00

feat(better command abstraction)!: switch to brigadier (#8)

* feat: switch to brigadier

* some updates

* feat: make suggestion provider work

* supress warnings

* feat: pay & set command

* feat: give & take command, better suggestions, permissions

* refactor: cleanup

* fix: dont register pay if currency is not payable

* fix: send commands only if you have perms

* make second test currency not payable

* feat: use command's description & name
This commit is contained in:
Jozef Steinhübl 2024-07-03 17:58:07 +02:00 committed by GitHub
parent 802d90a459
commit 35eebc1609
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 858 additions and 378 deletions

View file

@ -28,6 +28,7 @@ subprojects {
repositories { repositories {
mavenCentral() mavenCentral()
maven("https://storehouse.okaeri.eu/repository/maven-public/") maven("https://storehouse.okaeri.eu/repository/maven-public/")
maven("https://libraries.minecraft.net")
} }
} }

View file

@ -5,7 +5,7 @@ plugins {
repositories { repositories {
maven("https://repo.extendedclip.com/content/repositories/placeholderapi") maven("https://repo.extendedclip.com/content/repositories/placeholderapi")
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") maven("https://repo.papermc.io/repository/maven-public/")
maven("https://oss.sonatype.org/content/repositories/snapshots") maven("https://oss.sonatype.org/content/repositories/snapshots")
maven("https://oss.sonatype.org/content/repositories/central") maven("https://oss.sonatype.org/content/repositories/central")
} }
@ -13,10 +13,10 @@ repositories {
dependencies { dependencies {
implementation(project(":lighteco-common")) implementation(project(":lighteco-common"))
implementation("dev.jorel:commandapi-bukkit-shade:9.5.0")
implementation("net.kyori:adventure-platform-bukkit:4.2.0") implementation("net.kyori:adventure-platform-bukkit:4.2.0")
compileOnly("org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT") compileOnly("io.papermc.paper:paper-api:1.19.1-R0.1-SNAPSHOT")
compileOnly("io.papermc.paper:paper-mojangapi:1.19.1-R0.1-SNAPSHOT")
// PlaceholderAPI // PlaceholderAPI
compileOnly("me.clip:placeholderapi:2.11.3") compileOnly("me.clip:placeholderapi:2.11.3")
@ -29,7 +29,9 @@ dependencies {
} }
tasks.shadowJar { tasks.shadowJar {
relocate("dev.jorel.commandapi", "dev.xhyrom.lighteco.libraries.commandapi") dependencies {
exclude(dependency("com.mojang:brigadier"))
}
// common // common
relocate("eu.okaeri.configs", "dev.xhyrom.lighteco.libraries.okaeri.configs") relocate("eu.okaeri.configs", "dev.xhyrom.lighteco.libraries.okaeri.configs")

View file

@ -1,7 +1,5 @@
package dev.xhyrom.lighteco.bukkit; package dev.xhyrom.lighteco.bukkit;
import dev.jorel.commandapi.CommandAPI;
import dev.jorel.commandapi.CommandAPIBukkitConfig;
import dev.xhyrom.lighteco.bukkit.logger.BukkitLogger; import dev.xhyrom.lighteco.bukkit.logger.BukkitLogger;
import dev.xhyrom.lighteco.common.plugin.bootstrap.LightEcoBootstrap; import dev.xhyrom.lighteco.common.plugin.bootstrap.LightEcoBootstrap;
import dev.xhyrom.lighteco.common.plugin.bootstrap.LoaderBootstrap; import dev.xhyrom.lighteco.common.plugin.bootstrap.LoaderBootstrap;
@ -42,14 +40,10 @@ public class BukkitLightEcoBootstrap implements LightEcoBootstrap, LoaderBootstr
@Override @Override
public void onLoad() { public void onLoad() {
this.plugin.load(); this.plugin.load();
CommandAPI.onLoad(new CommandAPIBukkitConfig(this.loader)
.verboseOutput(this.getPlugin().getConfig().debug)
);
} }
@Override @Override
public void onEnable() { public void onEnable() {
CommandAPI.onEnable();
this.plugin.enable(); this.plugin.enable();
this.audience = BukkitAudiences.create(loader); this.audience = BukkitAudiences.create(loader);
@ -57,7 +51,6 @@ public class BukkitLightEcoBootstrap implements LightEcoBootstrap, LoaderBootstr
@Override @Override
public void onDisable() { public void onDisable() {
CommandAPI.onDisable();
this.plugin.disable(); this.plugin.disable();
} }
@ -68,7 +61,7 @@ public class BukkitLightEcoBootstrap implements LightEcoBootstrap, LoaderBootstr
@Override @Override
public Optional<UUID> lookupUniqueId(String username) { public Optional<UUID> lookupUniqueId(String username) {
return Optional.ofNullable(this.loader.getServer().getOfflinePlayer(username)).map(OfflinePlayer::getUniqueId); return Optional.of(this.loader.getServer().getOfflinePlayer(username)).map(OfflinePlayer::getUniqueId);
} }
@Override @Override

View file

@ -4,6 +4,7 @@ import dev.xhyrom.lighteco.api.LightEco;
import dev.xhyrom.lighteco.api.manager.ContextManager; import dev.xhyrom.lighteco.api.manager.ContextManager;
import dev.xhyrom.lighteco.api.platform.Platform; import dev.xhyrom.lighteco.api.platform.Platform;
import dev.xhyrom.lighteco.bukkit.hooks.Hooks; import dev.xhyrom.lighteco.bukkit.hooks.Hooks;
import dev.xhyrom.lighteco.bukkit.listeners.BukkitCommandSuggestionsListener;
import dev.xhyrom.lighteco.bukkit.listeners.BukkitConnectionListener; import dev.xhyrom.lighteco.bukkit.listeners.BukkitConnectionListener;
import dev.xhyrom.lighteco.bukkit.manager.BukkitCommandManager; import dev.xhyrom.lighteco.bukkit.manager.BukkitCommandManager;
import dev.xhyrom.lighteco.bukkit.manager.BukkitContextManager; import dev.xhyrom.lighteco.bukkit.manager.BukkitContextManager;
@ -36,6 +37,7 @@ public class BukkitLightEcoPlugin extends AbstractLightEcoPlugin {
@Override @Override
protected void registerListeners() { protected void registerListeners() {
this.bootstrap.getLoader().getServer().getPluginManager().registerEvents(new BukkitConnectionListener(this), this.bootstrap.getLoader()); this.bootstrap.getLoader().getServer().getPluginManager().registerEvents(new BukkitConnectionListener(this), this.bootstrap.getLoader());
this.bootstrap.getLoader().getServer().getPluginManager().registerEvents(new BukkitCommandSuggestionsListener(this), this.bootstrap.getLoader());
} }
@Override @Override

View file

@ -0,0 +1,45 @@
package dev.xhyrom.lighteco.bukkit.brigadier;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.mojang.brigadier.tree.ArgumentCommandNode;
import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.LiteralCommandNode;
import com.mojang.brigadier.tree.RootCommandNode;
import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.Map;
public class BukkitBrigadier {
private static final Field CHILDREN_FIELD;
private static final Field LITERALS_FIELD;
private static final Field ARGUMENTS_FIELD;
private static final Field[] CHILDREN_FIELDS;
static {
try {
CHILDREN_FIELD = CommandNode.class.getDeclaredField("children");
LITERALS_FIELD = CommandNode.class.getDeclaredField("literals");
ARGUMENTS_FIELD = CommandNode.class.getDeclaredField("arguments");
CHILDREN_FIELDS = new Field[]{CHILDREN_FIELD, LITERALS_FIELD, ARGUMENTS_FIELD};
for (Field field : CHILDREN_FIELDS) {
field.setAccessible(true);
}
} catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}
@SuppressWarnings("unchecked")
public static void removeChild(RootCommandNode<?> root, String name) {
try {
for (Field field : CHILDREN_FIELDS) {
Map<String, ?> children = (Map<String, ?>) field.get(root);
children.remove(name);
}
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
}

View file

@ -32,6 +32,11 @@ public class BukkitCommandSender extends AbstractCommandSender<CommandSender> {
return null; return null;
} }
@Override
public boolean eligible(String permission) {
return this.delegate.hasPermission(permission);
}
@Override @Override
public void sendMessage(Component message) { public void sendMessage(Component message) {
this.audience.sendMessage(message); this.audience.sendMessage(message);

View file

@ -0,0 +1,43 @@
package dev.xhyrom.lighteco.bukkit.listeners;
import com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent;
import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.LiteralCommandNode;
import dev.xhyrom.lighteco.bukkit.BukkitLightEcoPlugin;
import dev.xhyrom.lighteco.bukkit.brigadier.BukkitBrigadier;
import dev.xhyrom.lighteco.bukkit.chat.BukkitCommandSender;
import dev.xhyrom.lighteco.common.command.CommandSource;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
public class BukkitCommandSuggestionsListener implements Listener {
private final BukkitLightEcoPlugin plugin;
public BukkitCommandSuggestionsListener(BukkitLightEcoPlugin plugin) {
this.plugin = plugin;
}
@SuppressWarnings({"rawtypes", "unchecked", "deprecation"})
@EventHandler
public void onPlayerSendCommandsEvent(AsyncPlayerSendCommandsEvent<?> event) {
BukkitCommandSender sender = new BukkitCommandSender(event.getPlayer(), this.plugin.getCommandManager().audienceFactory);
CommandSource source = new CommandSource(this.plugin, sender);
if (event.isAsynchronous() || !event.hasFiredAsync()) {
for (CommandNode<CommandSource> command : this.plugin.getCommandManager().getDispatcher().getRoot().getChildren()) {
BukkitBrigadier.removeChild(event.getCommandNode(), command.getName());
BukkitBrigadier.removeChild(event.getCommandNode(), command.getName() + ":" + command.getName());
if (!command.canUse(source)) continue;
CommandNode<CommandSource> clone = new LiteralCommandNode(command.getName(), command.getCommand(), command.getRequirement(), command.getRedirect(), command.getRedirectModifier(), command.isFork());
for (CommandNode<CommandSource> child : command.getChildren()) {
if (child.canUse(source))
clone.addChild(child);
}
event.getCommandNode().addChild((CommandNode) clone);
}
}
}
}

View file

@ -1,18 +1,23 @@
package dev.xhyrom.lighteco.bukkit.manager; package dev.xhyrom.lighteco.bukkit.manager;
import com.mojang.brigadier.ParseResults;
import com.mojang.brigadier.tree.CommandNode;
import dev.xhyrom.lighteco.bukkit.chat.BukkitCommandSender; import dev.xhyrom.lighteco.bukkit.chat.BukkitCommandSender;
import dev.xhyrom.lighteco.common.command.CommandManager; import dev.xhyrom.lighteco.common.command.CommandManager;
import dev.xhyrom.lighteco.common.command.CommandSource;
import dev.xhyrom.lighteco.common.command.abstraction.Command;
import dev.xhyrom.lighteco.common.model.currency.Currency; import dev.xhyrom.lighteco.common.model.currency.Currency;
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin; import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandMap; import org.bukkit.command.CommandMap;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
public class BukkitCommandManager extends CommandManager { public class BukkitCommandManager extends CommandManager {
public final BukkitAudiences audienceFactory; public final BukkitAudiences audienceFactory;
@ -34,16 +39,50 @@ public class BukkitCommandManager extends CommandManager {
} }
@Override @Override
public void register(Currency currency, boolean main) { public Command[] register(Currency currency, boolean main) {
super.register(currency, main); Command[] commands = super.register(currency, main);
for (Command command : commands) {
this.registerToBukkit(command);
}
return commands;
}
private void registerToBukkit(Command command) {
org.bukkit.command.Command bukkitCommand = new org.bukkit.command.Command(
command.getName(),
command.getDescription(),
"/" + command.getName(),
command.getAliases()
) {
private final CommandNode<CommandSource> node = getDispatcher().getRoot().getChild(getName());
commandMap.register(currency.getIdentifier(), new Command(currency.getIdentifier()) {
@Override @Override
public boolean execute(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] strings) { public boolean execute(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] strings) {
bukkitCommandManagerExecute(new BukkitCommandSender(commandSender, audienceFactory), s, strings); bukkitCommandManagerExecute(new BukkitCommandSender(commandSender, audienceFactory), s, strings);
return true; return true;
} }
});
@Override
public @NotNull List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws IllegalArgumentException {
final List<String> suggestions = new ArrayList<>();
final CommandSource source = new CommandSource(plugin, new BukkitCommandSender(sender, audienceFactory));
final ParseResults<CommandSource> parseResults = getDispatcher().parse(
getName() + (args.length > 0 ? " " + String.join(" ", args) : ""),
source
);
getDispatcher().getCompletionSuggestions(
parseResults
).join().getList().forEach(suggestion -> suggestions.add(suggestion.getText()));
return suggestions;
}
};
commandMap.register(command.getName(), bukkitCommand);
} }
private void bukkitCommandManagerExecute(dev.xhyrom.lighteco.common.model.chat.CommandSender sender, String name, String[] args) { private void bukkitCommandManagerExecute(dev.xhyrom.lighteco.common.model.chat.CommandSender sender, String name, String[] args) {

View file

@ -18,7 +18,7 @@ public class TestCurrency2 implements Currency {
@Override @Override
public boolean isPayable() { public boolean isPayable() {
return true; return false;
} }
@Override @Override

View file

@ -2,10 +2,6 @@ plugins {
id("lighteco.shadow-logic") id("lighteco.shadow-logic")
} }
repositories {
maven("https://libraries.minecraft.net")
}
dependencies { dependencies {
api(project(":lighteco-api")) api(project(":lighteco-api"))
api("org.checkerframework:checker-qual:3.8.0") api("org.checkerframework:checker-qual:3.8.0")
@ -23,7 +19,7 @@ dependencies {
implementation("eu.okaeri:okaeri-configs-yaml-snakeyaml:5.0.0-beta.5") implementation("eu.okaeri:okaeri-configs-yaml-snakeyaml:5.0.0-beta.5")
implementation("eu.okaeri:okaeri-configs-validator-okaeri:5.0.0-beta.5") implementation("eu.okaeri:okaeri-configs-validator-okaeri:5.0.0-beta.5")
implementation("com.mojang:brigadier:1.0.18") compileOnly("com.mojang:brigadier:1.0.18")
compileOnly("com.zaxxer:HikariCP:5.0.1") compileOnly("com.zaxxer:HikariCP:5.0.1")
compileOnly("redis.clients:jedis:5.1.0") compileOnly("redis.clients:jedis:5.1.0")

View file

@ -1,21 +1,28 @@
package dev.xhyrom.lighteco.common.command; package dev.xhyrom.lighteco.common.command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.ParseResults;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import dev.xhyrom.lighteco.common.command.abstraction.Command; import dev.xhyrom.lighteco.common.command.abstraction.Command;
import dev.xhyrom.lighteco.common.command.argument.Arguments;
import dev.xhyrom.lighteco.common.commands.BalanceCommand; import dev.xhyrom.lighteco.common.commands.BalanceCommand;
import dev.xhyrom.lighteco.common.commands.BalanceOtherCommand;
import dev.xhyrom.lighteco.common.commands.CurrencyParentCommand; import dev.xhyrom.lighteco.common.commands.CurrencyParentCommand;
import dev.xhyrom.lighteco.common.commands.PayCommand;
import dev.xhyrom.lighteco.common.model.chat.CommandSender; import dev.xhyrom.lighteco.common.model.chat.CommandSender;
import dev.xhyrom.lighteco.common.model.currency.Currency; import dev.xhyrom.lighteco.common.model.currency.Currency;
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin; import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
import lombok.Getter;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class CommandManager { public class CommandManager {
protected final LightEcoPlugin plugin; protected final LightEcoPlugin plugin;
private final List<Command> commands = new ArrayList<>(); @Getter
private final CommandDispatcher<CommandSource> dispatcher = new CommandDispatcher<>();
public CommandManager(LightEcoPlugin plugin) { public CommandManager(LightEcoPlugin plugin) {
this.plugin = plugin; this.plugin = plugin;
@ -25,32 +32,53 @@ public class CommandManager {
register(currency, false); register(currency, false);
} }
public void register(Currency currency, boolean main) { public Command[] register(Currency currency, boolean main) {
List<Command> commands = new ArrayList<>();
commands.add(new CurrencyParentCommand(currency)); commands.add(new CurrencyParentCommand(currency));
dispatcher.getRoot().addChild(commands.get(0).build());
if (main) { if (main) {
commands.add(BalanceCommand.create(currency)); commands.add(BalanceCommand.create(currency));
commands.add(BalanceOtherCommand.create(currency)); commands.add(PayCommand.create(currency));
dispatcher.getRoot().addChild(commands.get(1).build());
dispatcher.getRoot().addChild(commands.get(2).build());
} }
return commands.toArray(new Command[0]);
} }
public void execute(CommandSender sender, String name, String[] args) { public void execute(CommandSender sender, String name, String[] args) {
List<Command> possibleCommands = this.commands.stream() final CommandSource source = new CommandSource(this.plugin, sender);
.filter(cmd -> cmd.getName().equalsIgnoreCase(name)) final ParseResults<CommandSource> parseResults = dispatcher.parse(
.toList(); name + (args.length > 0 ? " " + String.join(" ", args) : ""),
source
);
if (possibleCommands.isEmpty()) { try {
sender.sendMessage(Component.text("Command not found.")); // TODO: change dispatcher.execute(parseResults);
return; } catch (CommandSyntaxException e) {
sender.sendMessage(Component.text(e.getRawMessage().getString(), NamedTextColor.RED));
if (e.getInput() != null && e.getCursor() >= 0) {
int j = Math.min(e.getInput().length(), e.getCursor());
Component msg = Component.empty().color(NamedTextColor.GRAY).clickEvent(ClickEvent.clickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/" + name));
if (j > 10) {
msg = msg.append(Component.text("..."));
}
msg = msg.append(Component.text(e.getInput().substring(Math.max(0, j - 10), j)));
if (j < e.getInput().length()) {
Component component = Component.text(e.getInput().substring(j)).color(NamedTextColor.RED).decorate(TextDecoration.UNDERLINED);
msg = msg.append(component);
}
msg = msg.append(Component.translatable("command.context.here").color(NamedTextColor.RED).decorate(TextDecoration.ITALIC));
sender.sendMessage(msg);
}
} }
// get command according to args
Command command = possibleCommands.stream()
.filter(cmd -> cmd.getArgs().size() == args.length)
.findFirst()
.orElse(null);
System.out.println("[Manager] Command: " + command.getName() + " (" + command.getClass().getName() + ")" + " / " + command.getArgs());
command.execute(this.plugin, sender, new Arguments(plugin, command, List.of(args)));
} }
} }

View file

@ -0,0 +1,8 @@
package dev.xhyrom.lighteco.common.command;
import dev.xhyrom.lighteco.common.model.chat.CommandSender;
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
import org.checkerframework.checker.nullness.qual.NonNull;
public record CommandSource(@NonNull LightEcoPlugin plugin, @NonNull CommandSender sender) {
}

View file

@ -1,36 +1,44 @@
package dev.xhyrom.lighteco.common.command.abstraction; package dev.xhyrom.lighteco.common.command.abstraction;
import dev.xhyrom.lighteco.common.command.argument.Argument; import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import dev.xhyrom.lighteco.common.command.argument.Arguments; import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.LiteralCommandNode;
import dev.xhyrom.lighteco.common.command.CommandSource;
import dev.xhyrom.lighteco.common.config.message.CurrencyMessageConfig; import dev.xhyrom.lighteco.common.config.message.CurrencyMessageConfig;
import dev.xhyrom.lighteco.common.model.chat.CommandSender;
import dev.xhyrom.lighteco.common.model.currency.Currency; import dev.xhyrom.lighteco.common.model.currency.Currency;
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin; import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
import lombok.Getter; import lombok.Getter;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@Getter @Getter
public abstract class Command { public abstract class Command {
@NonNull @NonNull
private final String name; protected final String name;
@Nullable
private final String permission;
@NonNull @NonNull
private final List<Argument<?>> args; private final String description;
public Command(@NonNull String name, @Nullable String permission, @NonNull Argument<?>... args) { @NonNull
private final List<String> aliases = new ArrayList<>();
public Command(@NonNull String name, @NonNull String description, String... aliases) {
this.name = name; this.name = name;
this.permission = permission; this.description = description;
this.args = List.of(args);
Collections.addAll(this.aliases, aliases);
} }
public abstract void execute(LightEcoPlugin plugin, CommandSender sender, Arguments args); public abstract CommandNode<CommandSource> build();
protected LiteralArgumentBuilder<CommandSource> builder() {
return LiteralArgumentBuilder.literal(name);
}
protected CurrencyMessageConfig getCurrencyMessageConfig(LightEcoPlugin plugin, Currency currency) { protected CurrencyMessageConfig getCurrencyMessageConfig(LightEcoPlugin plugin, Currency currency) {
Map<String, CurrencyMessageConfig> config = plugin.getConfig().messages.currency; Map<String, CurrencyMessageConfig> config = plugin.getConfig().messages.currency;

View file

@ -1,41 +0,0 @@
package dev.xhyrom.lighteco.common.command.abstraction;
import dev.xhyrom.lighteco.common.command.argument.Arguments;
import dev.xhyrom.lighteco.common.command.argument.type.StringArgument;
import dev.xhyrom.lighteco.common.model.chat.CommandSender;
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
import lombok.Getter;
import net.kyori.adventure.text.Component;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Arrays;
@Getter
public class ParentCommand extends Command {
private final Command[] children;
public ParentCommand(@NonNull String name, @Nullable String permission, @NonNull Command... children) {
super(name, permission, new StringArgument("child"));
this.children = children;
}
@Override
public void execute(LightEcoPlugin plugin, CommandSender sender, Arguments args) {
String childName = args.string("child");
Command child = Arrays.stream(getChildren())
.filter(cmd -> cmd.getName().equalsIgnoreCase(childName) && (cmd.getArgs().size() == args.size() - 1 || cmd.getArgs().size() < args.size()))
.max((cmd1, cmd2) -> Integer.compare(cmd2.getArgs().size(), cmd1.getArgs().size()))
.orElse(null);
if (child == null) {
sender.sendMessage(Component.text("Command not found. / Parent Command"));
return;
}
System.out.println("Parent Command: " + getName() + " (" + getClass().getName() + ") " + " / Child Command: " + child.getName() + " (" + child.getClass().getName() + ")");
child.execute(plugin, sender, args.subList(1));
}
}

View file

@ -1,18 +0,0 @@
package dev.xhyrom.lighteco.common.command.argument;
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
import lombok.Getter;
public abstract class Argument<T> {
@Getter
private final String name;
protected Argument(String name) {
this.name = name;
}
public abstract Class<T> getPrimitiveType();
public abstract ArgumentType getArgumentType();
public abstract T parse(LightEcoPlugin plugin, String input);
}

View file

@ -1,8 +0,0 @@
package dev.xhyrom.lighteco.common.command.argument;
public enum ArgumentType {
STRING,
OFFLINE_USER,
INTEGER,
DOUBLE;
}

View file

@ -1,58 +0,0 @@
package dev.xhyrom.lighteco.common.command.argument;
import dev.xhyrom.lighteco.common.command.abstraction.Command;
import dev.xhyrom.lighteco.common.model.user.User;
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Arguments {
private final LightEcoPlugin plugin;
private final Command command;
private final List<String> arguments;
private final Map<String, Object> mappedArguments = new HashMap<>();
public Arguments(LightEcoPlugin plugin, Command command, List<String> arguments) {
this.plugin = plugin;
this.command = command;
this.arguments = arguments;
System.out.println("Arguments: " + arguments);
System.out.println("Command: " + command.getName() + " (" + command.getClass().getName() + ")" + " / " + command.getArgs());
for (int i = 0; i < command.getArgs().size(); i++) {
String arg = arguments.get(i);
System.out.println("Argument: " + arg + " / " + command.getArgs().get(i).getName());
this.mappedArguments.put(command.getArgs().get(i).getName(), (Object) command.getArgs().get(i).parse(plugin, arg));
}
}
public String string(String name) {
return (String) this.mappedArguments.get(name);
}
public User offlineUser(String name) {
return (User) this.mappedArguments.get(name);
}
public int integer(String name) {
return (int) this.mappedArguments.get(name);
}
public double dbl(String name) {
return (double) this.mappedArguments.get(name);
}
public String raw(int index) {
return (String) this.arguments.get(index);
}
public int size() {
return this.arguments.size();
}
public Arguments subList(int fromIndex) {
return new Arguments(this.plugin, this.command, this.arguments.subList(fromIndex, this.arguments.size()));
}
}

View file

@ -1,24 +0,0 @@
package dev.xhyrom.lighteco.common.command.argument.type;
import dev.xhyrom.lighteco.common.command.argument.ArgumentType;
public class DoubleArgument extends NumberArgument<Double> {
protected DoubleArgument(String name, Double min, Double max) {
super(name, min, max);
}
@Override
public Class<Double> getPrimitiveType() {
return Double.class;
}
@Override
public ArgumentType getArgumentType() {
return ArgumentType.DOUBLE;
}
@Override
public Double parse(String input) {
return Double.parseDouble(input);
}
}

View file

@ -1,24 +0,0 @@
package dev.xhyrom.lighteco.common.command.argument.type;
import dev.xhyrom.lighteco.common.command.argument.ArgumentType;
public class IntegerArgument extends NumberArgument<Integer> {
protected IntegerArgument(String name, Integer min, Integer max) {
super(name, min, max);
}
@Override
public Class<Integer> getPrimitiveType() {
return Integer.class;
}
@Override
public ArgumentType getArgumentType() {
return ArgumentType.INTEGER;
}
@Override
public Integer parse(String input) {
return Integer.parseInt(input);
}
}

View file

@ -1,32 +0,0 @@
package dev.xhyrom.lighteco.common.command.argument.type;
import dev.xhyrom.lighteco.common.command.argument.Argument;
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
abstract class NumberArgument<T> extends Argument<T> {
private final T min;
private final T max;
protected NumberArgument(String name, T min, T max) {
super(name);
this.min = min;
this.max = max;
}
public abstract T parse(String input);
@Override
public T parse(LightEcoPlugin plugin, String input) {
T value = parse(input);
if (value == null || (min != null && compare(value, min) < 0) || (max != null && compare(value, max) > 0)) {
return null;
}
return value;
}
private int compare(T a, T b) {
return ((Comparable<T>) a).compareTo(b);
}
}

View file

@ -1,34 +1,32 @@
package dev.xhyrom.lighteco.common.command.argument.type; package dev.xhyrom.lighteco.common.command.argument.type;
import dev.xhyrom.lighteco.common.command.argument.Argument; import com.mojang.brigadier.StringReader;
import dev.xhyrom.lighteco.common.command.argument.ArgumentType; import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import dev.xhyrom.lighteco.common.command.CommandSource;
import dev.xhyrom.lighteco.common.model.user.User; import dev.xhyrom.lighteco.common.model.user.User;
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin; import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
import java.util.UUID; import java.util.UUID;
public class OfflineUserArgument extends Argument<User> { public class OfflineUserArgument implements ArgumentType<String> {
public OfflineUserArgument(String name) { private OfflineUserArgument() {}
super(name);
}
@Override public static User getOfflineUser(CommandContext<CommandSource> context, String name) {
public Class<User> getPrimitiveType() { String userName = context.getArgument(name, String.class);
return User.class; LightEcoPlugin plugin = context.getSource().plugin();
}
@Override UUID uniqueId = plugin.getBootstrap().lookupUniqueId(userName).orElse(null);
public ArgumentType getArgumentType() {
return ArgumentType.OFFLINE_USER;
}
@Override
public User parse(LightEcoPlugin plugin, String input) {
UUID uniqueId = plugin.getBootstrap().lookupUniqueId(input).orElse(null);
if (uniqueId == null) { if (uniqueId == null) {
return null; return null;
} }
return plugin.getUserManager().loadUser(uniqueId).join(); return plugin.getUserManager().loadUser(uniqueId).join();
} }
@Override
public String parse(StringReader reader) throws CommandSyntaxException {
return reader.readString();
}
} }

View file

@ -1,29 +0,0 @@
package dev.xhyrom.lighteco.common.command.argument.type;
import dev.xhyrom.lighteco.common.command.argument.Argument;
import dev.xhyrom.lighteco.common.command.argument.ArgumentType;
import dev.xhyrom.lighteco.common.model.user.User;
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
import java.util.UUID;
public class StringArgument extends Argument<String> {
public StringArgument(String name) {
super(name);
}
@Override
public Class<String> getPrimitiveType() {
return String.class;
}
@Override
public ArgumentType getArgumentType() {
return ArgumentType.STRING;
}
@Override
public String parse(LightEcoPlugin plugin, String input) {
return input;
}
}

View file

@ -0,0 +1,34 @@
package dev.xhyrom.lighteco.common.command.suggestion.type;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import dev.xhyrom.lighteco.common.command.CommandSource;
import dev.xhyrom.lighteco.common.model.user.User;
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public class OfflineUserSuggestionProvider implements SuggestionProvider<CommandSource> {
public static OfflineUserSuggestionProvider create() {
return new OfflineUserSuggestionProvider();
}
@Override
public CompletableFuture<Suggestions> getSuggestions(CommandContext<CommandSource> context, SuggestionsBuilder builder) {
LightEcoPlugin plugin = context.getSource().plugin();
String remaining = builder.getRemaining();
for (UUID uniqueId : plugin.getBootstrap().getOnlinePlayers()) {
User user = plugin.getUserManager().getIfLoaded(uniqueId);
if (user == null) continue;
builder.suggest(user.getUsername());
}
return builder.buildFuture();
}
}

View file

@ -1,10 +1,14 @@
package dev.xhyrom.lighteco.common.commands; package dev.xhyrom.lighteco.common.commands;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.mojang.brigadier.tree.CommandNode;
import dev.xhyrom.lighteco.common.command.CommandSource;
import dev.xhyrom.lighteco.common.command.abstraction.Command; import dev.xhyrom.lighteco.common.command.abstraction.Command;
import dev.xhyrom.lighteco.common.command.argument.Argument;
import dev.xhyrom.lighteco.common.command.argument.Arguments;
import dev.xhyrom.lighteco.common.command.argument.type.OfflineUserArgument; import dev.xhyrom.lighteco.common.command.argument.type.OfflineUserArgument;
import dev.xhyrom.lighteco.common.config.message.CurrencyMessageConfig; import dev.xhyrom.lighteco.common.command.suggestion.type.OfflineUserSuggestionProvider;
import dev.xhyrom.lighteco.common.model.chat.CommandSender; import dev.xhyrom.lighteco.common.model.chat.CommandSender;
import dev.xhyrom.lighteco.common.model.currency.Currency; import dev.xhyrom.lighteco.common.model.currency.Currency;
import dev.xhyrom.lighteco.common.model.user.User; import dev.xhyrom.lighteco.common.model.user.User;
@ -12,35 +16,71 @@ import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Map;
import static com.mojang.brigadier.Command.SINGLE_SUCCESS;
public class BalanceCommand extends Command { public class BalanceCommand extends Command {
private final Currency currency; private final Currency currency;
public static BalanceCommand create(@NonNull Currency currency) { public static BalanceCommand create(@NonNull Currency currency) {
return new BalanceCommand(currency.getIdentifier() + ".balance", currency); return new BalanceCommand(currency);
} }
public BalanceCommand(@Nullable String permission, @NonNull Currency currency) { public BalanceCommand(@NonNull Currency currency) {
super("balance", permission, new Argument<?>[0]); super("balance", "Check your balance");
this.currency = currency; this.currency = currency;
} }
@Override @Override
public void execute(LightEcoPlugin plugin, CommandSender sender, Arguments args) { public CommandNode<CommandSource> build() {
User user = plugin.getUserManager().getIfLoaded(sender.getUniqueId()); return builder()
BigDecimal balance = user.getBalance(currency); .then(
RequiredArgumentBuilder.<CommandSource, String>argument("target", StringArgumentType.word())
.suggests(OfflineUserSuggestionProvider.create())
.requires((source) -> source.sender().eligible("lighteco.currency."+currency.getIdentifier()+".command.balance.others"))
.executes(context -> {
LightEcoPlugin plugin = context.getSource().plugin();
CommandSender sender = context.getSource().sender();
sender.sendMessage( User target = OfflineUserArgument.getOfflineUser(context, "target");
MiniMessage.miniMessage().deserialize( if (target == null || target.getUsername() == null) {
getCurrencyMessageConfig(plugin, currency).balance, return SINGLE_SUCCESS;
Placeholder.parsed("currency", currency.getIdentifier()), }
Placeholder.parsed("balance", balance.toPlainString())
) BigDecimal balance = target.getBalance(currency);
);
sender.sendMessage(
MiniMessage.miniMessage().deserialize(
getCurrencyMessageConfig(plugin, currency).balanceOthers,
Placeholder.parsed("currency", currency.getIdentifier()),
Placeholder.parsed("target", target.getUsername()),
Placeholder.parsed("balance", balance.toPlainString())
)
);
return SINGLE_SUCCESS;
}))
.requires((source) -> source.sender().eligible("lighteco.currency."+currency.getIdentifier()+".command.balance"))
.executes(context -> {
LightEcoPlugin plugin = context.getSource().plugin();
CommandSender sender = context.getSource().sender();
User user = plugin.getUserManager().getIfLoaded(sender.getUniqueId());
BigDecimal balance = user.getBalance(currency);
sender.sendMessage(
MiniMessage.miniMessage().deserialize(
getCurrencyMessageConfig(plugin, currency).balance,
Placeholder.parsed("currency", currency.getIdentifier()),
Placeholder.parsed("balance", balance.toPlainString())
)
);
return SINGLE_SUCCESS;
})
.build();
} }
} }

View file

@ -1,46 +0,0 @@
package dev.xhyrom.lighteco.common.commands;
import dev.xhyrom.lighteco.common.command.abstraction.Command;
import dev.xhyrom.lighteco.common.command.argument.Arguments;
import dev.xhyrom.lighteco.common.command.argument.type.OfflineUserArgument;
import dev.xhyrom.lighteco.common.config.message.CurrencyMessageConfig;
import dev.xhyrom.lighteco.common.model.chat.CommandSender;
import dev.xhyrom.lighteco.common.model.currency.Currency;
import dev.xhyrom.lighteco.common.model.user.User;
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.math.BigDecimal;
import java.util.Map;
public class BalanceOtherCommand extends Command {
private final Currency currency;
public static BalanceOtherCommand create(@NonNull Currency currency) {
return new BalanceOtherCommand(currency.getIdentifier() + ".balance.others", currency);
}
public BalanceOtherCommand(@Nullable String permission, @NonNull Currency currency) {
super("balance", permission, new OfflineUserArgument("target"));
this.currency = currency;
}
@Override
public void execute(LightEcoPlugin plugin, CommandSender sender, Arguments args) {
User target = args.offlineUser("target");
BigDecimal balance = target.getBalance(currency);
sender.sendMessage(
MiniMessage.miniMessage().deserialize(
getCurrencyMessageConfig(plugin, currency).balanceOthers,
Placeholder.parsed("currency", currency.getIdentifier()),
Placeholder.parsed("target", target.getUsername()),
Placeholder.parsed("balance", balance.toPlainString())
)
);
}
}

View file

@ -1,16 +1,61 @@
package dev.xhyrom.lighteco.common.commands; package dev.xhyrom.lighteco.common.commands;
import dev.xhyrom.lighteco.common.command.abstraction.ParentCommand; import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.tree.CommandNode;
import dev.xhyrom.lighteco.common.command.CommandSource;
import dev.xhyrom.lighteco.common.command.abstraction.Command;
import dev.xhyrom.lighteco.common.model.chat.CommandSender;
import dev.xhyrom.lighteco.common.model.currency.Currency; import dev.xhyrom.lighteco.common.model.currency.Currency;
import dev.xhyrom.lighteco.common.model.user.User;
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
public class CurrencyParentCommand extends ParentCommand { import java.math.BigDecimal;
import static com.mojang.brigadier.Command.SINGLE_SUCCESS;
public class CurrencyParentCommand extends Command {
private final Currency currency;
public CurrencyParentCommand(@NonNull Currency currency) { public CurrencyParentCommand(@NonNull Currency currency) {
super( super(
currency.getIdentifier(), currency.getIdentifier(),
currency.getIdentifier(), currency.getIdentifier()
BalanceCommand.create(currency),
BalanceOtherCommand.create(currency)
); );
this.currency = currency;
}
@Override
public CommandNode<CommandSource> build() {
LiteralArgumentBuilder<CommandSource> builder = builder()
.then(BalanceCommand.create(currency).build())
.then(SetCommand.create(currency).build())
.then(GiveCommand.create(currency).build())
.then(TakeCommand.create(currency).build())
.executes(context -> {
LightEcoPlugin plugin = context.getSource().plugin();
CommandSender sender = context.getSource().sender();
User user = plugin.getUserManager().getIfLoaded(sender.getUniqueId());
BigDecimal balance = user.getBalance(currency);
sender.sendMessage(
MiniMessage.miniMessage().deserialize(
getCurrencyMessageConfig(plugin, currency).balance,
Placeholder.parsed("currency", currency.getIdentifier()),
Placeholder.parsed("balance", balance.toPlainString())
)
);
return SINGLE_SUCCESS;
});
if (currency.isPayable())
builder = builder.then(PayCommand.create(currency).build());
return builder.build();
} }
} }

View file

@ -0,0 +1,107 @@
package dev.xhyrom.lighteco.common.commands;
import com.mojang.brigadier.arguments.DoubleArgumentType;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.tree.CommandNode;
import dev.xhyrom.lighteco.api.exception.CannotBeGreaterThan;
import dev.xhyrom.lighteco.common.command.CommandSource;
import dev.xhyrom.lighteco.common.command.abstraction.Command;
import dev.xhyrom.lighteco.common.command.argument.type.OfflineUserArgument;
import dev.xhyrom.lighteco.common.command.suggestion.type.OfflineUserSuggestionProvider;
import dev.xhyrom.lighteco.common.model.chat.CommandSender;
import dev.xhyrom.lighteco.common.model.currency.Currency;
import dev.xhyrom.lighteco.common.model.user.User;
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.math.BigDecimal;
import java.math.RoundingMode;
import static com.mojang.brigadier.Command.SINGLE_SUCCESS;
public class GiveCommand extends Command {
private static final MiniMessage miniMessage = MiniMessage.miniMessage();
private final Currency currency;
public static GiveCommand create(@NonNull Currency currency) {
return new GiveCommand(currency);
}
public GiveCommand(@NonNull Currency currency) {
super("give", "Give a player some money");
this.currency = currency;
}
private void execute(CommandContext<CommandSource> context) {
final LightEcoPlugin plugin = context.getSource().plugin();
final CommandSender sender = context.getSource().sender();
final User target = OfflineUserArgument.getOfflineUser(context, "target");
if (target == null || target.getUsername() == null) {
return;
}
BigDecimal amount = BigDecimal.valueOf(currency.fractionalDigits() > 0
? context.getArgument("amount", Double.class)
: context.getArgument("amount", Integer.class));
amount = amount.setScale(currency.fractionalDigits(), RoundingMode.DOWN);
try {
target.deposit(currency, amount);
} catch (CannotBeGreaterThan e) {
sender.sendMessage(
miniMessage.deserialize(
this.getCurrencyMessageConfig(plugin, this.currency).cannotBeGreaterThan,
Placeholder.parsed("max", plugin.getConfig().maximumBalance.toPlainString())
)
);
return;
}
sender.sendMessage(
miniMessage.deserialize(
this.getCurrencyMessageConfig(plugin, this.currency).set,
Placeholder.parsed("currency", currency.getIdentifier()),
Placeholder.parsed("target", target.getUsername()),
Placeholder.parsed("amount", amount.toPlainString())
)
);
}
@Override
public CommandNode<CommandSource> build() {
if (currency.fractionalDigits() > 0) {
return builder()
.requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.give"))
.then(RequiredArgumentBuilder.<CommandSource, String>argument("target", StringArgumentType.word())
.suggests(OfflineUserSuggestionProvider.create())
.then(RequiredArgumentBuilder.<CommandSource, Double>argument("amount", DoubleArgumentType.doubleArg(1))
.requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.give"))
.executes(c -> {
execute(c);
return SINGLE_SUCCESS;
})))
.build();
}
return builder()
.requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.give"))
.then(RequiredArgumentBuilder.<CommandSource, String>argument("target", StringArgumentType.word())
.suggests(OfflineUserSuggestionProvider.create())
.then(RequiredArgumentBuilder.<CommandSource, Integer>argument("amount", IntegerArgumentType.integer(1))
.requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.give"))
.executes(c -> {
execute(c);
return SINGLE_SUCCESS;
})))
.build();
}
}

View file

@ -0,0 +1,151 @@
package dev.xhyrom.lighteco.common.commands;
import com.mojang.brigadier.arguments.DoubleArgumentType;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.tree.CommandNode;
import dev.xhyrom.lighteco.api.exception.CannotBeGreaterThan;
import dev.xhyrom.lighteco.common.command.CommandSource;
import dev.xhyrom.lighteco.common.command.abstraction.Command;
import dev.xhyrom.lighteco.common.command.argument.type.OfflineUserArgument;
import dev.xhyrom.lighteco.common.command.suggestion.type.OfflineUserSuggestionProvider;
import dev.xhyrom.lighteco.common.model.chat.CommandSender;
import dev.xhyrom.lighteco.common.model.currency.Currency;
import dev.xhyrom.lighteco.common.model.user.User;
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.math.BigDecimal;
import java.math.RoundingMode;
import static com.mojang.brigadier.Command.SINGLE_SUCCESS;
public class PayCommand extends Command {
private static final MiniMessage miniMessage = MiniMessage.miniMessage();
private final Currency currency;
public static PayCommand create(@NonNull Currency currency) {
return new PayCommand(currency);
}
public PayCommand(@NonNull Currency currency) {
super("pay", "Pay a player");
this.currency = currency;
}
private void execute(CommandContext<CommandSource> context) {
final LightEcoPlugin plugin = context.getSource().plugin();
final CommandSender sender = context.getSource().sender();
final User target = OfflineUserArgument.getOfflineUser(context, "target");
if (target == null || target.getUsername() == null) {
return;
}
BigDecimal amount = BigDecimal.valueOf(currency.fractionalDigits() > 0
? context.getArgument("amount", Double.class)
: context.getArgument("amount", Integer.class));
amount = amount.setScale(currency.fractionalDigits(), RoundingMode.DOWN);
final User user = plugin.getUserManager().getIfLoaded(sender.getUniqueId());
if (user == null) {
return;
}
if (user.getBalance(this.currency).compareTo(amount) < 0) {
sender.sendMessage(
miniMessage.deserialize(this.getCurrencyMessageConfig(plugin, this.currency).notEnoughMoney)
);
return;
}
// calculate tax using Currency#calculateTax
BigDecimal tax = currency.getProxy().calculateTax(user.getProxy(), amount);
tax = tax.setScale(currency.getProxy().fractionalDigits(), RoundingMode.DOWN);
// subtract tax from amount
BigDecimal taxedAmount = amount.subtract(tax);
try {
target.deposit(currency, taxedAmount);
user.withdraw(currency, amount);
} catch (CannotBeGreaterThan e) {
sender.sendMessage(
miniMessage.deserialize(
this.getCurrencyMessageConfig(plugin, this.currency).cannotBeGreaterThan,
Placeholder.parsed("max", plugin.getConfig().maximumBalance.toPlainString())
)
);
return;
}
String template = tax.compareTo(BigDecimal.ZERO) > 0
? this.getCurrencyMessageConfig(plugin, this.currency).payWithTax
: this.getCurrencyMessageConfig(plugin, this.currency).pay;
String templateReceived = tax.compareTo(BigDecimal.ZERO) > 0
? this.getCurrencyMessageConfig(plugin, this.currency).payReceivedWithTax
: this.getCurrencyMessageConfig(plugin, this.currency).payReceived;
sender.sendMessage(
miniMessage.deserialize(
template,
Placeholder.parsed("currency", currency.getIdentifier()),
Placeholder.parsed("target", target.getUsername()),
Placeholder.parsed("amount", amount.toPlainString()),
Placeholder.parsed("taxed_amount", taxedAmount.toPlainString()),
Placeholder.parsed("sender_balance", user.getBalance(currency).toPlainString()),
Placeholder.parsed("receiver_balance", target.getBalance(currency).toPlainString())
)
);
target.sendMessage(
miniMessage.deserialize(
templateReceived,
Placeholder.parsed("currency", currency.getIdentifier()),
Placeholder.parsed("sender", user.getUsername()),
Placeholder.parsed("amount", amount.toPlainString()),
Placeholder.parsed("taxed_amount", taxedAmount.toPlainString()),
Placeholder.parsed("sender_balance", user.getBalance(currency).toPlainString()),
Placeholder.parsed("receiver_balance", target.getBalance(currency).toPlainString())
)
);
}
@Override
public CommandNode<CommandSource> build() {
if (currency.fractionalDigits() > 0) {
return builder()
.requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.pay"))
.then(RequiredArgumentBuilder.<CommandSource, String>argument("target", StringArgumentType.word())
.suggests(OfflineUserSuggestionProvider.create())
.then(RequiredArgumentBuilder.<CommandSource, Double>argument("amount", DoubleArgumentType.doubleArg(1))
.requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.pay"))
.executes(c -> {
execute(c);
return SINGLE_SUCCESS;
})))
.build();
}
return builder()
.requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.pay"))
.then(RequiredArgumentBuilder.<CommandSource, String>argument("target", StringArgumentType.word())
.suggests(OfflineUserSuggestionProvider.create())
.then(RequiredArgumentBuilder.<CommandSource, Integer>argument("amount", IntegerArgumentType.integer(1))
.requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.pay"))
.executes(c -> {
execute(c);
return SINGLE_SUCCESS;
})))
.build();
}
}

View file

@ -0,0 +1,107 @@
package dev.xhyrom.lighteco.common.commands;
import com.mojang.brigadier.arguments.DoubleArgumentType;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.tree.CommandNode;
import dev.xhyrom.lighteco.api.exception.CannotBeGreaterThan;
import dev.xhyrom.lighteco.common.command.CommandSource;
import dev.xhyrom.lighteco.common.command.abstraction.Command;
import dev.xhyrom.lighteco.common.command.argument.type.OfflineUserArgument;
import dev.xhyrom.lighteco.common.command.suggestion.type.OfflineUserSuggestionProvider;
import dev.xhyrom.lighteco.common.model.chat.CommandSender;
import dev.xhyrom.lighteco.common.model.currency.Currency;
import dev.xhyrom.lighteco.common.model.user.User;
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.math.BigDecimal;
import java.math.RoundingMode;
import static com.mojang.brigadier.Command.SINGLE_SUCCESS;
public class SetCommand extends Command {
private static final MiniMessage miniMessage = MiniMessage.miniMessage();
private final Currency currency;
public static SetCommand create(@NonNull Currency currency) {
return new SetCommand(currency);
}
public SetCommand(@NonNull Currency currency) {
super("set", "Set a player's balance");
this.currency = currency;
}
private void execute(CommandContext<CommandSource> context) {
final LightEcoPlugin plugin = context.getSource().plugin();
final CommandSender sender = context.getSource().sender();
final User target = OfflineUserArgument.getOfflineUser(context, "target");
if (target == null || target.getUsername() == null) {
return;
}
BigDecimal amount = BigDecimal.valueOf(currency.fractionalDigits() > 0
? context.getArgument("amount", Double.class)
: context.getArgument("amount", Integer.class));
amount = amount.setScale(currency.fractionalDigits(), RoundingMode.DOWN);
try {
target.setBalance(currency, amount);
} catch (CannotBeGreaterThan e) {
sender.sendMessage(
miniMessage.deserialize(
this.getCurrencyMessageConfig(plugin, this.currency).cannotBeGreaterThan,
Placeholder.parsed("max", plugin.getConfig().maximumBalance.toPlainString())
)
);
return;
}
sender.sendMessage(
miniMessage.deserialize(
this.getCurrencyMessageConfig(plugin, this.currency).set,
Placeholder.parsed("currency", currency.getIdentifier()),
Placeholder.parsed("target", target.getUsername()),
Placeholder.parsed("amount", amount.toPlainString())
)
);
}
@Override
public CommandNode<CommandSource> build() {
if (currency.fractionalDigits() > 0) {
return builder()
.requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.set"))
.then(RequiredArgumentBuilder.<CommandSource, String>argument("target", StringArgumentType.word())
.suggests(OfflineUserSuggestionProvider.create())
.then(RequiredArgumentBuilder.<CommandSource, Double>argument("amount", DoubleArgumentType.doubleArg(1))
.requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.set"))
.executes(c -> {
execute(c);
return SINGLE_SUCCESS;
})))
.build();
}
return builder()
.requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.set"))
.then(RequiredArgumentBuilder.<CommandSource, String>argument("target", StringArgumentType.word())
.suggests(OfflineUserSuggestionProvider.create())
.then(RequiredArgumentBuilder.<CommandSource, Integer>argument("amount", IntegerArgumentType.integer(1))
.requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.set"))
.executes(c -> {
execute(c);
return SINGLE_SUCCESS;
})))
.build();
}
}

View file

@ -0,0 +1,107 @@
package dev.xhyrom.lighteco.common.commands;
import com.mojang.brigadier.arguments.DoubleArgumentType;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.tree.CommandNode;
import dev.xhyrom.lighteco.api.exception.CannotBeGreaterThan;
import dev.xhyrom.lighteco.common.command.CommandSource;
import dev.xhyrom.lighteco.common.command.abstraction.Command;
import dev.xhyrom.lighteco.common.command.argument.type.OfflineUserArgument;
import dev.xhyrom.lighteco.common.command.suggestion.type.OfflineUserSuggestionProvider;
import dev.xhyrom.lighteco.common.model.chat.CommandSender;
import dev.xhyrom.lighteco.common.model.currency.Currency;
import dev.xhyrom.lighteco.common.model.user.User;
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.math.BigDecimal;
import java.math.RoundingMode;
import static com.mojang.brigadier.Command.SINGLE_SUCCESS;
public class TakeCommand extends Command {
private static final MiniMessage miniMessage = MiniMessage.miniMessage();
private final Currency currency;
public static TakeCommand create(@NonNull Currency currency) {
return new TakeCommand(currency);
}
public TakeCommand(@NonNull Currency currency) {
super("take", "Take money from a player");
this.currency = currency;
}
private void execute(CommandContext<CommandSource> context) {
final LightEcoPlugin plugin = context.getSource().plugin();
final CommandSender sender = context.getSource().sender();
final User target = OfflineUserArgument.getOfflineUser(context, "target");
if (target == null || target.getUsername() == null) {
return;
}
BigDecimal amount = BigDecimal.valueOf(currency.fractionalDigits() > 0
? context.getArgument("amount", Double.class)
: context.getArgument("amount", Integer.class));
amount = amount.setScale(currency.fractionalDigits(), RoundingMode.DOWN);
try {
target.withdraw(currency, amount);
} catch (CannotBeGreaterThan e) {
sender.sendMessage(
miniMessage.deserialize(
this.getCurrencyMessageConfig(plugin, this.currency).cannotBeGreaterThan,
Placeholder.parsed("max", plugin.getConfig().maximumBalance.toPlainString())
)
);
return;
}
sender.sendMessage(
miniMessage.deserialize(
this.getCurrencyMessageConfig(plugin, this.currency).set,
Placeholder.parsed("currency", currency.getIdentifier()),
Placeholder.parsed("target", target.getUsername()),
Placeholder.parsed("amount", amount.toPlainString())
)
);
}
@Override
public CommandNode<CommandSource> build() {
if (currency.fractionalDigits() > 0) {
return builder()
.requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.take"))
.then(RequiredArgumentBuilder.<CommandSource, String>argument("target", StringArgumentType.word())
.suggests(OfflineUserSuggestionProvider.create())
.then(RequiredArgumentBuilder.<CommandSource, Double>argument("amount", DoubleArgumentType.doubleArg(1))
.requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.take"))
.executes(c -> {
execute(c);
return SINGLE_SUCCESS;
})))
.build();
}
return builder()
.requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.take"))
.then(RequiredArgumentBuilder.<CommandSource, String>argument("target", StringArgumentType.word())
.suggests(OfflineUserSuggestionProvider.create())
.then(RequiredArgumentBuilder.<CommandSource, Integer>argument("amount", IntegerArgumentType.integer(1))
.requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.take"))
.executes(c -> {
execute(c);
return SINGLE_SUCCESS;
})))
.build();
}
}

View file

@ -8,5 +8,6 @@ public interface CommandSender {
String getUsername(); String getUsername();
UUID getUniqueId(); UUID getUniqueId();
boolean eligible(String permission);
void sendMessage(Component message); void sendMessage(Component message);
} }