diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eeb29cd..37ad61d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,8 +12,7 @@ jobs: distribution: 'adopt' - name: Build with Gradle run: | - ./gradlew shadowJar -p bukkittest - ./gradlew shadowJar -p bukkit + ./gradlew shadowJar -p paper ./gradlew shadowJar -p currency-money - uses: actions/upload-artifact@v3 with: diff --git a/.gitignore b/.gitignore index 1285e0e..2698b5a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ ### ForgeGradle ### # Minecraft client/server files run/ +runServer/ ### Intellij ### # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider diff --git a/api/src/main/java/dev/xhyrom/lighteco/api/platform/Platform.java b/api/src/main/java/dev/xhyrom/lighteco/api/platform/Platform.java index 0ede153..ed89fdf 100644 --- a/api/src/main/java/dev/xhyrom/lighteco/api/platform/Platform.java +++ b/api/src/main/java/dev/xhyrom/lighteco/api/platform/Platform.java @@ -11,7 +11,7 @@ public interface Platform { @NonNull Type getType(); enum Type { - BUKKIT("Bukkit"), + PAPER("Paper"), SPONGE("Sponge"), VELOCITY("Velocity"), BUNGEECORD("BungeeCord"); @@ -27,7 +27,7 @@ public interface Platform { } public boolean isLocal() { - return this == BUKKIT || this == SPONGE; + return this == PAPER || this == SPONGE; } public boolean isProxy() { diff --git a/build.gradle.kts b/build.gradle.kts index d196431..d46ab81 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -28,6 +28,7 @@ subprojects { repositories { mavenCentral() maven("https://storehouse.okaeri.eu/repository/maven-public/") + maven("https://libraries.minecraft.net") } } diff --git a/buildSrc/src/main/kotlin/lighteco.base-logic.gradle.kts b/buildSrc/src/main/kotlin/lighteco.base-logic.gradle.kts index 3a09e7d..d50789b 100644 --- a/buildSrc/src/main/kotlin/lighteco.base-logic.gradle.kts +++ b/buildSrc/src/main/kotlin/lighteco.base-logic.gradle.kts @@ -4,7 +4,12 @@ plugins { } java { - // toolchain.languageVersion.set(JavaLanguageVersion.of(17)) + targetCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = JavaVersion.VERSION_17 + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } + withSourcesJar() } @@ -13,6 +18,7 @@ tasks { filesMatching(listOf("plugin.yml")) { expand( "name" to project.name, + "coreName" to "LightEco", "version" to project.version, "description" to project.description, "author" to "xHyroM" diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/BalanceCommand.java b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/BalanceCommand.java deleted file mode 100644 index 1324094..0000000 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/BalanceCommand.java +++ /dev/null @@ -1,59 +0,0 @@ -package dev.xhyrom.lighteco.bukkit.commands; - -import dev.jorel.commandapi.CommandAPICommand; -import dev.jorel.commandapi.arguments.OfflinePlayerArgument; -import dev.jorel.commandapi.executors.CommandArguments; -import dev.xhyrom.lighteco.bukkit.chat.BukkitCommandSender; -import dev.xhyrom.lighteco.bukkit.manager.BukkitCommandManager; -import dev.xhyrom.lighteco.common.model.currency.Currency; -import lombok.RequiredArgsConstructor; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.CommandSender; - -@RequiredArgsConstructor -public class BalanceCommand implements Command { - private final BukkitCommandManager manager; - private final String name; - private final Currency currency; - private final String permissionBase; - - @Override - public CommandAPICommand[] multipleBuild() { - return new CommandAPICommand[]{ - new CommandAPICommand(name) - .withPermission(permissionBase + "balance.others") - .withArguments(new OfflinePlayerArgument("target")) - .executes((sender, args) -> { - this.handleBalance(sender, args, currency); - }), - new CommandAPICommand(name) - .withPermission(permissionBase + "balance") - .executesPlayer((sender, args) -> { - this.handleBalance(sender, args, currency); - }) - }; - } - - public void handleBalance(CommandSender originalSender, CommandArguments args, Currency currency) { - BukkitCommandSender sender = new BukkitCommandSender(originalSender, this.manager.audienceFactory); - OfflinePlayer target = (OfflinePlayer) args.get("target"); - - if (target == null) { - this.manager.onBalance(sender, currency); - - return; - } - - this.manager.plugin.getUserManager().loadUser(target.getUniqueId()) - .thenAccept(result -> { - String username = result.getUsername() == null ? - target.getName() != null - ? target.getName() - : args.getRaw("target") - : result.getUsername(); - result.setUsername(username); - - this.manager.onBalance(sender, currency, result); - }); - } -} diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/Command.java b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/Command.java deleted file mode 100644 index 30f56b6..0000000 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/Command.java +++ /dev/null @@ -1,13 +0,0 @@ -package dev.xhyrom.lighteco.bukkit.commands; - -import dev.jorel.commandapi.CommandAPICommand; - -public interface Command { - default CommandAPICommand build() { - return null; - } - - default CommandAPICommand[] multipleBuild() { - return new CommandAPICommand[0]; - } -} diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/GiveCommand.java b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/GiveCommand.java deleted file mode 100644 index e138c0d..0000000 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/GiveCommand.java +++ /dev/null @@ -1,54 +0,0 @@ -package dev.xhyrom.lighteco.bukkit.commands; - -import dev.jorel.commandapi.CommandAPICommand; -import dev.jorel.commandapi.arguments.DoubleArgument; -import dev.jorel.commandapi.arguments.IntegerArgument; -import dev.jorel.commandapi.arguments.OfflinePlayerArgument; -import dev.jorel.commandapi.executors.CommandArguments; -import dev.xhyrom.lighteco.bukkit.chat.BukkitCommandSender; -import dev.xhyrom.lighteco.bukkit.manager.BukkitCommandManager; -import dev.xhyrom.lighteco.common.model.currency.Currency; -import lombok.RequiredArgsConstructor; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.CommandSender; - -import java.math.BigDecimal; - -@RequiredArgsConstructor -public class GiveCommand implements Command { - private final BukkitCommandManager manager; - private final Currency currency; - private final String permissionBase; - - @Override - public CommandAPICommand build() { - return new CommandAPICommand("give") - .withPermission(permissionBase + "give") - .withArguments( - new OfflinePlayerArgument("target"), - currency.getProxy().fractionalDigits() > 0 - ? new DoubleArgument("amount", 1) - : new IntegerArgument("amount", 1) - ) - .executes((sender, args) -> { - this.handleGive(sender, args, currency); - }); - } - - - private void handleGive(CommandSender originalSender, CommandArguments args, Currency currency) { - BukkitCommandSender sender = new BukkitCommandSender(originalSender, this.manager.audienceFactory); - OfflinePlayer target = (OfflinePlayer) args.get("target"); - BigDecimal amount = BigDecimal.valueOf(Double.parseDouble(args.getRaw("amount"))); - - if (!this.manager.canUse(sender, currency)) return; - - this.manager.plugin.getUserManager().loadUser(target.getUniqueId()) - .thenAccept(result -> { - String name = target.getName() != null ? target.getName() : args.getRaw("target"); - result.setUsername(name); - - this.manager.onGive(sender, currency, result, amount); - }); - } -} diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/PayCommand.java b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/PayCommand.java deleted file mode 100644 index 4e07a94..0000000 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/PayCommand.java +++ /dev/null @@ -1,57 +0,0 @@ -package dev.xhyrom.lighteco.bukkit.commands; - -import dev.jorel.commandapi.CommandAPICommand; -import dev.jorel.commandapi.arguments.DoubleArgument; -import dev.jorel.commandapi.arguments.IntegerArgument; -import dev.jorel.commandapi.arguments.OfflinePlayerArgument; -import dev.jorel.commandapi.executors.CommandArguments; -import dev.xhyrom.lighteco.bukkit.chat.BukkitCommandSender; -import dev.xhyrom.lighteco.bukkit.manager.BukkitCommandManager; -import dev.xhyrom.lighteco.common.model.currency.Currency; -import lombok.RequiredArgsConstructor; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.CommandSender; - -import java.math.BigDecimal; - -@RequiredArgsConstructor -public class PayCommand implements Command { - private final BukkitCommandManager manager; - private final Currency currency; - private final String permissionBase; - - @Override - public CommandAPICommand build() { - return new CommandAPICommand("pay") - .withPermission(permissionBase + "pay") - .withArguments( - new OfflinePlayerArgument("target"), - currency.getProxy().fractionalDigits() > 0 - ? new DoubleArgument("amount", 1) - : new IntegerArgument("amount", 1) - ) - .executesPlayer((sender, args) -> { - this.handlePay(sender, args, currency); - }); - } - - private void handlePay(CommandSender originalSender, CommandArguments args, Currency currency) { - BukkitCommandSender sender = new BukkitCommandSender(originalSender, this.manager.audienceFactory); - OfflinePlayer target = (OfflinePlayer) args.get("target"); - BigDecimal amount = BigDecimal.valueOf(Double.parseDouble(args.getRaw("amount"))); - - if (!this.manager.canUse(sender, currency)) return; - - this.manager.plugin.getUserManager().loadUser(target.getUniqueId()) - .thenAccept(result -> { - String username = result.getUsername() == null ? - target.getName() != null - ? target.getName() - : args.getRaw("target") - : result.getUsername(); - result.setUsername(username); - - this.manager.onPay(sender, currency, result, amount); - }); - } -} diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/SetCommand.java b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/SetCommand.java deleted file mode 100644 index c45f9ff..0000000 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/SetCommand.java +++ /dev/null @@ -1,54 +0,0 @@ -package dev.xhyrom.lighteco.bukkit.commands; - -import dev.jorel.commandapi.CommandAPICommand; -import dev.jorel.commandapi.arguments.DoubleArgument; -import dev.jorel.commandapi.arguments.IntegerArgument; -import dev.jorel.commandapi.arguments.OfflinePlayerArgument; -import dev.jorel.commandapi.executors.CommandArguments; -import dev.xhyrom.lighteco.bukkit.chat.BukkitCommandSender; -import dev.xhyrom.lighteco.bukkit.manager.BukkitCommandManager; -import dev.xhyrom.lighteco.common.model.currency.Currency; -import lombok.RequiredArgsConstructor; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.CommandSender; - -import java.math.BigDecimal; - -@RequiredArgsConstructor -public class SetCommand implements Command { - private final BukkitCommandManager manager; - private final Currency currency; - private final String permissionBase; - - @Override - public CommandAPICommand build() { - return new CommandAPICommand("set") - .withPermission(permissionBase + "set") - .withArguments( - new OfflinePlayerArgument("target"), - currency.getProxy().fractionalDigits() > 0 - ? new DoubleArgument("amount", 0) - : new IntegerArgument("amount", 0) - ) - .executes((sender, args) -> { - this.handleSet(sender, args, currency); - }); - } - - - private void handleSet(CommandSender originalSender, CommandArguments args, Currency currency) { - BukkitCommandSender sender = new BukkitCommandSender(originalSender, this.manager.audienceFactory); - OfflinePlayer target = (OfflinePlayer) args.get("target"); - BigDecimal amount = BigDecimal.valueOf(Double.parseDouble(args.getRaw("amount"))); - - if (!this.manager.canUse(sender, currency)) return; - - this.manager.plugin.getUserManager().loadUser(target.getUniqueId()) - .thenAccept(result -> { - String name = target.getName() != null ? target.getName() : args.getRaw("target"); - result.setUsername(name); - - this.manager.onSet(sender, currency, result, amount); - }); - } -} diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/TakeCommand.java b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/TakeCommand.java deleted file mode 100644 index 3f25263..0000000 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/TakeCommand.java +++ /dev/null @@ -1,54 +0,0 @@ -package dev.xhyrom.lighteco.bukkit.commands; - -import dev.jorel.commandapi.CommandAPICommand; -import dev.jorel.commandapi.arguments.DoubleArgument; -import dev.jorel.commandapi.arguments.IntegerArgument; -import dev.jorel.commandapi.arguments.OfflinePlayerArgument; -import dev.jorel.commandapi.executors.CommandArguments; -import dev.xhyrom.lighteco.bukkit.chat.BukkitCommandSender; -import dev.xhyrom.lighteco.bukkit.manager.BukkitCommandManager; -import dev.xhyrom.lighteco.common.model.currency.Currency; -import lombok.RequiredArgsConstructor; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.CommandSender; - -import java.math.BigDecimal; - -@RequiredArgsConstructor -public class TakeCommand implements Command { - private final BukkitCommandManager manager; - private final Currency currency; - private final String permissionBase; - - @Override - public CommandAPICommand build() { - return new CommandAPICommand("take") - .withPermission(permissionBase + "take") - .withArguments( - new OfflinePlayerArgument("target"), - currency.getProxy().fractionalDigits() > 0 - ? new DoubleArgument("amount", 1) - : new IntegerArgument("amount", 1) - ) - .executes((sender, args) -> { - this.handleTake(sender, args, currency); - }); - } - - - private void handleTake(CommandSender originalSender, CommandArguments args, Currency currency) { - BukkitCommandSender sender = new BukkitCommandSender(originalSender, this.manager.audienceFactory); - OfflinePlayer target = (OfflinePlayer) args.get("target"); - BigDecimal amount = BigDecimal.valueOf(Double.parseDouble(args.getRaw("amount"))); - - if (!this.manager.canUse(sender, currency)) return; - - this.manager.plugin.getUserManager().loadUser(target.getUniqueId()) - .thenAccept(result -> { - String name = target.getName() != null ? target.getName() : args.getRaw("target"); - result.setUsername(name); - - this.manager.onTake(sender, currency, result, amount); - }); - } -} diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/manager/BukkitCommandManager.java b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/manager/BukkitCommandManager.java deleted file mode 100644 index 9f10eb9..0000000 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/manager/BukkitCommandManager.java +++ /dev/null @@ -1,77 +0,0 @@ -package dev.xhyrom.lighteco.bukkit.manager; - -import dev.jorel.commandapi.CommandAPICommand; -import dev.xhyrom.lighteco.bukkit.commands.*; -import dev.xhyrom.lighteco.common.manager.command.AbstractCommandManager; -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.plugin.java.JavaPlugin; -import org.checkerframework.checker.nullness.qual.NonNull; - -public class BukkitCommandManager extends AbstractCommandManager { - public final BukkitAudiences audienceFactory; - - public BukkitCommandManager(LightEcoPlugin plugin) { - super(plugin); - - this.audienceFactory = BukkitAudiences.create((JavaPlugin) this.plugin.getBootstrap().getLoader()); - } - - @Override - public void registerCurrencyCommand(@NonNull Currency currency) { - registerCommands(currency.getIdentifier(), currency); - - for (String alias : currency.getIdentifierAliases()) { - registerCommands(alias, currency); - } - } - - @Override - public void registerCurrencyCommand(@NonNull Currency currency, boolean main) { - if (!main) { - registerCurrencyCommand(currency); - return; - } - - String permissionBase = "lighteco.currency." + currency.getIdentifier() + ".command."; - - // Register main command - registerCurrencyCommand(currency); - - // Expose pay as main command - if (currency.isPayable()) - new PayCommand(this, currency, permissionBase).build().register(); - - // Expose balance as main command - for (CommandAPICommand cmd : new BalanceCommand( - this, - "balance", - currency, - permissionBase - ).multipleBuild()) { - cmd.register(); - } - } - - private void registerCommands(@NonNull String name, @NonNull Currency currency) { - String permissionBase = "lighteco.currency." + currency.getIdentifier() + ".command."; - - BalanceCommand balanceCommand = new BalanceCommand(this, "balance", currency, permissionBase); - - CommandAPICommand cmd = new CommandAPICommand(name) - .withSubcommand(new SetCommand(this, currency, permissionBase).build()) - .withSubcommand(new GiveCommand(this, currency, permissionBase).build()) - .withSubcommand(new TakeCommand(this, currency, permissionBase).build()) - .withSubcommands(balanceCommand.multipleBuild()) - // We want balance to be the default command - .executesPlayer((sender, args) -> { - balanceCommand.handleBalance(sender, args, currency); - }); - - if (currency.isPayable()) - cmd = cmd.withSubcommand(new PayCommand(this, currency, permissionBase).build()); - - cmd.register(); - } -} diff --git a/bukkittest/.gitignore b/bukkittest/.gitignore deleted file mode 100644 index 72a0aec..0000000 --- a/bukkittest/.gitignore +++ /dev/null @@ -1,44 +0,0 @@ -.gradle -build/ -!gradle/wrapper/gradle-wrapper.jar -!**/src/main/**/build/ -!**/src/test/**/build/ - -### IntelliJ IDEA ### -.idea/modules.xml -.idea/jarRepositories.xml -.idea/compiler.xml -.idea/libraries/ -*.iws -*.iml -*.ipr -out/ -!**/src/main/**/out/ -!**/src/test/**/out/ - -### Eclipse ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache -bin/ -!**/src/main/**/bin/ -!**/src/test/**/bin/ - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ - -### VS Code ### -.vscode/ - -### Mac OS ### -.DS_Store - -runServer/ \ No newline at end of file diff --git a/common/build.gradle.kts b/common/build.gradle.kts index a2595f9..f01959a 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -19,6 +19,8 @@ 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") + compileOnly("com.mojang:brigadier:1.0.18") + compileOnly("com.zaxxer:HikariCP:5.0.1") compileOnly("redis.clients:jedis:5.1.0") diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/api/impl/ApiCommandManager.java b/common/src/main/java/dev/xhyrom/lighteco/common/api/impl/ApiCommandManager.java index bab2ecd..bbfa9f4 100644 --- a/common/src/main/java/dev/xhyrom/lighteco/common/api/impl/ApiCommandManager.java +++ b/common/src/main/java/dev/xhyrom/lighteco/common/api/impl/ApiCommandManager.java @@ -5,8 +5,8 @@ import dev.xhyrom.lighteco.api.model.currency.Currency; import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin; import org.checkerframework.checker.nullness.qual.NonNull; -public class ApiCommandManager extends ApiAbstractManager implements CommandManager { - public ApiCommandManager(LightEcoPlugin plugin, dev.xhyrom.lighteco.common.manager.command.CommandManager handle) { +public class ApiCommandManager extends ApiAbstractManager implements CommandManager { + public ApiCommandManager(LightEcoPlugin plugin, dev.xhyrom.lighteco.common.command.CommandManager handle) { super(plugin, handle); } @@ -15,7 +15,7 @@ public class ApiCommandManager extends ApiAbstractManager context) { + LightEcoPlugin plugin = context.getSource().plugin(); + CommandSender sender = context.getSource().sender(); + + User target = null; + try { + target = OfflineUserArgument.getOfflineUser(context, "target"); + } catch (LockedUserException e) { + sender.sendMessage(MiniMessage.miniMessage().deserialize( + plugin.getConfig().messages.wait + )); + } + + if (target == null || target.getUsername() == null) { + String userName = context.getArgument("target", String.class); + + sender.sendMessage(MiniMessage.miniMessage().deserialize( + plugin.getConfig().messages.userNotFound, + Placeholder.parsed("username", userName) + )); + return null; + } + + return target; + } + + public static CurrencyMessageConfig getCurrencyMessageConfig(LightEcoPlugin plugin, Currency currency) { + Map config = plugin.getConfig().messages.currency; + CurrencyMessageConfig currencyMessageConfig = config.get(currency.getIdentifier()); + + if (currencyMessageConfig == null) { + return config.get("default"); + } + + return currencyMessageConfig; + } +} diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/command/CommandManager.java b/common/src/main/java/dev/xhyrom/lighteco/common/command/CommandManager.java new file mode 100644 index 0000000..f04c600 --- /dev/null +++ b/common/src/main/java/dev/xhyrom/lighteco/common/command/CommandManager.java @@ -0,0 +1,130 @@ +package dev.xhyrom.lighteco.common.command; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +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.commands.BalanceCommand; +import dev.xhyrom.lighteco.common.commands.CurrencyParentCommand; +import dev.xhyrom.lighteco.common.commands.InfoCommand; +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 net.kyori.adventure.text.minimessage.MiniMessage; + +import java.util.*; +import java.util.concurrent.*; + +public class CommandManager { + protected final LightEcoPlugin plugin; + private final ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder() + .setDaemon(true) + .setNameFormat("lighteco-command-executor") + .build() + ); + + @Getter + private final CommandDispatcher dispatcher = new CommandDispatcher<>(); + + @Getter + private final Set locks = ConcurrentHashMap.newKeySet(); + private final Map locksMappings = new ConcurrentHashMap<>(); + + public CommandManager(LightEcoPlugin plugin) { + this.plugin = plugin; + } + + // Register built-in commands + public void register() { + register(new InfoCommand()); + } + + public void register(Currency currency, boolean main) { + register(new CurrencyParentCommand(currency)); + + if (main) { + register(BalanceCommand.create(currency)); + register(PayCommand.create(currency)); + } + } + + protected void register(Command command) { + dispatcher.getRoot().addChild(command.build()); + } + + public void execute(CommandSender sender, String name, String[] args) { + if (!sender.isConsole() && locks.contains(sender.getUniqueId())) { + sender.sendMessage(MiniMessage.miniMessage().deserialize( + this.plugin.getConfig().messages.wait + )); + return; + } + + final CommandSource source = new CommandSource(this.plugin, sender); + final ParseResults parseResults = dispatcher.parse( + name + (args.length > 0 ? " " + String.join(" ", args) : ""), + source + ); + + if (!sender.isConsole()) + locks.add(sender.getUniqueId()); + + CompletableFuture.runAsync(() -> { + try { + dispatcher.execute(parseResults); + } catch (CommandSyntaxException e) { + this.sendError(sender, name, e); + } finally { + if (!source.sender().isConsole()) { + this.plugin.getBootstrap().getLogger().debug("Removing lock for " + sender.getUsername()); + + UUID target = locksMappings.get(sender.getUniqueId()); + if (target != null) { + locks.remove(target); + locksMappings.remove(sender.getUniqueId()); + + this.plugin.getBootstrap().getLogger().debug("Removing lock caused by " + sender.getUsername() + " for " + target); + } + + locks.remove(sender.getUniqueId()); + } + } + }, executor); + } + + public void lockBySender(CommandSender sender, UUID target) { + locks.add(target); + locksMappings.put(sender.getUniqueId(), target); + } + + private void sendError(CommandSender sender, String name, 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); + } + } +} diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/command/CommandSource.java b/common/src/main/java/dev/xhyrom/lighteco/common/command/CommandSource.java new file mode 100644 index 0000000..103ac6e --- /dev/null +++ b/common/src/main/java/dev/xhyrom/lighteco/common/command/CommandSource.java @@ -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) { +} diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/command/abstraction/Command.java b/common/src/main/java/dev/xhyrom/lighteco/common/command/abstraction/Command.java new file mode 100644 index 0000000..c44f2af --- /dev/null +++ b/common/src/main/java/dev/xhyrom/lighteco/common/command/abstraction/Command.java @@ -0,0 +1,36 @@ +package dev.xhyrom.lighteco.common.command.abstraction; + +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.tree.CommandNode; +import dev.xhyrom.lighteco.common.command.CommandSource; +import lombok.Getter; +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@Getter +public abstract class Command { + @NonNull + protected final String name; + + @NonNull + private final String description; + + @NonNull + private final List aliases = new ArrayList<>(); + + public Command(@NonNull String name, @NonNull String description, String... aliases) { + this.name = name; + this.description = description; + + Collections.addAll(this.aliases, aliases); + } + + public abstract CommandNode build(); + + protected LiteralArgumentBuilder builder() { + return LiteralArgumentBuilder.literal(name); + } +} diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/command/argument/type/OfflineUserArgument.java b/common/src/main/java/dev/xhyrom/lighteco/common/command/argument/type/OfflineUserArgument.java new file mode 100644 index 0000000..9416568 --- /dev/null +++ b/common/src/main/java/dev/xhyrom/lighteco/common/command/argument/type/OfflineUserArgument.java @@ -0,0 +1,43 @@ +package dev.xhyrom.lighteco.common.command.argument.type; + +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.command.exception.LockedUserException; +import dev.xhyrom.lighteco.common.model.chat.CommandSender; +import dev.xhyrom.lighteco.common.model.user.User; +import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin; + +import java.util.UUID; + +public class OfflineUserArgument implements ArgumentType { + private OfflineUserArgument() {} + + public static User getOfflineUser(CommandContext context, String name) throws LockedUserException { + String userName = context.getArgument(name, String.class); + LightEcoPlugin plugin = context.getSource().plugin(); + CommandSender sender = context.getSource().sender(); + + UUID uniqueId = plugin.getBootstrap().lookupUniqueId(userName).orElse(null); + if (uniqueId == null) { + return null; + } + + if (sender.getUniqueId() != uniqueId && plugin.getCommandManager().getLocks().contains(uniqueId)) { + throw new LockedUserException(uniqueId); + } + + // Lock the user to prevent race conditions + if (!sender.isConsole()) + plugin.getCommandManager().lockBySender(context.getSource().sender(), uniqueId); + + return plugin.getUserManager().loadUser(uniqueId).join(); + } + + @Override + public String parse(StringReader reader) throws CommandSyntaxException { + return reader.readString(); + } +} \ No newline at end of file diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/command/exception/LockedUserException.java b/common/src/main/java/dev/xhyrom/lighteco/common/command/exception/LockedUserException.java new file mode 100644 index 0000000..994d0d1 --- /dev/null +++ b/common/src/main/java/dev/xhyrom/lighteco/common/command/exception/LockedUserException.java @@ -0,0 +1,9 @@ +package dev.xhyrom.lighteco.common.command.exception; + +import java.util.UUID; + +public class LockedUserException extends Exception { + public LockedUserException(UUID uniqueId) { + super("User with uuid " + uniqueId + " is currently locked thus cannot be modified"); + } +} diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/command/suggestion/type/OfflineUserSuggestionProvider.java b/common/src/main/java/dev/xhyrom/lighteco/common/command/suggestion/type/OfflineUserSuggestionProvider.java new file mode 100644 index 0000000..9aa86d1 --- /dev/null +++ b/common/src/main/java/dev/xhyrom/lighteco/common/command/suggestion/type/OfflineUserSuggestionProvider.java @@ -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 { + public static OfflineUserSuggestionProvider create() { + return new OfflineUserSuggestionProvider(); + } + + @Override + public CompletableFuture getSuggestions(CommandContext 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(); + } +} diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/commands/BalanceCommand.java b/common/src/main/java/dev/xhyrom/lighteco/common/commands/BalanceCommand.java new file mode 100644 index 0000000..471b675 --- /dev/null +++ b/common/src/main/java/dev/xhyrom/lighteco/common/commands/BalanceCommand.java @@ -0,0 +1,83 @@ +package dev.xhyrom.lighteco.common.commands; + +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; +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.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 static com.mojang.brigadier.Command.SINGLE_SUCCESS; +import static dev.xhyrom.lighteco.common.command.CommandHelper.*; + +public class BalanceCommand extends Command { + private final Currency currency; + + public static BalanceCommand create(@NonNull Currency currency) { + return new BalanceCommand(currency); + } + + public BalanceCommand(@NonNull Currency currency) { + super("balance", "Check your balance"); + + this.currency = currency; + } + + @Override + public CommandNode build() { + return builder() + .then( + RequiredArgumentBuilder.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(); + + final User target = getUser(context); + if (target == 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(); + } +} diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/commands/CurrencyParentCommand.java b/common/src/main/java/dev/xhyrom/lighteco/common/commands/CurrencyParentCommand.java new file mode 100644 index 0000000..84ef42b --- /dev/null +++ b/common/src/main/java/dev/xhyrom/lighteco/common/commands/CurrencyParentCommand.java @@ -0,0 +1,62 @@ +package dev.xhyrom.lighteco.common.commands; + +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; + +import java.math.BigDecimal; + +import static com.mojang.brigadier.Command.SINGLE_SUCCESS; +import static dev.xhyrom.lighteco.common.command.CommandHelper.getCurrencyMessageConfig; + +public class CurrencyParentCommand extends Command { + private final Currency currency; + + public CurrencyParentCommand(@NonNull Currency currency) { + super( + currency.getIdentifier(), + currency.getIdentifier() + ); + + this.currency = currency; + } + + @Override + public CommandNode build() { + LiteralArgumentBuilder 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(); + } +} diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/commands/GiveCommand.java b/common/src/main/java/dev/xhyrom/lighteco/common/commands/GiveCommand.java new file mode 100644 index 0000000..7e247d5 --- /dev/null +++ b/common/src/main/java/dev/xhyrom/lighteco/common/commands/GiveCommand.java @@ -0,0 +1,106 @@ +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.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; +import static dev.xhyrom.lighteco.common.command.CommandHelper.*; + +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 context) { + final LightEcoPlugin plugin = context.getSource().plugin(); + final CommandSender sender = context.getSource().sender(); + + final User target = getUser(context); + if (target == 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( + getCurrencyMessageConfig(plugin, this.currency).cannotBeGreaterThan, + Placeholder.parsed("max", plugin.getConfig().maximumBalance.toPlainString()) + ) + ); + + return; + } + + sender.sendMessage( + miniMessage.deserialize( + getCurrencyMessageConfig(plugin, this.currency).set, + Placeholder.parsed("currency", currency.getIdentifier()), + Placeholder.parsed("target", target.getUsername()), + Placeholder.parsed("amount", amount.toPlainString()) + ) + ); + } + + @Override + public CommandNode build() { + if (currency.fractionalDigits() > 0) { + return builder() + .requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.give")) + .then(RequiredArgumentBuilder.argument("target", StringArgumentType.word()) + .suggests(OfflineUserSuggestionProvider.create()) + .then(RequiredArgumentBuilder.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.argument("target", StringArgumentType.word()) + .suggests(OfflineUserSuggestionProvider.create()) + .then(RequiredArgumentBuilder.argument("amount", IntegerArgumentType.integer(1)) + .requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.give")) + .executes(c -> { + execute(c); + return SINGLE_SUCCESS; + }))) + .build(); + } +} diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/commands/InfoCommand.java b/common/src/main/java/dev/xhyrom/lighteco/common/commands/InfoCommand.java new file mode 100644 index 0000000..fc4fe0f --- /dev/null +++ b/common/src/main/java/dev/xhyrom/lighteco/common/commands/InfoCommand.java @@ -0,0 +1,36 @@ +package dev.xhyrom.lighteco.common.commands; + +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.plugin.LightEcoPlugin; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; + +import static com.mojang.brigadier.Command.SINGLE_SUCCESS; + +public class InfoCommand extends Command { + public InfoCommand() { + super("lighteco", "LightEco information"); + } + + @Override + public CommandNode build() { + return builder() + .requires(source -> source.sender().eligible("lighteco.command.info")) + .executes(context -> { + LightEcoPlugin plugin = context.getSource().plugin(); + CommandSender sender = context.getSource().sender(); + + sender.sendMessage(MiniMessage.miniMessage().deserialize( + "<#fa5246>LightEco (<#d6766f>v) on <#d6766f>", + Placeholder.parsed("version", plugin.getBootstrap().getVersion()), + Placeholder.parsed("platform", plugin.getPlatformType().getName()) + )); + + return SINGLE_SUCCESS; + }) + .build(); + } +} diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/commands/PayCommand.java b/common/src/main/java/dev/xhyrom/lighteco/common/commands/PayCommand.java new file mode 100644 index 0000000..94db38c --- /dev/null +++ b/common/src/main/java/dev/xhyrom/lighteco/common/commands/PayCommand.java @@ -0,0 +1,150 @@ +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.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; +import static dev.xhyrom.lighteco.common.command.CommandHelper.*; + +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 context) { + final LightEcoPlugin plugin = context.getSource().plugin(); + final CommandSender sender = context.getSource().sender(); + + final User target = getUser(context); + if (target == 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(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( + getCurrencyMessageConfig(plugin, this.currency).cannotBeGreaterThan, + Placeholder.parsed("max", plugin.getConfig().maximumBalance.toPlainString()) + ) + ); + + return; + } + + String template = tax.compareTo(BigDecimal.ZERO) > 0 + ? getCurrencyMessageConfig(plugin, this.currency).payWithTax + : getCurrencyMessageConfig(plugin, this.currency).pay; + + String templateReceived = tax.compareTo(BigDecimal.ZERO) > 0 + ? getCurrencyMessageConfig(plugin, this.currency).payReceivedWithTax + : 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 build() { + if (currency.fractionalDigits() > 0) { + return builder() + .requires((source) -> !source.sender().isConsole() && source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.pay")) + .then(RequiredArgumentBuilder.argument("target", StringArgumentType.word()) + .suggests(OfflineUserSuggestionProvider.create()) + .then(RequiredArgumentBuilder.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().isConsole() && source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.pay")) + .then(RequiredArgumentBuilder.argument("target", StringArgumentType.word()) + .suggests(OfflineUserSuggestionProvider.create()) + .then(RequiredArgumentBuilder.argument("amount", IntegerArgumentType.integer(1)) + .requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.pay")) + .executes(c -> { + execute(c); + return SINGLE_SUCCESS; + }))) + .build(); + } +} diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/commands/SetCommand.java b/common/src/main/java/dev/xhyrom/lighteco/common/commands/SetCommand.java new file mode 100644 index 0000000..06b3ef2 --- /dev/null +++ b/common/src/main/java/dev/xhyrom/lighteco/common/commands/SetCommand.java @@ -0,0 +1,106 @@ +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.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; +import static dev.xhyrom.lighteco.common.command.CommandHelper.*; + +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 context) { + final LightEcoPlugin plugin = context.getSource().plugin(); + final CommandSender sender = context.getSource().sender(); + + final User target = getUser(context); + if (target == 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( + getCurrencyMessageConfig(plugin, this.currency).cannotBeGreaterThan, + Placeholder.parsed("max", plugin.getConfig().maximumBalance.toPlainString()) + ) + ); + + return; + } + + sender.sendMessage( + miniMessage.deserialize( + getCurrencyMessageConfig(plugin, this.currency).set, + Placeholder.parsed("currency", currency.getIdentifier()), + Placeholder.parsed("target", target.getUsername()), + Placeholder.parsed("amount", amount.toPlainString()) + ) + ); + } + + @Override + public CommandNode build() { + if (currency.fractionalDigits() > 0) { + return builder() + .requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.set")) + .then(RequiredArgumentBuilder.argument("target", StringArgumentType.word()) + .suggests(OfflineUserSuggestionProvider.create()) + .then(RequiredArgumentBuilder.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.argument("target", StringArgumentType.word()) + .suggests(OfflineUserSuggestionProvider.create()) + .then(RequiredArgumentBuilder.argument("amount", IntegerArgumentType.integer(1)) + .requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.set")) + .executes(c -> { + execute(c); + return SINGLE_SUCCESS; + }))) + .build(); + } +} diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/commands/TakeCommand.java b/common/src/main/java/dev/xhyrom/lighteco/common/commands/TakeCommand.java new file mode 100644 index 0000000..75187b1 --- /dev/null +++ b/common/src/main/java/dev/xhyrom/lighteco/common/commands/TakeCommand.java @@ -0,0 +1,106 @@ +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.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; +import static dev.xhyrom.lighteco.common.command.CommandHelper.*; + +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 context) { + final LightEcoPlugin plugin = context.getSource().plugin(); + final CommandSender sender = context.getSource().sender(); + + final User target = getUser(context); + if (target == 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( + getCurrencyMessageConfig(plugin, this.currency).cannotBeGreaterThan, + Placeholder.parsed("max", plugin.getConfig().maximumBalance.toPlainString()) + ) + ); + + return; + } + + sender.sendMessage( + miniMessage.deserialize( + getCurrencyMessageConfig(plugin, this.currency).set, + Placeholder.parsed("currency", currency.getIdentifier()), + Placeholder.parsed("target", target.getUsername()), + Placeholder.parsed("amount", amount.toPlainString()) + ) + ); + } + + @Override + public CommandNode build() { + if (currency.fractionalDigits() > 0) { + return builder() + .requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.take")) + .then(RequiredArgumentBuilder.argument("target", StringArgumentType.word()) + .suggests(OfflineUserSuggestionProvider.create()) + .then(RequiredArgumentBuilder.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.argument("target", StringArgumentType.word()) + .suggests(OfflineUserSuggestionProvider.create()) + .then(RequiredArgumentBuilder.argument("amount", IntegerArgumentType.integer(1)) + .requires((source) -> source.sender().eligible("lighteco.currency." + currency.getIdentifier() + ".command.take")) + .executes(c -> { + execute(c); + return SINGLE_SUCCESS; + }))) + .build(); + } +} diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/config/message/CurrencyMessageConfig.java b/common/src/main/java/dev/xhyrom/lighteco/common/config/message/CurrencyMessageConfig.java index 00380ce..d5589a2 100644 --- a/common/src/main/java/dev/xhyrom/lighteco/common/config/message/CurrencyMessageConfig.java +++ b/common/src/main/java/dev/xhyrom/lighteco/common/config/message/CurrencyMessageConfig.java @@ -17,7 +17,6 @@ public class CurrencyMessageConfig extends OkaeriConfig { public String payReceived = " | Received from "; public String payReceivedWithTax = " | Received from ( after tax)"; - public String wait = "Please wait a moment before using this command again."; public String notEnoughMoney = "You don't have enough money!"; public String cannotPaySelf = "You cannot pay yourself!"; public String cannotBeGreaterThan = "Amount cannot be greater than "; diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/config/message/MessageConfig.java b/common/src/main/java/dev/xhyrom/lighteco/common/config/message/MessageConfig.java index 88be91a..1e0a5ef 100644 --- a/common/src/main/java/dev/xhyrom/lighteco/common/config/message/MessageConfig.java +++ b/common/src/main/java/dev/xhyrom/lighteco/common/config/message/MessageConfig.java @@ -7,4 +7,7 @@ import java.util.Map; public class MessageConfig extends OkaeriConfig { public Map currency = Collections.singletonMap("default", new CurrencyMessageConfig()); + + public String wait = "Please wait a moment before using this command again."; + public String userNotFound = "User not found."; } diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/manager/command/AbstractCommandManager.java b/common/src/main/java/dev/xhyrom/lighteco/common/manager/command/AbstractCommandManager.java deleted file mode 100644 index dec658f..0000000 --- a/common/src/main/java/dev/xhyrom/lighteco/common/manager/command/AbstractCommandManager.java +++ /dev/null @@ -1,275 +0,0 @@ -package dev.xhyrom.lighteco.common.manager.command; - -import dev.xhyrom.lighteco.api.exception.CannotBeGreaterThan; -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 java.math.BigDecimal; -import java.math.RoundingMode; -import java.util.ArrayList; -import java.util.Map; -import java.util.UUID; - -public abstract class AbstractCommandManager implements CommandManager { - public final LightEcoPlugin plugin; - private final MiniMessage miniMessage = MiniMessage.miniMessage(); - private final Map config; - private final ArrayList mustWait = new ArrayList<>(); - - protected AbstractCommandManager(LightEcoPlugin plugin) { - this.plugin = plugin; - this.config = this.plugin.getConfig().messages.currency; - } - - @Override - public boolean canUse(CommandSender sender, Currency currency) { - // Console doesn't need to wait - if (sender.getUniqueId() == null) return true; - - if (mustWait.contains(sender.getUniqueId())) { - sender.sendMessage( - miniMessage.deserialize( - this.getConfig(currency).wait - ) - ); - - return false; - } - - return true; - } - - private void addToMustWait(UUID ...uuids) { - for (UUID uuid : uuids) { - if (uuid != null) - mustWait.add(uuid); - } - } - - private void removeFromMustWait(UUID ...uuids) { - for (UUID uuid : uuids) { - if (uuid != null) - mustWait.remove(uuid); - } - } - - private CurrencyMessageConfig getConfig(Currency currency) { - CurrencyMessageConfig currencyMessageConfig = this.config.get(currency.getIdentifier()); - - if (currencyMessageConfig == null) { - return this.config.get("default"); - } - - return currencyMessageConfig; - } - - @Override - public void onBalance(CommandSender sender, Currency currency) { - User user = this.plugin.getUserManager().getIfLoaded(sender.getUniqueId()); - BigDecimal balance = user.getBalance(currency); - - sender.sendMessage( - miniMessage.deserialize( - getConfig(currency).balance, - Placeholder.parsed("currency", currency.getIdentifier()), - Placeholder.parsed("balance", balance.toPlainString()) - ) - ); - } - - @Override - public void onBalance(CommandSender sender, Currency currency, User target) { - BigDecimal balance = target.getBalance(currency); - - sender.sendMessage( - miniMessage.deserialize( - getConfig(currency).balanceOthers, - Placeholder.parsed("currency", currency.getIdentifier()), - Placeholder.parsed("target", target.getUsername()), - Placeholder.parsed("balance", balance.toPlainString()) - ) - - ); - } - - @Override - public void onSet(CommandSender sender, Currency currency, User target, BigDecimal amount) { - addToMustWait(sender.getUniqueId(), target.getUniqueId()); - amount = amount.setScale(currency.getProxy().fractionalDigits(), RoundingMode.DOWN); - - try { - target.setBalance(currency, amount); - } catch (CannotBeGreaterThan e) { - removeFromMustWait(target.getUniqueId(), sender.getUniqueId()); - sender.sendMessage( - miniMessage.deserialize( - this.getConfig(currency).cannotBeGreaterThan, - Placeholder.parsed("max", this.plugin.getConfig().maximumBalance.toPlainString()) - ) - ); - - return; - } - - sender.sendMessage( - miniMessage.deserialize( - this.getConfig(currency).set, - Placeholder.parsed("currency", currency.getIdentifier()), - Placeholder.parsed("target", target.getUsername()), - Placeholder.parsed("amount", amount.toPlainString()) - ) - ); - - removeFromMustWait(target.getUniqueId(), sender.getUniqueId()); - } - - @Override - public void onGive(CommandSender sender, Currency currency, User target, BigDecimal amount) { - addToMustWait(sender.getUniqueId(), target.getUniqueId()); - amount = amount.setScale(currency.getProxy().fractionalDigits(), RoundingMode.DOWN); - - try { - target.deposit(currency, amount); - } catch (CannotBeGreaterThan e) { - removeFromMustWait(target.getUniqueId(), sender.getUniqueId()); - sender.sendMessage( - miniMessage.deserialize( - this.getConfig(currency).cannotBeGreaterThan, - Placeholder.parsed("max", this.plugin.getConfig().maximumBalance.toPlainString()) - ) - ); - - return; - } - - sender.sendMessage( - miniMessage.deserialize( - this.getConfig(currency).give, - Placeholder.parsed("currency", currency.getIdentifier()), - Placeholder.parsed("target", target.getUsername()), - Placeholder.parsed("amount", amount.toPlainString()), - Placeholder.parsed("balance", target.getBalance(currency).toPlainString()) - ) - ); - - removeFromMustWait(target.getUniqueId(), sender.getUniqueId()); - } - - @Override - public void onTake(CommandSender sender, Currency currency, User target, BigDecimal amount) { - addToMustWait(sender.getUniqueId(), target.getUniqueId()); - amount = amount.setScale(currency.getProxy().fractionalDigits(), RoundingMode.DOWN); - - try { - target.withdraw(currency, amount); - } catch (CannotBeGreaterThan e) { - removeFromMustWait(target.getUniqueId(), sender.getUniqueId()); - sender.sendMessage( - miniMessage.deserialize( - this.getConfig(currency).cannotBeGreaterThan, - Placeholder.parsed("max", this.plugin.getConfig().maximumBalance.toPlainString()) - ) - ); - - return; - } - - sender.sendMessage( - miniMessage.deserialize( - this.getConfig(currency).take, - Placeholder.parsed("currency", currency.getIdentifier()), - Placeholder.parsed("target", target.getUsername()), - Placeholder.parsed("amount", amount.toPlainString()), - Placeholder.parsed("balance", target.getBalance(currency).toPlainString()) - ) - ); - - removeFromMustWait(target.getUniqueId(), sender.getUniqueId()); - } - - @Override - public void onPay(CommandSender sender, Currency currency, User target, BigDecimal amount) { - if (sender.getUniqueId() != null && (sender.getUniqueId() == target.getUniqueId())) { - sender.sendMessage( - miniMessage.deserialize(this.getConfig(currency).cannotPaySelf) - ); - - return; - } - - amount = amount.setScale(currency.getProxy().fractionalDigits(), RoundingMode.DOWN); - - User user = this.plugin.getUserManager().getIfLoaded(sender.getUniqueId()); - - if (user.getBalance(currency).compareTo(amount) < 0) { - sender.sendMessage( - miniMessage.deserialize(this.getConfig(currency).notEnoughMoney) - ); - - return; - } - - addToMustWait(sender.getUniqueId(), target.getUniqueId()); - - // 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) { - removeFromMustWait(target.getUniqueId(), sender.getUniqueId()); - sender.sendMessage( - miniMessage.deserialize( - this.getConfig(currency).cannotBeGreaterThan, - Placeholder.parsed("max", this.plugin.getConfig().maximumBalance.toPlainString()) - ) - ); - - return; - } - - String template = tax.compareTo(BigDecimal.ZERO) > 0 - ? this.getConfig(currency).payWithTax - : this.getConfig(currency).pay; - - String templateReceived = tax.compareTo(BigDecimal.ZERO) > 0 - ? this.getConfig(currency).payReceivedWithTax - : this.getConfig(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()) - ) - ); - - removeFromMustWait(target.getUniqueId(), sender.getUniqueId()); - } -} diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/manager/command/CommandManager.java b/common/src/main/java/dev/xhyrom/lighteco/common/manager/command/CommandManager.java deleted file mode 100644 index bcb3c5d..0000000 --- a/common/src/main/java/dev/xhyrom/lighteco/common/manager/command/CommandManager.java +++ /dev/null @@ -1,23 +0,0 @@ -package dev.xhyrom.lighteco.common.manager.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 org.checkerframework.checker.nullness.qual.NonNull; - -import java.math.BigDecimal; - -public interface CommandManager { - void registerCurrencyCommand(@NonNull Currency currency); - void registerCurrencyCommand(@NonNull Currency currency, boolean main); - - boolean canUse(CommandSender sender, Currency currency); - - void onBalance(CommandSender sender, Currency currency); - void onBalance(CommandSender sender, Currency currency, User target); - - void onSet(CommandSender sender, Currency currency, User target, BigDecimal amount); - void onGive(CommandSender sender, Currency currency, User target, BigDecimal amount); - void onTake(CommandSender sender, Currency currency, User target, BigDecimal amount); - void onPay(CommandSender sender, Currency currency, User target, BigDecimal amount); -} diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/model/chat/CommandSender.java b/common/src/main/java/dev/xhyrom/lighteco/common/model/chat/CommandSender.java index 9827b2b..63b197a 100644 --- a/common/src/main/java/dev/xhyrom/lighteco/common/model/chat/CommandSender.java +++ b/common/src/main/java/dev/xhyrom/lighteco/common/model/chat/CommandSender.java @@ -1,12 +1,18 @@ package dev.xhyrom.lighteco.common.model.chat; import net.kyori.adventure.text.Component; +import org.checkerframework.checker.nullness.qual.Nullable; import java.util.UUID; public interface CommandSender { String getUsername(); - UUID getUniqueId(); + @Nullable UUID getUniqueId(); + boolean eligible(String permission); void sendMessage(Component message); + + default boolean isConsole() { + return getUniqueId() == null; + } } diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/plugin/AbstractLightEcoPlugin.java b/common/src/main/java/dev/xhyrom/lighteco/common/plugin/AbstractLightEcoPlugin.java index ab03d48..639716c 100644 --- a/common/src/main/java/dev/xhyrom/lighteco/common/plugin/AbstractLightEcoPlugin.java +++ b/common/src/main/java/dev/xhyrom/lighteco/common/plugin/AbstractLightEcoPlugin.java @@ -65,6 +65,9 @@ public abstract class AbstractLightEcoPlugin implements LightEcoPlugin { // setup managers this.setupManagers(); + // register built-in commands + this.getCommandManager().register(); + // register platform hooks this.registerPlatformHooks(); diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/plugin/LightEcoPlugin.java b/common/src/main/java/dev/xhyrom/lighteco/common/plugin/LightEcoPlugin.java index 0791a64..3953c3c 100644 --- a/common/src/main/java/dev/xhyrom/lighteco/common/plugin/LightEcoPlugin.java +++ b/common/src/main/java/dev/xhyrom/lighteco/common/plugin/LightEcoPlugin.java @@ -2,9 +2,9 @@ package dev.xhyrom.lighteco.common.plugin; import dev.xhyrom.lighteco.api.manager.ContextManager; import dev.xhyrom.lighteco.api.platform.Platform; +import dev.xhyrom.lighteco.common.command.CommandManager; import dev.xhyrom.lighteco.common.config.Config; import dev.xhyrom.lighteco.common.dependencies.DependencyManager; -import dev.xhyrom.lighteco.common.manager.command.CommandManager; import dev.xhyrom.lighteco.common.manager.currency.CurrencyManager; import dev.xhyrom.lighteco.common.manager.user.UserManager; import dev.xhyrom.lighteco.common.messaging.InternalMessagingService; diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/plugin/bootstrap/LightEcoBootstrap.java b/common/src/main/java/dev/xhyrom/lighteco/common/plugin/bootstrap/LightEcoBootstrap.java index 07b053a..0e349a8 100644 --- a/common/src/main/java/dev/xhyrom/lighteco/common/plugin/bootstrap/LightEcoBootstrap.java +++ b/common/src/main/java/dev/xhyrom/lighteco/common/plugin/bootstrap/LightEcoBootstrap.java @@ -7,6 +7,7 @@ import net.kyori.adventure.audience.Audience; import java.io.InputStream; import java.nio.file.Path; import java.util.List; +import java.util.Optional; import java.util.UUID; public interface LightEcoBootstrap { @@ -14,8 +15,12 @@ public interface LightEcoBootstrap { PluginLogger getLogger(); SchedulerAdapter getScheduler(); Path getDataDirectory(); + String getVersion(); + + Optional lookupUniqueId(String username); boolean isPlayerOnline(UUID uniqueId); List getOnlinePlayers(); + InputStream getResourceStream(String filename); Audience getPlayerAudience(UUID uniqueId); } diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/plugin/logger/PluginLogger.java b/common/src/main/java/dev/xhyrom/lighteco/common/plugin/logger/PluginLogger.java index ca1ab93..3f0c578 100644 --- a/common/src/main/java/dev/xhyrom/lighteco/common/plugin/logger/PluginLogger.java +++ b/common/src/main/java/dev/xhyrom/lighteco/common/plugin/logger/PluginLogger.java @@ -4,6 +4,9 @@ public interface PluginLogger { void info(String message); void info(String message, Object ...args); + void debug(String message); + void debug(String message, Object ...args); + void warn(String message); void warn(String message, Object ...args); diff --git a/currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/bukkit/BukkitMCLoader.java b/currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/paper/PaperMCLoader.java similarity index 88% rename from currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/bukkit/BukkitMCLoader.java rename to currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/paper/PaperMCLoader.java index f19dc8b..51a39ad 100644 --- a/currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/bukkit/BukkitMCLoader.java +++ b/currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/paper/PaperMCLoader.java @@ -1,23 +1,23 @@ -package dev.xhyrom.lighteco.currency.money.bukkit; +package dev.xhyrom.lighteco.currency.money.paper; import dev.xhyrom.lighteco.api.LightEco; import dev.xhyrom.lighteco.api.LightEcoProvider; import dev.xhyrom.lighteco.api.manager.CommandManager; import dev.xhyrom.lighteco.api.manager.CurrencyManager; import dev.xhyrom.lighteco.api.model.currency.Currency; -import dev.xhyrom.lighteco.currency.money.bukkit.hooks.vault.VaultFactory; +import dev.xhyrom.lighteco.currency.money.paper.hooks.vault.VaultFactory; import dev.xhyrom.lighteco.currency.money.common.AbstractPlugin; import dev.xhyrom.lighteco.currency.money.common.Plugin; import dev.xhyrom.lighteco.currency.money.common.currency.MoneyCurrency; import lombok.Getter; import org.bukkit.plugin.java.JavaPlugin; -public class BukkitMCLoader extends JavaPlugin { +public class PaperMCLoader extends JavaPlugin { private VaultFactory vaultFactory; @Getter private final Plugin plugin; - public BukkitMCLoader() { + public PaperMCLoader() { this.plugin = new AbstractPlugin(this.getDataFolder().toPath()); } diff --git a/currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/bukkit/hooks/vault/Vault.java b/currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/paper/hooks/vault/Vault.java similarity index 99% rename from currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/bukkit/hooks/vault/Vault.java rename to currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/paper/hooks/vault/Vault.java index 03888e4..cc2cb94 100644 --- a/currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/bukkit/hooks/vault/Vault.java +++ b/currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/paper/hooks/vault/Vault.java @@ -1,4 +1,4 @@ -package dev.xhyrom.lighteco.currency.money.bukkit.hooks.vault; +package dev.xhyrom.lighteco.currency.money.paper.hooks.vault; import dev.xhyrom.lighteco.api.LightEco; import dev.xhyrom.lighteco.api.LightEcoProvider; diff --git a/currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/bukkit/hooks/vault/VaultFactory.java b/currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/paper/hooks/vault/VaultFactory.java similarity index 76% rename from currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/bukkit/hooks/vault/VaultFactory.java rename to currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/paper/hooks/vault/VaultFactory.java index 8a72208..84d8829 100644 --- a/currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/bukkit/hooks/vault/VaultFactory.java +++ b/currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/paper/hooks/vault/VaultFactory.java @@ -1,16 +1,16 @@ -package dev.xhyrom.lighteco.currency.money.bukkit.hooks.vault; +package dev.xhyrom.lighteco.currency.money.paper.hooks.vault; -import dev.xhyrom.lighteco.currency.money.bukkit.BukkitMCLoader; +import dev.xhyrom.lighteco.currency.money.paper.PaperMCLoader; import net.milkbowl.vault.economy.Economy; import org.bukkit.Bukkit; import org.bukkit.plugin.ServicePriority; import org.bukkit.plugin.ServicesManager; public class VaultFactory { - private final BukkitMCLoader loader; + private final PaperMCLoader loader; private Vault vault; - public VaultFactory(BukkitMCLoader loader) { + public VaultFactory(PaperMCLoader loader) { this.loader = loader; } diff --git a/currency-money/src/main/resources/plugin.yml b/currency-money/src/main/resources/plugin.yml index d1c95bb..e893415 100644 --- a/currency-money/src/main/resources/plugin.yml +++ b/currency-money/src/main/resources/plugin.yml @@ -1,11 +1,11 @@ name: ${name} description: ${description} version: ${version} -main: dev.xhyrom.lighteco.currency.money.bukkit.BukkitMCLoader +main: dev.xhyrom.lighteco.currency.money.paper.PaperMCLoader author: ${author} -api-version: 1.20 +api-version: 1.17 load: STARTUP softdepend: - Vault - - lighteco-bukkit + - LightEco diff --git a/bukkit/.gitignore b/paper/.gitignore similarity index 100% rename from bukkit/.gitignore rename to paper/.gitignore diff --git a/bukkit/README.md b/paper/README.md similarity index 100% rename from bukkit/README.md rename to paper/README.md diff --git a/bukkit/build.gradle.kts b/paper/build.gradle.kts similarity index 81% rename from bukkit/build.gradle.kts rename to paper/build.gradle.kts index 93903e5..0456452 100644 --- a/bukkit/build.gradle.kts +++ b/paper/build.gradle.kts @@ -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") diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitLightEcoBootstrap.java b/paper/src/main/java/dev/xhyrom/lighteco/paper/PaperLightEcoBootstrap.java similarity index 67% rename from bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitLightEcoBootstrap.java rename to paper/src/main/java/dev/xhyrom/lighteco/paper/PaperLightEcoBootstrap.java index a94bf72..0695adb 100644 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitLightEcoBootstrap.java +++ b/paper/src/main/java/dev/xhyrom/lighteco/paper/PaperLightEcoBootstrap.java @@ -1,13 +1,12 @@ -package dev.xhyrom.lighteco.bukkit; +package dev.xhyrom.lighteco.paper; -import dev.jorel.commandapi.CommandAPI; -import dev.jorel.commandapi.CommandAPIBukkitConfig; -import dev.xhyrom.lighteco.bukkit.logger.BukkitLogger; +import dev.xhyrom.lighteco.paper.logger.PaperLogger; import dev.xhyrom.lighteco.common.plugin.bootstrap.LightEcoBootstrap; import dev.xhyrom.lighteco.common.plugin.bootstrap.LoaderBootstrap; import dev.xhyrom.lighteco.common.plugin.logger.PluginLogger; import dev.xhyrom.lighteco.common.plugin.scheduler.SchedulerAdapter; import lombok.Getter; +import org.bukkit.OfflinePlayer; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.platform.bukkit.BukkitAudiences; import org.bukkit.entity.Entity; @@ -17,11 +16,12 @@ import org.bukkit.plugin.java.JavaPlugin; import java.io.InputStream; import java.nio.file.Path; import java.util.List; +import java.util.Optional; import java.util.UUID; @Getter -public class BukkitLightEcoBootstrap implements LightEcoBootstrap, LoaderBootstrap { - private final BukkitLightEcoPlugin plugin = new BukkitLightEcoPlugin(this); +public class PaperLightEcoBootstrap implements LightEcoBootstrap, LoaderBootstrap { + private final PaperLightEcoPlugin plugin = new PaperLightEcoPlugin(this); @Getter private final JavaPlugin loader; @@ -29,33 +29,29 @@ public class BukkitLightEcoBootstrap implements LightEcoBootstrap, LoaderBootstr private final PluginLogger logger; @Getter private final SchedulerAdapter scheduler; + @Getter private BukkitAudiences audience; - public BukkitLightEcoBootstrap(JavaPlugin loader) { + public PaperLightEcoBootstrap(JavaPlugin loader) { this.loader = loader; - this.logger = new BukkitLogger(loader.getLogger()); - this.scheduler = new BukkitSchedulerAdapter(this); + this.logger = new PaperLogger(this.plugin, loader.getLogger()); + this.scheduler = new PaperSchedulerAdapter(this); } @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); + this.audience = BukkitAudiences.create(this.loader); } @Override public void onDisable() { - CommandAPI.onDisable(); this.plugin.disable(); } @@ -64,6 +60,16 @@ public class BukkitLightEcoBootstrap implements LightEcoBootstrap, LoaderBootstr return this.loader.getDataFolder().toPath(); } + @Override + public String getVersion() { + return this.loader.getDescription().getVersion(); + } + + @Override + public Optional lookupUniqueId(String username) { + return Optional.of(this.loader.getServer().getOfflinePlayer(username)).map(OfflinePlayer::getUniqueId); + } + @Override public boolean isPlayerOnline(UUID uniqueId) { Player player = this.loader.getServer().getPlayer(uniqueId); diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitLightEcoLoader.java b/paper/src/main/java/dev/xhyrom/lighteco/paper/PaperLightEcoLoader.java similarity index 60% rename from bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitLightEcoLoader.java rename to paper/src/main/java/dev/xhyrom/lighteco/paper/PaperLightEcoLoader.java index a8f76e9..73b8ae1 100644 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitLightEcoLoader.java +++ b/paper/src/main/java/dev/xhyrom/lighteco/paper/PaperLightEcoLoader.java @@ -1,14 +1,14 @@ -package dev.xhyrom.lighteco.bukkit; +package dev.xhyrom.lighteco.paper; import org.bukkit.plugin.java.JavaPlugin; // Used inside plugin.yml @SuppressWarnings("unused") -public class BukkitLightEcoLoader extends JavaPlugin { - private final BukkitLightEcoBootstrap bootstrap; +public class PaperLightEcoLoader extends JavaPlugin { + private final PaperLightEcoBootstrap bootstrap; - public BukkitLightEcoLoader() { - this.bootstrap = new BukkitLightEcoBootstrap(this); + public PaperLightEcoLoader() { + this.bootstrap = new PaperLightEcoBootstrap(this); } @Override diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitLightEcoPlugin.java b/paper/src/main/java/dev/xhyrom/lighteco/paper/PaperLightEcoPlugin.java similarity index 64% rename from bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitLightEcoPlugin.java rename to paper/src/main/java/dev/xhyrom/lighteco/paper/PaperLightEcoPlugin.java index bca9b1f..a3b5b82 100644 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitLightEcoPlugin.java +++ b/paper/src/main/java/dev/xhyrom/lighteco/paper/PaperLightEcoPlugin.java @@ -1,12 +1,13 @@ -package dev.xhyrom.lighteco.bukkit; +package dev.xhyrom.lighteco.paper; 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.BukkitConnectionListener; -import dev.xhyrom.lighteco.bukkit.manager.BukkitCommandManager; -import dev.xhyrom.lighteco.bukkit.manager.BukkitContextManager; +import dev.xhyrom.lighteco.paper.hooks.Hooks; +import dev.xhyrom.lighteco.paper.listeners.PaperCommandSuggestionsListener; +import dev.xhyrom.lighteco.paper.listeners.PaperConnectionListener; +import dev.xhyrom.lighteco.paper.manager.PaperCommandManager; +import dev.xhyrom.lighteco.paper.manager.PaperContextManager; import dev.xhyrom.lighteco.common.manager.currency.StandardCurrencyManager; import dev.xhyrom.lighteco.common.messaging.MessagingFactory; import dev.xhyrom.lighteco.common.plugin.AbstractLightEcoPlugin; @@ -17,33 +18,34 @@ import org.bukkit.plugin.ServicePriority; import org.checkerframework.checker.nullness.qual.NonNull; @Getter -public class BukkitLightEcoPlugin extends AbstractLightEcoPlugin { - private final BukkitLightEcoBootstrap bootstrap; +public class PaperLightEcoPlugin extends AbstractLightEcoPlugin { + private final PaperLightEcoBootstrap bootstrap; @Getter private StandardUserManager userManager; @Getter private StandardCurrencyManager currencyManager; @Getter - private BukkitCommandManager commandManager; + private PaperCommandManager commandManager; @Getter private ContextManager contextManager; - public BukkitLightEcoPlugin(BukkitLightEcoBootstrap bootstrap) { + public PaperLightEcoPlugin(PaperLightEcoBootstrap bootstrap) { this.bootstrap = bootstrap; } @Override protected void registerListeners() { - this.bootstrap.getLoader().getServer().getPluginManager().registerEvents(new BukkitConnectionListener(this), this.bootstrap.getLoader()); + this.bootstrap.getLoader().getServer().getPluginManager().registerEvents(new PaperConnectionListener(this), this.bootstrap.getLoader()); + this.bootstrap.getLoader().getServer().getPluginManager().registerEvents(new PaperCommandSuggestionsListener(this), this.bootstrap.getLoader()); } @Override public void setupManagers() { this.userManager = new StandardUserManager(this); this.currencyManager = new StandardCurrencyManager(this); - this.commandManager = new BukkitCommandManager(this); - this.contextManager = new BukkitContextManager(); + this.commandManager = new PaperCommandManager(this); + this.contextManager = new PaperContextManager(); } @Override @@ -68,6 +70,6 @@ public class BukkitLightEcoPlugin extends AbstractLightEcoPlugin { @Override public Platform.@NonNull Type getPlatformType() { - return Platform.Type.BUKKIT; + return Platform.Type.PAPER; } } diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitSchedulerAdapter.java b/paper/src/main/java/dev/xhyrom/lighteco/paper/PaperSchedulerAdapter.java similarity index 87% rename from bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitSchedulerAdapter.java rename to paper/src/main/java/dev/xhyrom/lighteco/paper/PaperSchedulerAdapter.java index 0312ffd..f051ba1 100644 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitSchedulerAdapter.java +++ b/paper/src/main/java/dev/xhyrom/lighteco/paper/PaperSchedulerAdapter.java @@ -1,21 +1,20 @@ -package dev.xhyrom.lighteco.bukkit; +package dev.xhyrom.lighteco.paper; import dev.xhyrom.lighteco.common.plugin.scheduler.SchedulerAdapter; import dev.xhyrom.lighteco.common.plugin.scheduler.SchedulerTask; -import lombok.Getter; import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitTask; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; -public class BukkitSchedulerAdapter implements SchedulerAdapter { +public class PaperSchedulerAdapter implements SchedulerAdapter { private final Executor async; - private final BukkitLightEcoBootstrap bootstrap; + private final PaperLightEcoBootstrap bootstrap; private final BukkitScheduler scheduler; - public BukkitSchedulerAdapter(BukkitLightEcoBootstrap bootstrap) { + public PaperSchedulerAdapter(PaperLightEcoBootstrap bootstrap) { this.bootstrap = bootstrap; this.scheduler = bootstrap.getLoader().getServer().getScheduler(); diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/chat/BukkitCommandSender.java b/paper/src/main/java/dev/xhyrom/lighteco/paper/chat/PaperCommandSender.java similarity index 56% rename from bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/chat/BukkitCommandSender.java rename to paper/src/main/java/dev/xhyrom/lighteco/paper/chat/PaperCommandSender.java index 9bdce61..f732850 100644 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/chat/BukkitCommandSender.java +++ b/paper/src/main/java/dev/xhyrom/lighteco/paper/chat/PaperCommandSender.java @@ -1,21 +1,15 @@ -package dev.xhyrom.lighteco.bukkit.chat; +package dev.xhyrom.lighteco.paper.chat; import dev.xhyrom.lighteco.common.model.chat.AbstractCommandSender; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.text.Component; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.UUID; -public class BukkitCommandSender extends AbstractCommandSender { - private final Audience audience; - - public BukkitCommandSender(CommandSender sender, BukkitAudiences audienceFactory) { +public class PaperCommandSender extends AbstractCommandSender { + public PaperCommandSender(CommandSender sender) { super(sender); - - this.audience = audienceFactory.sender(sender); } @Override @@ -32,8 +26,13 @@ public class BukkitCommandSender extends AbstractCommandSender { return null; } + @Override + public boolean eligible(String permission) { + return this.delegate.hasPermission(permission); + } + @Override public void sendMessage(Component message) { - this.audience.sendMessage(message); + this.delegate.sendMessage(message); } } \ No newline at end of file diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/hooks/Hooks.java b/paper/src/main/java/dev/xhyrom/lighteco/paper/hooks/Hooks.java similarity index 77% rename from bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/hooks/Hooks.java rename to paper/src/main/java/dev/xhyrom/lighteco/paper/hooks/Hooks.java index a820a55..8597548 100644 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/hooks/Hooks.java +++ b/paper/src/main/java/dev/xhyrom/lighteco/paper/hooks/Hooks.java @@ -1,6 +1,6 @@ -package dev.xhyrom.lighteco.bukkit.hooks; +package dev.xhyrom.lighteco.paper.hooks; -import dev.xhyrom.lighteco.bukkit.BukkitLightEcoPlugin; +import dev.xhyrom.lighteco.paper.PaperLightEcoPlugin; import lombok.experimental.UtilityClass; import org.bukkit.Bukkit; @@ -8,7 +8,7 @@ import org.bukkit.Bukkit; public class Hooks { private static PlaceholderAPIExpansion placeholderAPIExpansion; - public static void register(BukkitLightEcoPlugin plugin) { + public static void register(PaperLightEcoPlugin plugin) { if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { placeholderAPIExpansion = new PlaceholderAPIExpansion(plugin); placeholderAPIExpansion.register(); diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/hooks/PlaceholderAPIExpansion.java b/paper/src/main/java/dev/xhyrom/lighteco/paper/hooks/PlaceholderAPIExpansion.java similarity index 91% rename from bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/hooks/PlaceholderAPIExpansion.java rename to paper/src/main/java/dev/xhyrom/lighteco/paper/hooks/PlaceholderAPIExpansion.java index b0bbb01..7604fca 100644 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/hooks/PlaceholderAPIExpansion.java +++ b/paper/src/main/java/dev/xhyrom/lighteco/paper/hooks/PlaceholderAPIExpansion.java @@ -1,6 +1,6 @@ -package dev.xhyrom.lighteco.bukkit.hooks; +package dev.xhyrom.lighteco.paper.hooks; -import dev.xhyrom.lighteco.bukkit.BukkitLightEcoPlugin; +import dev.xhyrom.lighteco.paper.PaperLightEcoPlugin; import dev.xhyrom.lighteco.common.model.currency.Currency; import dev.xhyrom.lighteco.common.model.user.User; import lombok.RequiredArgsConstructor; @@ -11,7 +11,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; @RequiredArgsConstructor public class PlaceholderAPIExpansion extends PlaceholderExpansion { - private final BukkitLightEcoPlugin plugin; + private final PaperLightEcoPlugin plugin; @Override public @NonNull String getIdentifier() { diff --git a/paper/src/main/java/dev/xhyrom/lighteco/paper/listeners/PaperCommandSuggestionsListener.java b/paper/src/main/java/dev/xhyrom/lighteco/paper/listeners/PaperCommandSuggestionsListener.java new file mode 100644 index 0000000..2cf8a1f --- /dev/null +++ b/paper/src/main/java/dev/xhyrom/lighteco/paper/listeners/PaperCommandSuggestionsListener.java @@ -0,0 +1,55 @@ +package dev.xhyrom.lighteco.paper.listeners; + +import com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent; +import com.mojang.brigadier.tree.CommandNode; +import com.mojang.brigadier.tree.LiteralCommandNode; +import dev.xhyrom.lighteco.paper.PaperLightEcoPlugin; +import dev.xhyrom.lighteco.paper.util.PaperBrigadier; +import dev.xhyrom.lighteco.paper.chat.PaperCommandSender; +import dev.xhyrom.lighteco.common.command.CommandSource; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +public class PaperCommandSuggestionsListener implements Listener { + private final PaperLightEcoPlugin plugin; + + public PaperCommandSuggestionsListener(PaperLightEcoPlugin plugin) { + this.plugin = plugin; + } + + @SuppressWarnings("deprecation") + @EventHandler + public void onPlayerSendCommandsEvent(AsyncPlayerSendCommandsEvent event) { + PaperCommandSender sender = new PaperCommandSender(event.getPlayer()); + CommandSource source = new CommandSource(this.plugin, sender); + if (event.isAsynchronous() || !event.hasFiredAsync()) { + for (CommandNode command : this.plugin.getCommandManager().getDispatcher().getRoot().getChildren()) { + PaperBrigadier.removeChild(event.getCommandNode(), command.getName()); + PaperBrigadier.removeChild(event.getCommandNode(), this.plugin.getBootstrap().getLoader().getName().toLowerCase() + ":" + command.getName()); + + if (!command.canUse(source)) continue; + + addChild(event, source, command, createClone(command)); + addChild(event, source, command, createClone(this.plugin.getBootstrap().getLoader().getName().toLowerCase() + ":" + command.getName(), command)); + } + } + } + + @SuppressWarnings({"rawtypes", "unchecked", "deprecation"}) + private void addChild(AsyncPlayerSendCommandsEvent event, CommandSource source, CommandNode command, CommandNode clone) { + for (CommandNode child : command.getChildren()) { + if (child.canUse(source)) + clone.addChild(child); + } + + event.getCommandNode().addChild((CommandNode) clone); + } + + private CommandNode createClone(CommandNode command) { + return createClone(command.getName(), command); + } + + private CommandNode createClone(String name, CommandNode command) { + return new LiteralCommandNode<>(name, command.getCommand(), command.getRequirement(), command.getRedirect(), command.getRedirectModifier(), command.isFork()); + } +} diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/listeners/BukkitConnectionListener.java b/paper/src/main/java/dev/xhyrom/lighteco/paper/listeners/PaperConnectionListener.java similarity index 89% rename from bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/listeners/BukkitConnectionListener.java rename to paper/src/main/java/dev/xhyrom/lighteco/paper/listeners/PaperConnectionListener.java index 2b79005..a8e511f 100644 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/listeners/BukkitConnectionListener.java +++ b/paper/src/main/java/dev/xhyrom/lighteco/paper/listeners/PaperConnectionListener.java @@ -1,6 +1,6 @@ -package dev.xhyrom.lighteco.bukkit.listeners; +package dev.xhyrom.lighteco.paper.listeners; -import dev.xhyrom.lighteco.bukkit.BukkitLightEcoPlugin; +import dev.xhyrom.lighteco.paper.PaperLightEcoPlugin; import dev.xhyrom.lighteco.common.model.currency.Currency; import dev.xhyrom.lighteco.common.model.user.User; import net.kyori.adventure.text.Component; @@ -14,11 +14,11 @@ import org.bukkit.event.player.PlayerQuitEvent; import java.util.UUID; -public class BukkitConnectionListener implements Listener { - private final BukkitLightEcoPlugin plugin; +public class PaperConnectionListener implements Listener { + private final PaperLightEcoPlugin plugin; private final MiniMessage miniMessage = MiniMessage.miniMessage(); - public BukkitConnectionListener(BukkitLightEcoPlugin plugin) { + public PaperConnectionListener(PaperLightEcoPlugin plugin) { this.plugin = plugin; } diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/logger/BukkitLogger.java b/paper/src/main/java/dev/xhyrom/lighteco/paper/logger/PaperLogger.java similarity index 72% rename from bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/logger/BukkitLogger.java rename to paper/src/main/java/dev/xhyrom/lighteco/paper/logger/PaperLogger.java index 7d4d6f7..a423c0b 100644 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/logger/BukkitLogger.java +++ b/paper/src/main/java/dev/xhyrom/lighteco/paper/logger/PaperLogger.java @@ -1,14 +1,17 @@ -package dev.xhyrom.lighteco.bukkit.logger; +package dev.xhyrom.lighteco.paper.logger; +import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin; import dev.xhyrom.lighteco.common.plugin.logger.PluginLogger; import java.util.logging.Level; import java.util.logging.Logger; -public class BukkitLogger implements PluginLogger { +public class PaperLogger implements PluginLogger { + private final LightEcoPlugin plugin; private final Logger logger; - public BukkitLogger(Logger logger) { + public PaperLogger(LightEcoPlugin plugin, Logger logger) { + this.plugin = plugin; this.logger = logger; } @@ -22,6 +25,20 @@ public class BukkitLogger implements PluginLogger { this.logger.info(String.format(message, args)); } + @Override + public void debug(String message) { + if (!this.plugin.getConfig().debug) return; + + info(message); + } + + @Override + public void debug(String message, Object... args) { + if (!this.plugin.getConfig().debug) return; + + info(message, args); + } + @Override public void warn(String message) { this.logger.log(Level.WARNING, message); diff --git a/paper/src/main/java/dev/xhyrom/lighteco/paper/manager/PaperCommandManager.java b/paper/src/main/java/dev/xhyrom/lighteco/paper/manager/PaperCommandManager.java new file mode 100644 index 0000000..abbfb30 --- /dev/null +++ b/paper/src/main/java/dev/xhyrom/lighteco/paper/manager/PaperCommandManager.java @@ -0,0 +1,64 @@ +package dev.xhyrom.lighteco.paper.manager; + +import com.mojang.brigadier.ParseResults; +import dev.xhyrom.lighteco.paper.chat.PaperCommandSender; +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 dev.xhyrom.lighteco.paper.util.PaperCommandMapUtil; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.TabCompleter; + +import java.util.ArrayList; +import java.util.List; + +public class PaperCommandManager extends CommandManager { + private final PaperCommandMapUtil commandMapUtil; + + public PaperCommandManager(LightEcoPlugin plugin) { + super(plugin); + + this.commandMapUtil = new PaperCommandMapUtil(plugin); + } + + @Override + protected void register(Command command) { + super.register(command); + + CommandExecutor executor = (sender, bukkitCommand, s, args) -> { + if (s.startsWith("lighteco:")) { + s = s.substring(9); + } + + execute(new PaperCommandSender(sender), s, args); + return true; + }; + + TabCompleter completer = (sender, bukkitCommand, s, args) -> { + final List suggestions = new ArrayList<>(); + final CommandSource source = new CommandSource(plugin, new PaperCommandSender(sender)); + + final ParseResults parseResults = getDispatcher().parse( + command.getName() + (args.length > 0 ? " " + String.join(" ", args) : ""), + source + ); + + getDispatcher().getCompletionSuggestions( + parseResults + ).join().getList().forEach(suggestion -> suggestions.add(suggestion.getText())); + + return suggestions; + }; + + List aliases = new ArrayList<>(command.getAliases()); + aliases.add(command.getName()); + + this.commandMapUtil.register( + executor, + completer, + aliases + ); + } +} diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/manager/BukkitContextManager.java b/paper/src/main/java/dev/xhyrom/lighteco/paper/manager/PaperContextManager.java similarity index 77% rename from bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/manager/BukkitContextManager.java rename to paper/src/main/java/dev/xhyrom/lighteco/paper/manager/PaperContextManager.java index 1ec1a53..b63e8f8 100644 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/manager/BukkitContextManager.java +++ b/paper/src/main/java/dev/xhyrom/lighteco/paper/manager/PaperContextManager.java @@ -1,4 +1,4 @@ -package dev.xhyrom.lighteco.bukkit.manager; +package dev.xhyrom.lighteco.paper.manager; import dev.xhyrom.lighteco.api.manager.ContextManager; import org.bukkit.entity.Player; @@ -6,7 +6,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import java.util.UUID; -public class BukkitContextManager implements ContextManager { +public class PaperContextManager implements ContextManager { @Override public @NonNull UUID getPlayerUniqueId(@NonNull Player player) { return player.getUniqueId(); diff --git a/paper/src/main/java/dev/xhyrom/lighteco/paper/util/PaperBrigadier.java b/paper/src/main/java/dev/xhyrom/lighteco/paper/util/PaperBrigadier.java new file mode 100644 index 0000000..ad4a7bc --- /dev/null +++ b/paper/src/main/java/dev/xhyrom/lighteco/paper/util/PaperBrigadier.java @@ -0,0 +1,41 @@ +package dev.xhyrom.lighteco.paper.util; + +import com.mojang.brigadier.tree.CommandNode; +import com.mojang.brigadier.tree.RootCommandNode; + +import java.lang.reflect.Field; +import java.util.Map; + +public class PaperBrigadier { + 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 children = (Map) field.get(root); + children.remove(name); + } + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } +} diff --git a/paper/src/main/java/dev/xhyrom/lighteco/paper/util/PaperCommandMapUtil.java b/paper/src/main/java/dev/xhyrom/lighteco/paper/util/PaperCommandMapUtil.java new file mode 100644 index 0000000..2e3b06c --- /dev/null +++ b/paper/src/main/java/dev/xhyrom/lighteco/paper/util/PaperCommandMapUtil.java @@ -0,0 +1,56 @@ +package dev.xhyrom.lighteco.paper.util; + +import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin; +import org.bukkit.command.*; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; + +import java.lang.reflect.Constructor; +import java.util.List; +import java.util.Map; + +public class PaperCommandMapUtil { + private static final Constructor COMMAND_CONSTRUCTOR; + + static { + try { + COMMAND_CONSTRUCTOR = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class); + COMMAND_CONSTRUCTOR.setAccessible(true); + } catch (NoSuchMethodException e) { + throw new ExceptionInInitializerError(e); + } + } + + private final LightEcoPlugin plugin; + public PaperCommandMapUtil(LightEcoPlugin plugin) { + this.plugin = plugin; + } + + public void register(CommandExecutor executor, TabCompleter completer, List aliases) { + Plugin bukkitPlugin = (JavaPlugin) this.plugin.getBootstrap().getLoader(); + CommandMap commandMap = bukkitPlugin.getServer().getCommandMap(); + Map knownCommands = commandMap.getKnownCommands(); + + for (String name : aliases) { + if (!name.toLowerCase().equals(name)) { + throw new IllegalArgumentException("Command aliases must be lowercase! (name: " + name + ")"); + } + + try { + PluginCommand command = COMMAND_CONSTRUCTOR.newInstance(name, bukkitPlugin); + + commandMap.register(bukkitPlugin.getName().toLowerCase(), command); + knownCommands.put(bukkitPlugin.getName().toLowerCase() + ":" + name.toLowerCase(), command); + knownCommands.put(name, command); + + command.setLabel(name); + command.setExecutor(executor); + command.setTabCompleter(completer); + + commandMap.register(bukkitPlugin.getName(), command); + } catch (ReflectiveOperationException e) { + this.plugin.getBootstrap().getLogger().error("Failed to register command: %s", e); + } + } + } +} diff --git a/bukkit/src/main/resources/plugin.yml b/paper/src/main/resources/plugin.yml similarity index 55% rename from bukkit/src/main/resources/plugin.yml rename to paper/src/main/resources/plugin.yml index 0d7f4be..6868c77 100644 --- a/bukkit/src/main/resources/plugin.yml +++ b/paper/src/main/resources/plugin.yml @@ -1,9 +1,9 @@ -name: ${name} +name: ${coreName} description: ${description} version: ${version} -main: dev.xhyrom.lighteco.bukkit.BukkitLightEcoLoader +main: dev.xhyrom.lighteco.paper.PaperLightEcoLoader author: ${author} -api-version: 1.16 +api-version: 1.17 load: STARTUP softdepend: diff --git a/settings.gradle.kts b/settings.gradle.kts index 854271b..1c0f551 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,15 +3,22 @@ rootProject.name = "lighteco-parent" sequenceOf( "api", "common", - "bukkit", - "bukkittest", + "paper", "sponge-8", - "currency-money" + "currency-money", + "test" ).forEach { include("lighteco-$it") project(":lighteco-$it").projectDir = file(it) } +sequenceOf( + "paper" +).forEach { + include("lighteco-test-$it") + project(":lighteco-test-$it").projectDir = file("test/$it") +} + pluginManagement { repositories { mavenLocal() diff --git a/sponge-8/src/main/java/dev/xhyrom/lighteco/sponge/SpongeLightEcoBootstrap.java b/sponge-8/src/main/java/dev/xhyrom/lighteco/sponge/SpongeLightEcoBootstrap.java index ab281f0..c1f736d 100644 --- a/sponge-8/src/main/java/dev/xhyrom/lighteco/sponge/SpongeLightEcoBootstrap.java +++ b/sponge-8/src/main/java/dev/xhyrom/lighteco/sponge/SpongeLightEcoBootstrap.java @@ -12,6 +12,7 @@ import org.spongepowered.plugin.builtin.jvm.Plugin; import java.io.InputStream; import java.nio.file.Path; import java.util.List; +import java.util.Optional; import java.util.UUID; @Plugin("lighteco-sponge") @@ -60,6 +61,16 @@ public class SpongeLightEcoBootstrap implements LightEcoBootstrap, LoaderBootstr return null; } + @Override + public String getVersion() { + return null; + } + + @Override + public Optional lookupUniqueId(String username) { + return Optional.empty(); + } + @Override public boolean isPlayerOnline(UUID uniqueId) { return false; diff --git a/sponge-8/src/main/java/dev/xhyrom/lighteco/sponge/SpongeLightEcoPlugin.java b/sponge-8/src/main/java/dev/xhyrom/lighteco/sponge/SpongeLightEcoPlugin.java index 89646bb..a80b1b6 100644 --- a/sponge-8/src/main/java/dev/xhyrom/lighteco/sponge/SpongeLightEcoPlugin.java +++ b/sponge-8/src/main/java/dev/xhyrom/lighteco/sponge/SpongeLightEcoPlugin.java @@ -3,7 +3,7 @@ package dev.xhyrom.lighteco.sponge; import dev.xhyrom.lighteco.api.LightEco; import dev.xhyrom.lighteco.api.manager.ContextManager; import dev.xhyrom.lighteco.api.platform.Platform; -import dev.xhyrom.lighteco.common.manager.command.CommandManager; +import dev.xhyrom.lighteco.common.command.CommandManager; import dev.xhyrom.lighteco.common.manager.currency.StandardCurrencyManager; import dev.xhyrom.lighteco.common.manager.user.StandardUserManager; import dev.xhyrom.lighteco.common.messaging.MessagingFactory; diff --git a/bukkittest/build.gradle.kts b/test/paper/build.gradle.kts similarity index 61% rename from bukkittest/build.gradle.kts rename to test/paper/build.gradle.kts index 545c292..fa27896 100644 --- a/bukkittest/build.gradle.kts +++ b/test/paper/build.gradle.kts @@ -6,8 +6,17 @@ plugins { } server { - version = "1.20.1" - type = "paper" + version = "1.20.6" + type = "purpur" + + // Minecraft 1.20.6 requires java 21 + java { + targetCompatibility = JavaVersion.VERSION_21 + sourceCompatibility = JavaVersion.VERSION_21 + toolchain { + languageVersion.set(JavaLanguageVersion.of(21)) + } + } } repositories { diff --git a/bukkittest/src/main/java/dev/xhyrom/lighteco/bukkittest/TestCurrency.java b/test/paper/src/main/java/dev/xhyrom/lighteco/test/paper/TestCurrency.java similarity index 92% rename from bukkittest/src/main/java/dev/xhyrom/lighteco/bukkittest/TestCurrency.java rename to test/paper/src/main/java/dev/xhyrom/lighteco/test/paper/TestCurrency.java index 4652c83..c5534af 100644 --- a/bukkittest/src/main/java/dev/xhyrom/lighteco/bukkittest/TestCurrency.java +++ b/test/paper/src/main/java/dev/xhyrom/lighteco/test/paper/TestCurrency.java @@ -1,4 +1,4 @@ -package dev.xhyrom.lighteco.bukkittest; +package dev.xhyrom.lighteco.test.paper; import dev.xhyrom.lighteco.api.model.currency.Currency; diff --git a/bukkittest/src/main/java/dev/xhyrom/lighteco/bukkittest/TestCurrency2.java b/test/paper/src/main/java/dev/xhyrom/lighteco/test/paper/TestCurrency2.java similarity index 92% rename from bukkittest/src/main/java/dev/xhyrom/lighteco/bukkittest/TestCurrency2.java rename to test/paper/src/main/java/dev/xhyrom/lighteco/test/paper/TestCurrency2.java index 63de38a..e501613 100644 --- a/bukkittest/src/main/java/dev/xhyrom/lighteco/bukkittest/TestCurrency2.java +++ b/test/paper/src/main/java/dev/xhyrom/lighteco/test/paper/TestCurrency2.java @@ -1,4 +1,4 @@ -package dev.xhyrom.lighteco.bukkittest; +package dev.xhyrom.lighteco.test.paper; import dev.xhyrom.lighteco.api.model.currency.Currency; import dev.xhyrom.lighteco.api.model.user.User; @@ -18,7 +18,7 @@ public class TestCurrency2 implements Currency { @Override public boolean isPayable() { - return true; + return false; } @Override diff --git a/bukkittest/src/main/java/dev/xhyrom/lighteco/bukkittest/TestPlugin.java b/test/paper/src/main/java/dev/xhyrom/lighteco/test/paper/TestPlugin.java similarity index 96% rename from bukkittest/src/main/java/dev/xhyrom/lighteco/bukkittest/TestPlugin.java rename to test/paper/src/main/java/dev/xhyrom/lighteco/test/paper/TestPlugin.java index 26170e1..2b28756 100644 --- a/bukkittest/src/main/java/dev/xhyrom/lighteco/bukkittest/TestPlugin.java +++ b/test/paper/src/main/java/dev/xhyrom/lighteco/test/paper/TestPlugin.java @@ -1,4 +1,4 @@ -package dev.xhyrom.lighteco.bukkittest; +package dev.xhyrom.lighteco.test.paper; import dev.xhyrom.lighteco.api.LightEco; import dev.xhyrom.lighteco.api.LightEcoProvider; diff --git a/bukkittest/src/main/resources/plugin.yml b/test/paper/src/main/resources/plugin.yml similarity index 64% rename from bukkittest/src/main/resources/plugin.yml rename to test/paper/src/main/resources/plugin.yml index 0fdea7e..31d3857 100644 --- a/bukkittest/src/main/resources/plugin.yml +++ b/test/paper/src/main/resources/plugin.yml @@ -1,10 +1,10 @@ name: ${name} description: ${description} version: ${version} -main: dev.xhyrom.lighteco.bukkittest.TestPlugin +main: dev.xhyrom.lighteco.test.paper.TestPlugin author: ${author} api-version: 1.20 softdepend: - Vault - - lighteco-bukkit \ No newline at end of file + - LightEco \ No newline at end of file