1
0
Fork 0
mirror of https://github.com/xHyroM/lighteco.git synced 2024-12-25 21:51:07 +01:00

feat: command manager

This commit is contained in:
Jozef Steinhübl 2023-08-26 16:45:04 +02:00
parent b9c7b9eb88
commit 4f988b53d2
17 changed files with 363 additions and 88 deletions

View file

@ -10,6 +10,7 @@ dependencies {
implementation(project(":lighteco-common"))
implementation("dev.jorel:commandapi-bukkit-shade:9.1.0")
implementation("net.kyori:adventure-platform-bukkit:4.2.0")
compileOnly("io.papermc.paper:paper-api:1.20.1-R0.1-SNAPSHOT")

View file

@ -0,0 +1,39 @@
package dev.xhyrom.lighteco.bukkit.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<CommandSender> {
private final Audience audience;
public BukkitCommandSender(CommandSender sender, BukkitAudiences audienceFactory) {
super(sender);
this.audience = audienceFactory.sender(sender);
}
@Override
public String getUsername() {
return this.delegate.getName();
}
@Override
public UUID getUniqueId() {
if (super.delegate instanceof Player) {
return ((Player) super.delegate).getUniqueId();
}
return null;
}
@Override
public void sendMessage(Component message) {
this.audience.sendMessage(message);
}
}

View file

@ -1,26 +1,165 @@
package dev.xhyrom.lighteco.bukkit.manager;
import dev.jorel.commandapi.CommandAPI;
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.common.manager.command.AbstractCommandManager;
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.platform.bukkit.BukkitAudiences;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.math.BigDecimal;
import java.util.List;
public class BukkitCommandManager extends AbstractCommandManager {
private final BukkitAudiences audienceFactory;
public BukkitCommandManager(LightEcoPlugin plugin) {
super(plugin);
this.audienceFactory = BukkitAudiences.create((JavaPlugin) this.plugin.getBootstrap().getLoader());
}
private List<CommandAPICommand> getBalanceCommands(String name, String permissionBase, Currency currency) {
return List.of(
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);
})
);
}
@Override
public void registerCurrencyCommand(@NonNull Currency currency) {
new CommandAPICommand(currency.getIdentifier())
.withPermission("lighteco.command.balance." + currency.getIdentifier())
.executesPlayer((sender, args) -> {
User user = this.plugin.getUserManager().getIfLoaded(sender.getUniqueId());
String permissionBase = "lighteco.currency." + currency.getIdentifier() + ".command.";
this.onBalance(user, currency);
})
// Balance
getBalanceCommands(currency.getIdentifier(), permissionBase, currency)
.forEach(CommandAPICommand::register);
List<CommandAPICommand> balanceCommands = getBalanceCommands("balance", permissionBase, currency);
new CommandAPICommand(currency.getIdentifier())
.withSubcommand(new CommandAPICommand("set")
.withPermission(permissionBase + "set")
.withArguments(
new OfflinePlayerArgument("target"),
currency.getProxy().getDecimalPlaces() > 0
? new DoubleArgument("amount", 0)
: new IntegerArgument("amount", 0)
)
.executes((sender, args) -> {
this.handleSet(sender, args, currency);
})
)
.withSubcommand(new CommandAPICommand("give")
.withPermission(permissionBase + "give")
.withArguments(
new OfflinePlayerArgument("target"),
currency.getProxy().getDecimalPlaces() > 0
? new DoubleArgument("amount", 1)
: new IntegerArgument("amount", 1)
)
.executes((sender, args) -> {
this.handleGive(sender, args, currency);
})
)
.withSubcommand(new CommandAPICommand("take")
.withPermission(permissionBase + "take")
.withArguments(
new OfflinePlayerArgument("target"),
currency.getProxy().getDecimalPlaces() > 0
? new DoubleArgument("amount", 1)
: new IntegerArgument("amount", 1)
)
.executes((sender, args) -> {
this.handleTake(sender, args, currency);
})
)
.withSubcommand(balanceCommands.get(0))
.withSubcommands(balanceCommands.get(1))
.register();
}
private void handleBalance(CommandSender originalSender, CommandArguments args, Currency currency) {
BukkitCommandSender sender = new BukkitCommandSender(originalSender, this.audienceFactory);
OfflinePlayer target = (OfflinePlayer) args.get("target");
if (target == null) {
this.onBalance(sender, currency);
return;
}
this.plugin.getUserManager().loadUser(target.getUniqueId())
.thenAcceptAsync(result -> {
String name = target.getName() != null ? target.getName() : args.getRaw("target");
result.setUsername(name);
this.onBalance(sender, currency, result);
});
}
private void handleSet(CommandSender originalSender, CommandArguments args, Currency currency) {
BukkitCommandSender sender = new BukkitCommandSender(originalSender, this.audienceFactory);
OfflinePlayer target = (OfflinePlayer) args.get("target");
BigDecimal amount = BigDecimal.valueOf(Double.parseDouble(args.getRaw("amount")));
if (!this.canUse(sender)) return;
this.plugin.getUserManager().loadUser(target.getUniqueId())
.thenAcceptAsync(result -> {
String name = target.getName() != null ? target.getName() : args.getRaw("target");
result.setUsername(name);
this.onSet(sender, currency, result, amount);
});
}
private void handleGive(CommandSender originalSender, CommandArguments args, Currency currency) {
BukkitCommandSender sender = new BukkitCommandSender(originalSender, this.audienceFactory);
OfflinePlayer target = (OfflinePlayer) args.get("target");
BigDecimal amount = BigDecimal.valueOf(Double.parseDouble(args.getRaw("amount")));
if (!this.canUse(sender)) return;
this.plugin.getUserManager().loadUser(target.getUniqueId())
.thenAcceptAsync(result -> {
String name = target.getName() != null ? target.getName() : args.getRaw("target");
result.setUsername(name);
this.onGive(sender, currency, result, amount);
});
}
public void handleTake(CommandSender originalSender, CommandArguments args, Currency currency) {
BukkitCommandSender sender = new BukkitCommandSender(originalSender, this.audienceFactory);
OfflinePlayer target = (OfflinePlayer) args.get("target");
BigDecimal amount = BigDecimal.valueOf(Double.parseDouble(args.getRaw("amount")));
if (!this.canUse(sender)) return;
this.plugin.getUserManager().loadUser(target.getUniqueId())
.thenAcceptAsync(result -> {
String name = target.getName() != null ? target.getName() : args.getRaw("target");
result.setUsername(name);
this.onTake(sender, currency, result, amount);
});
}
}

View file

@ -15,11 +15,9 @@ import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.ParseException;
public class TestPlugin extends JavaPlugin implements Listener {
public class TestPlugin extends JavaPlugin {
@Override
public void onEnable() {
getServer().getPluginManager().registerEvents(this, this);
getLogger().info("TestPlugin loaded!");
LightEco provider = LightEcoProvider.get();
@ -36,40 +34,4 @@ public class TestPlugin extends JavaPlugin implements Listener {
provider.getCommandManager().registerCurrencyCommand(currencyManager.getCurrency("test"));
}
@EventHandler
public void onWalk(AsyncPlayerChatEvent event) throws ParseException {
Player player = event.getPlayer();
LightEco provider = LightEcoProvider.get();
CurrencyManager currencyManager = provider.getCurrencyManager();
User user = provider.getPlayerAdapter(Player.class).getUser(player);
String message = event.getMessage();
String command = message.split(" ")[0];
String[] args = message.substring(command.length()).trim().split(" ");
Currency currency = currencyManager.getCurrency(args[0]);
switch (command) {
case "balance" -> player.sendMessage(user.getBalance(currency).toString());
case "add" -> {
if (currency.getDecimalPlaces() > 0) {
DecimalFormat decimalFormat = new DecimalFormat("#0.00");
user.setBalance(currency, BigDecimal.valueOf(
Double.parseDouble(
decimalFormat.format(
Double.parseDouble(args[1])
)
)
));
} else {
user.setBalance(currency, BigDecimal.valueOf(Integer.parseInt(args[1])));
}
provider.getUserManager().saveUser(user).thenAccept(aVoid -> player.sendMessage("Saved!"));
}
}
}
}

View file

@ -4,6 +4,12 @@ plugins {
dependencies {
api(project(":lighteco-api"))
api("net.kyori:adventure-api:4.12.0") {
exclude(module = "adventure-bom")
exclude(module = "checker-qual")
exclude(module = "annotations")
}
api("net.kyori:adventure-text-minimessage:4.14.0")
implementation("eu.okaeri:okaeri-configs-yaml-snakeyaml:5.0.0-beta.5")
implementation("eu.okaeri:okaeri-configs-validator-okaeri:5.0.0-beta.5")

View file

@ -3,6 +3,7 @@ package dev.xhyrom.lighteco.common.api.impl;
import dev.xhyrom.lighteco.api.model.currency.Currency;
import dev.xhyrom.lighteco.api.model.user.User;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.math.BigDecimal;
import java.util.UUID;
@ -20,12 +21,12 @@ public class ApiUser implements User {
}
@Override
public @NonNull String getUsername() {
return null;
public @Nullable String getUsername() {
return this.handler.getUsername();
}
@Override
public BigDecimal getBalance(@NonNull Currency currency) {
public @NonNull BigDecimal getBalance(@NonNull Currency currency) {
dev.xhyrom.lighteco.common.model.currency.Currency internal = this.handler.getPlugin()
.getCurrencyManager()
.getIfLoaded(currency.getIdentifier());

View file

@ -20,7 +20,8 @@ public class ApiUserManager extends ApiAbstractManager<dev.xhyrom.lighteco.commo
@Override
public @NonNull CompletableFuture<User> loadUser(@NonNull UUID uniqueId) {
return this.plugin.getStorage().loadUser(uniqueId);
return this.plugin.getStorage().loadUser(uniqueId)
.thenApply(ApiUserManager::wrap);
}
@Override

View file

@ -1,24 +0,0 @@
package dev.xhyrom.lighteco.common.cache;
import java.util.HashMap;
import java.util.Map;
public class TypedMap<T> {
private final Map<T, Object> map = new HashMap<>();
public <V> V get(T key) {
return (V) map.get(key);
}
public <V> V getOrDefault(T key, V defaultValue) {
return (V) map.getOrDefault(key, defaultValue);
}
public <V> void put(T key, V value) {
map.put(key, value);
}
public void clear() {
map.clear();
}
}

View file

@ -1,23 +1,113 @@
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 dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
import net.kyori.adventure.text.minimessage.MiniMessage;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.UUID;
public abstract class AbstractCommandManager implements CommandManager {
protected final LightEcoPlugin plugin;
private final MiniMessage miniMessage = MiniMessage.miniMessage();
private final ArrayList<UUID> mustWait = new ArrayList<>();
public AbstractCommandManager(LightEcoPlugin plugin) {
this.plugin = plugin;
}
@Override
public void onBalance(User sender, Currency currency) {
BigDecimal balance = sender.getBalance(currency);
public boolean canUse(CommandSender sender) {
// Console doesn't need to wait
if (sender.getUniqueId() == null) return true;
System.out.println("Your balance: " + balance.toPlainString() + " " + currency.getIdentifier());
//sender.sendMessage("&aYour balance: &e" + balance.toPlainString() + " &a" + currency.getIdentifier() + "&r");
if (mustWait.contains(sender.getUniqueId())) {
sender.sendMessage(
miniMessage.deserialize("<red>Please wait a moment before using this command again.")
);
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);
}
}
@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("<yellow>Your balance: <gold>" + balance.toPlainString() + " <yellow>" + currency.getIdentifier())
);
}
@Override
public void onBalance(CommandSender sender, Currency currency, User target) {
BigDecimal balance = target.getBalance(currency);
sender.sendMessage(
miniMessage.deserialize("<yellow>" + target.getUsername() + "'s balance: <gold>" + balance.toPlainString() + " <yellow>" + currency.getIdentifier())
);
}
@Override
public void onSet(CommandSender sender, Currency currency, User target, BigDecimal amount) {
addToMustWait(sender.getUniqueId(), target.getUniqueId());
target.setBalance(currency, amount);
sender.sendMessage(
miniMessage.deserialize("<yellow>Set " + target.getUsername() + "'s balance to <gold>" + amount.toPlainString() + " <yellow>" + currency.getIdentifier())
);
this.plugin.getUserManager().saveUser(target)
.thenAccept(v -> removeFromMustWait(target.getUniqueId(), sender.getUniqueId()));
}
@Override
public void onGive(CommandSender sender, Currency currency, User target, BigDecimal amount) {
addToMustWait(sender.getUniqueId(), target.getUniqueId());
target.setBalance(currency, target.getBalance(currency).add(amount));
sender.sendMessage(
miniMessage.deserialize("<yellow>Gave " + target.getUsername() + " <gold>" + amount.toPlainString() + " <yellow>" + currency.getIdentifier())
);
this.plugin.getUserManager().saveUser(target)
.thenAccept(v -> removeFromMustWait(target.getUniqueId(), sender.getUniqueId()));
}
@Override
public void onTake(CommandSender sender, Currency currency, User target, BigDecimal amount) {
addToMustWait(sender.getUniqueId(), target.getUniqueId());
target.setBalance(currency, target.getBalance(currency).subtract(amount));
sender.sendMessage(
miniMessage.deserialize("<yellow>Took <gold>" + amount.toPlainString() + " <yellow>" + currency.getIdentifier() + " from " + target.getUsername())
);
this.plugin.getUserManager().saveUser(target)
.thenAccept(v -> removeFromMustWait(target.getUniqueId(), sender.getUniqueId()));
}
}

View file

@ -1,11 +1,21 @@
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 onBalance(User sender, Currency currency);
boolean canUse(CommandSender sender);
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);
}

View file

@ -21,6 +21,11 @@ public class StandardUserManager extends AbstractManager<UUID, User> implements
return new User(this.plugin, uniqueId);
}
@Override
public CompletableFuture<User> loadUser(UUID uniqueId) {
return this.plugin.getStorage().loadUser(uniqueId);
}
@Override
public CompletableFuture<Void> load() {
Set<UUID> uniqueIds = new HashSet<>(keys());
@ -31,6 +36,11 @@ public class StandardUserManager extends AbstractManager<UUID, User> implements
.collect(CompletableFuture::allOf, (future, userFuture) -> future.join(), (future, userFuture) -> future.join());
}
@Override
public CompletableFuture<Void> saveUser(User user) {
return this.plugin.getStorage().saveUser(user.getProxy());
}
@Override
public void invalidateCaches() {
values().forEach(User::invalidateCaches);

View file

@ -7,7 +7,10 @@ import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public interface UserManager extends Manager<UUID, User> {
CompletableFuture<Void> saveUser(User user);
CompletableFuture<Void> load();
CompletableFuture<User> loadUser(UUID uniqueId);
void invalidateCaches();
}

View file

@ -0,0 +1,9 @@
package dev.xhyrom.lighteco.common.model.chat;
public abstract class AbstractCommandSender<T> implements CommandSender {
protected final T delegate;
public AbstractCommandSender(T delegate) {
this.delegate = delegate;
}
}

View file

@ -0,0 +1,12 @@
package dev.xhyrom.lighteco.common.model.chat;
import net.kyori.adventure.text.Component;
import java.util.UUID;
public interface CommandSender {
String getUsername();
UUID getUniqueId();
void sendMessage(Component message);
}

View file

@ -1,12 +1,14 @@
package dev.xhyrom.lighteco.common.model.user;
import dev.xhyrom.lighteco.common.api.impl.ApiUser;
import dev.xhyrom.lighteco.common.cache.TypedMap;
import dev.xhyrom.lighteco.common.model.currency.Currency;
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
import lombok.Getter;
import lombok.Setter;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.UUID;
@Getter
@ -17,18 +19,26 @@ public class User {
@Getter
private final UUID uniqueId;
private final TypedMap<Currency> balances = new TypedMap<>();
@Getter
@Setter
private String username;
private final HashMap<Currency, BigDecimal> balances = new HashMap<>();
public User(LightEcoPlugin plugin, UUID uniqueId) {
this(plugin, uniqueId, null);
}
public User(LightEcoPlugin plugin, UUID uniqueId, String username) {
this.plugin = plugin;
this.uniqueId = uniqueId;
this.username = username;
}
public <T> T getBalance(@NonNull Currency currency) {
return balances.<T>getOrDefault(currency, (T) currency.getDefaultBalance());
public BigDecimal getBalance(@NonNull Currency currency) {
return balances.getOrDefault(currency, currency.getDefaultBalance());
}
public <T> void setBalance(@NonNull Currency currency, @NonNull T balance) {
public void setBalance(@NonNull Currency currency, @NonNull BigDecimal balance) {
balances.put(currency, balance);
}

View file

@ -1,6 +1,6 @@
package dev.xhyrom.lighteco.common.storage;
import dev.xhyrom.lighteco.api.model.user.User;
import dev.xhyrom.lighteco.common.model.user.User;
import dev.xhyrom.lighteco.api.storage.StorageProvider;
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
@ -37,10 +37,16 @@ public class Storage {
}
public CompletableFuture<User> loadUser(UUID uniqueId) {
return future(() -> this.provider.loadUser(uniqueId));
User user = this.plugin.getUserManager().getIfLoaded(uniqueId);
if (user != null) {
return CompletableFuture.completedFuture(user);
}
return future(() -> this.provider.loadUser(uniqueId))
.thenApply(apiUser -> this.plugin.getUserManager().getIfLoaded(apiUser.getUniqueId()));
}
public CompletableFuture<Void> saveUser(User user) {
public CompletableFuture<Void> saveUser(dev.xhyrom.lighteco.api.model.user.User user) {
return future(() -> this.provider.saveUser(user));
}
}

View file

@ -43,7 +43,7 @@ public class MemoryStorageProvider implements StorageProvider {
private void simulateSlowDatabaseQuery() {
try {
Thread.sleep(500);
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}