mirror of
https://github.com/xHyroM/lighteco.git
synced 2024-12-22 20:41: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:
parent
802d90a459
commit
35eebc1609
31 changed files with 858 additions and 378 deletions
|
@ -28,6 +28,7 @@ subprojects {
|
|||
repositories {
|
||||
mavenCentral()
|
||||
maven("https://storehouse.okaeri.eu/repository/maven-public/")
|
||||
maven("https://libraries.minecraft.net")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ plugins {
|
|||
repositories {
|
||||
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/central")
|
||||
}
|
||||
|
@ -13,10 +13,10 @@ repositories {
|
|||
dependencies {
|
||||
implementation(project(":lighteco-common"))
|
||||
|
||||
implementation("dev.jorel:commandapi-bukkit-shade:9.5.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
|
||||
compileOnly("me.clip:placeholderapi:2.11.3")
|
||||
|
@ -29,7 +29,9 @@ dependencies {
|
|||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
relocate("dev.jorel.commandapi", "dev.xhyrom.lighteco.libraries.commandapi")
|
||||
dependencies {
|
||||
exclude(dependency("com.mojang:brigadier"))
|
||||
}
|
||||
|
||||
// common
|
||||
relocate("eu.okaeri.configs", "dev.xhyrom.lighteco.libraries.okaeri.configs")
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
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.common.plugin.bootstrap.LightEcoBootstrap;
|
||||
import dev.xhyrom.lighteco.common.plugin.bootstrap.LoaderBootstrap;
|
||||
|
@ -42,14 +40,10 @@ public class BukkitLightEcoBootstrap implements LightEcoBootstrap, LoaderBootstr
|
|||
@Override
|
||||
public void onLoad() {
|
||||
this.plugin.load();
|
||||
CommandAPI.onLoad(new CommandAPIBukkitConfig(this.loader)
|
||||
.verboseOutput(this.getPlugin().getConfig().debug)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
CommandAPI.onEnable();
|
||||
this.plugin.enable();
|
||||
|
||||
this.audience = BukkitAudiences.create(loader);
|
||||
|
@ -57,7 +51,6 @@ public class BukkitLightEcoBootstrap implements LightEcoBootstrap, LoaderBootstr
|
|||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
CommandAPI.onDisable();
|
||||
this.plugin.disable();
|
||||
}
|
||||
|
||||
|
@ -68,7 +61,7 @@ public class BukkitLightEcoBootstrap implements LightEcoBootstrap, LoaderBootstr
|
|||
|
||||
@Override
|
||||
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
|
||||
|
|
|
@ -4,6 +4,7 @@ import dev.xhyrom.lighteco.api.LightEco;
|
|||
import dev.xhyrom.lighteco.api.manager.ContextManager;
|
||||
import dev.xhyrom.lighteco.api.platform.Platform;
|
||||
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.manager.BukkitCommandManager;
|
||||
import dev.xhyrom.lighteco.bukkit.manager.BukkitContextManager;
|
||||
|
@ -36,6 +37,7 @@ public class BukkitLightEcoPlugin extends AbstractLightEcoPlugin {
|
|||
@Override
|
||||
protected void registerListeners() {
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,6 +32,11 @@ public class BukkitCommandSender extends AbstractCommandSender<CommandSender> {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean eligible(String permission) {
|
||||
return this.delegate.hasPermission(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(Component message) {
|
||||
this.audience.sendMessage(message);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +1,23 @@
|
|||
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.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.plugin.LightEcoPlugin;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandMap;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BukkitCommandManager extends CommandManager {
|
||||
public final BukkitAudiences audienceFactory;
|
||||
|
@ -34,16 +39,50 @@ public class BukkitCommandManager extends CommandManager {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void register(Currency currency, boolean main) {
|
||||
super.register(currency, main);
|
||||
public Command[] register(Currency currency, boolean 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
|
||||
public boolean execute(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] strings) {
|
||||
bukkitCommandManagerExecute(new BukkitCommandSender(commandSender, audienceFactory), s, strings);
|
||||
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) {
|
||||
|
|
|
@ -18,7 +18,7 @@ public class TestCurrency2 implements Currency {
|
|||
|
||||
@Override
|
||||
public boolean isPayable() {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,10 +2,6 @@ plugins {
|
|||
id("lighteco.shadow-logic")
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven("https://libraries.minecraft.net")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(project(":lighteco-api"))
|
||||
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-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("redis.clients:jedis:5.1.0")
|
||||
|
|
|
@ -1,21 +1,28 @@
|
|||
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.argument.Arguments;
|
||||
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.PayCommand;
|
||||
import dev.xhyrom.lighteco.common.model.chat.CommandSender;
|
||||
import dev.xhyrom.lighteco.common.model.currency.Currency;
|
||||
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
|
||||
import lombok.Getter;
|
||||
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.List;
|
||||
|
||||
public class CommandManager {
|
||||
protected final LightEcoPlugin plugin;
|
||||
private final List<Command> commands = new ArrayList<>();
|
||||
@Getter
|
||||
private final CommandDispatcher<CommandSource> dispatcher = new CommandDispatcher<>();
|
||||
|
||||
public CommandManager(LightEcoPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
|
@ -25,32 +32,53 @@ public class CommandManager {
|
|||
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));
|
||||
|
||||
dispatcher.getRoot().addChild(commands.get(0).build());
|
||||
if (main) {
|
||||
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) {
|
||||
List<Command> possibleCommands = this.commands.stream()
|
||||
.filter(cmd -> cmd.getName().equalsIgnoreCase(name))
|
||||
.toList();
|
||||
final CommandSource source = new CommandSource(this.plugin, sender);
|
||||
final ParseResults<CommandSource> parseResults = dispatcher.parse(
|
||||
name + (args.length > 0 ? " " + String.join(" ", args) : ""),
|
||||
source
|
||||
);
|
||||
|
||||
if (possibleCommands.isEmpty()) {
|
||||
sender.sendMessage(Component.text("Command not found.")); // TODO: change
|
||||
return;
|
||||
try {
|
||||
dispatcher.execute(parseResults);
|
||||
} 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)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
}
|
|
@ -1,36 +1,44 @@
|
|||
package dev.xhyrom.lighteco.common.command.abstraction;
|
||||
|
||||
import dev.xhyrom.lighteco.common.command.argument.Argument;
|
||||
import dev.xhyrom.lighteco.common.command.argument.Arguments;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
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.model.chat.CommandSender;
|
||||
import dev.xhyrom.lighteco.common.model.currency.Currency;
|
||||
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
|
||||
import lombok.Getter;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
public abstract class Command {
|
||||
@NonNull
|
||||
private final String name;
|
||||
|
||||
@Nullable
|
||||
private final String permission;
|
||||
protected final String name;
|
||||
|
||||
@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.permission = permission;
|
||||
this.args = List.of(args);
|
||||
this.description = description;
|
||||
|
||||
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) {
|
||||
Map<String, CurrencyMessageConfig> config = plugin.getConfig().messages.currency;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
package dev.xhyrom.lighteco.common.command.argument;
|
||||
|
||||
public enum ArgumentType {
|
||||
STRING,
|
||||
OFFLINE_USER,
|
||||
INTEGER,
|
||||
DOUBLE;
|
||||
}
|
|
@ -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()));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -1,34 +1,32 @@
|
|||
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 com.mojang.brigadier.StringReader;
|
||||
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.plugin.LightEcoPlugin;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class OfflineUserArgument extends Argument<User> {
|
||||
public OfflineUserArgument(String name) {
|
||||
super(name);
|
||||
}
|
||||
public class OfflineUserArgument implements ArgumentType<String> {
|
||||
private OfflineUserArgument() {}
|
||||
|
||||
@Override
|
||||
public Class<User> getPrimitiveType() {
|
||||
return User.class;
|
||||
}
|
||||
public static User getOfflineUser(CommandContext<CommandSource> context, String name) {
|
||||
String userName = context.getArgument(name, String.class);
|
||||
LightEcoPlugin plugin = context.getSource().plugin();
|
||||
|
||||
@Override
|
||||
public ArgumentType getArgumentType() {
|
||||
return ArgumentType.OFFLINE_USER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User parse(LightEcoPlugin plugin, String input) {
|
||||
UUID uniqueId = plugin.getBootstrap().lookupUniqueId(input).orElse(null);
|
||||
UUID uniqueId = plugin.getBootstrap().lookupUniqueId(userName).orElse(null);
|
||||
if (uniqueId == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return plugin.getUserManager().loadUser(uniqueId).join();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parse(StringReader reader) throws CommandSyntaxException {
|
||||
return reader.readString();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -1,10 +1,14 @@
|
|||
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.argument.Argument;
|
||||
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.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;
|
||||
|
@ -12,35 +16,71 @@ 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;
|
||||
|
||||
import static com.mojang.brigadier.Command.SINGLE_SUCCESS;
|
||||
|
||||
public class BalanceCommand extends Command {
|
||||
private final 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) {
|
||||
super("balance", permission, new Argument<?>[0]);
|
||||
public BalanceCommand(@NonNull Currency currency) {
|
||||
super("balance", "Check your balance");
|
||||
|
||||
this.currency = currency;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(LightEcoPlugin plugin, CommandSender sender, Arguments args) {
|
||||
User user = plugin.getUserManager().getIfLoaded(sender.getUniqueId());
|
||||
BigDecimal balance = user.getBalance(currency);
|
||||
public CommandNode<CommandSource> build() {
|
||||
return builder()
|
||||
.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(
|
||||
MiniMessage.miniMessage().deserialize(
|
||||
getCurrencyMessageConfig(plugin, currency).balance,
|
||||
Placeholder.parsed("currency", currency.getIdentifier()),
|
||||
Placeholder.parsed("balance", balance.toPlainString())
|
||||
)
|
||||
);
|
||||
User target = OfflineUserArgument.getOfflineUser(context, "target");
|
||||
if (target == null || target.getUsername() == null) {
|
||||
return SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,16 +1,61 @@
|
|||
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.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;
|
||||
|
||||
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) {
|
||||
super(
|
||||
currency.getIdentifier(),
|
||||
currency.getIdentifier(),
|
||||
BalanceCommand.create(currency),
|
||||
BalanceOtherCommand.create(currency)
|
||||
currency.getIdentifier()
|
||||
);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -8,5 +8,6 @@ public interface CommandSender {
|
|||
String getUsername();
|
||||
UUID getUniqueId();
|
||||
|
||||
boolean eligible(String permission);
|
||||
void sendMessage(Component message);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue