mirror of
https://github.com/xHyroM/lighteco.git
synced 2024-11-23 23:31:05 +01:00
feat: pool settings
This commit is contained in:
parent
c52e9da63d
commit
2cfba60fbe
30 changed files with 424 additions and 139 deletions
|
@ -16,10 +16,33 @@ public interface LightEco {
|
|||
*/
|
||||
@NonNull Platform getPlatform();
|
||||
|
||||
/**
|
||||
* Gets the {@link UserManager}, which manages the users.
|
||||
*
|
||||
* @return the user manager
|
||||
*/
|
||||
@NonNull UserManager getUserManager();
|
||||
|
||||
/**
|
||||
* Gets the {@link CurrencyManager}, which manages the currencies.
|
||||
*
|
||||
* @return the currency manager
|
||||
*/
|
||||
@NonNull CurrencyManager getCurrencyManager();
|
||||
|
||||
/**
|
||||
* Gets the {@link CommandManager}, which manages the commands.
|
||||
*
|
||||
* @return the command manager
|
||||
*/
|
||||
@NonNull CommandManager getCommandManager();
|
||||
|
||||
/**
|
||||
* Gets the {@link PlayerAdapter} for a player class.
|
||||
*
|
||||
* @param playerClass the player class
|
||||
* @return the player adapter
|
||||
* @param <T> the player class
|
||||
*/
|
||||
<T> @NonNull PlayerAdapter<T> getPlayerAdapter(@NonNull Class<T> playerClass);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ public final class LightEcoProvider {
|
|||
LightEco instance = LightEcoProvider.instance;
|
||||
if (instance == null) {
|
||||
throw new NotLoadedException();
|
||||
};
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ public final class LightEcoProvider {
|
|||
public static void set(LightEco instance) {
|
||||
if (LightEcoProvider.instance != null) {
|
||||
throw new IllegalStateException("LightEco is already loaded!");
|
||||
};
|
||||
}
|
||||
|
||||
LightEcoProvider.instance = instance;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,23 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||
|
||||
public interface CommandManager {
|
||||
// Make more transparent and freedom way to do this (more abstract)
|
||||
|
||||
/**
|
||||
* Registers commands for a currency.
|
||||
*
|
||||
* @param currency the currency to register the command for
|
||||
*/
|
||||
void registerCurrencyCommand(@NonNull Currency currency);
|
||||
|
||||
/**
|
||||
* Registers commands for a currency.
|
||||
* <p>
|
||||
* If main is true, the pay and balance commands will be exposed as main commands.
|
||||
* You can also use {@link #registerCurrencyCommand(Currency)} to register the commands as subcommands.
|
||||
* </p>
|
||||
*
|
||||
* @param currency the currency to register the command for
|
||||
* @param main if pay and balance should be exposed as main commands
|
||||
*/
|
||||
void registerCurrencyCommand(@NonNull Currency currency, boolean main);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,18 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||
import java.util.UUID;
|
||||
|
||||
public interface ContextManager<T> {
|
||||
/**
|
||||
* Gets the unique id of a player.
|
||||
*
|
||||
* @param context the context to get the unique id of
|
||||
* @return the unique id of the player
|
||||
*/
|
||||
@NonNull UUID getPlayerUniqueId(@NonNull T context);
|
||||
|
||||
/**
|
||||
* Gets the player class of the platform.
|
||||
*
|
||||
* @return the player class
|
||||
*/
|
||||
@NonNull Class<?> getPlayerClass();
|
||||
}
|
||||
|
|
|
@ -3,16 +3,42 @@ package dev.xhyrom.lighteco.api.manager;
|
|||
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.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface CurrencyManager {
|
||||
/**
|
||||
* Gets all registered currencies.
|
||||
*
|
||||
* @return a collection of all registered currencies
|
||||
*/
|
||||
@NonNull Collection<Currency> getRegisteredCurrencies();
|
||||
|
||||
Currency getCurrency(@NonNull String identifier);
|
||||
/**
|
||||
* Gets a currency by its identifier.
|
||||
*
|
||||
* @param identifier the identifier of the currency
|
||||
* @return the currency, or null if not found
|
||||
*/
|
||||
@Nullable Currency getCurrency(@NonNull String identifier);
|
||||
|
||||
/**
|
||||
* Registers a currency.
|
||||
*
|
||||
* @param currency the currency to register
|
||||
*/
|
||||
void registerCurrency(@NonNull Currency currency);
|
||||
|
||||
List<User> getTopUsers(@NonNull Currency currency, int length);
|
||||
/**
|
||||
* Gets the top users for a currency.
|
||||
*
|
||||
* @implNote This method is not cached. It fetches the data from the database every time it is called.
|
||||
* @param currency the currency to get the top users for
|
||||
* @param length the length of the list
|
||||
* @return a future that completes with the top users (sorted from highest to lowest balance)
|
||||
*/
|
||||
CompletableFuture<List<User>> getTopUsers(@NonNull Currency currency, int length);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,20 @@ public interface UserManager {
|
|||
|
||||
@NonNull CompletableFuture<Void> saveUser(@NonNull User user);
|
||||
|
||||
/**
|
||||
* Saves multiple users at once.
|
||||
* <p>
|
||||
* Uses TRANSACTION clause under the hood.
|
||||
* If one of the users fails to save, the entire transaction will be rolled back.
|
||||
* This is to ensure data integrity.
|
||||
* If you want to save users individually, use {@link #saveUser(User)} instead.
|
||||
* </p>
|
||||
*
|
||||
* @param users the users to save
|
||||
* @return a future that completes when the users have been saved
|
||||
*/
|
||||
@NonNull CompletableFuture<Void> saveUsers(@NonNull User... users);
|
||||
|
||||
@Nullable User getUser(@NonNull UUID uniqueId);
|
||||
|
||||
boolean isLoaded(@NonNull UUID uniqueId);
|
||||
|
|
|
@ -3,32 +3,57 @@ package dev.xhyrom.lighteco.api.model.currency;
|
|||
import dev.xhyrom.lighteco.api.model.user.User;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.NumberFormat;
|
||||
|
||||
public interface Currency {
|
||||
String getIdentifier();
|
||||
/**
|
||||
* Get the type of the currency, either {@link Type#LOCAL} or {@link Type#GLOBAL}
|
||||
* Returns the identifier of the currency.
|
||||
*
|
||||
* @return the identifier
|
||||
*/
|
||||
String getIdentifier();
|
||||
|
||||
/**
|
||||
* Returns the type of the currency, either {@link Type#LOCAL} or {@link Type#GLOBAL}
|
||||
*
|
||||
* @see Type
|
||||
* @return The type of the currency
|
||||
*/
|
||||
Type getType();
|
||||
|
||||
/**
|
||||
* Format the given amount to a string
|
||||
*
|
||||
* @param amount The amount to format
|
||||
* @return The formatted amount
|
||||
*/
|
||||
default String format(BigDecimal amount) {
|
||||
NumberFormat format = NumberFormat.getInstance();
|
||||
format.setMaximumFractionDigits(fractionalDigits());
|
||||
|
||||
return format.format(amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this currency is payable
|
||||
*
|
||||
* @return `true` if this currency is payable, `false` otherwise
|
||||
*/
|
||||
boolean isPayable();
|
||||
|
||||
/**
|
||||
* Get the number of fractional digits this currency has
|
||||
* Returns the number of fractional digits this currency has
|
||||
*
|
||||
* @return The number of fractional digits
|
||||
*/
|
||||
default int fractionalDigits() {
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the users that have a balance in this currency
|
||||
* Returns the default balance for this currency
|
||||
*
|
||||
* @return The users
|
||||
* @return The default balance
|
||||
*/
|
||||
BigDecimal getDefaultBalance();
|
||||
|
||||
|
@ -46,7 +71,7 @@ public interface Currency {
|
|||
/**
|
||||
* Represents the type of currency
|
||||
*/
|
||||
public enum Type {
|
||||
enum Type {
|
||||
/**
|
||||
* A currency that is only available on a single server
|
||||
*/
|
||||
|
|
|
@ -32,6 +32,10 @@ public interface User {
|
|||
|
||||
/**
|
||||
* Set the balance of this user for the specified currency.
|
||||
* <p>
|
||||
* Save the user after setting the balance using {@link dev.xhyrom.lighteco.api.manager.UserManager#saveUser(User)}. <br/>
|
||||
* If you're doing multiple changes, use {@link dev.xhyrom.lighteco.api.manager.UserManager#saveUsers(User...)}
|
||||
* </p>
|
||||
*
|
||||
* @param currency the currency
|
||||
* @param balance the balance
|
||||
|
|
|
@ -3,6 +3,11 @@ package dev.xhyrom.lighteco.api.platform;
|
|||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
public interface Platform {
|
||||
/**
|
||||
* Get the type of this platform.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@NonNull Type getType();
|
||||
|
||||
enum Type {
|
||||
|
|
|
@ -6,7 +6,19 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface PlayerAdapter<T> {
|
||||
/**
|
||||
* Gets the user of a player.
|
||||
*
|
||||
* @param player the player to get the user of
|
||||
* @return the user
|
||||
*/
|
||||
@NonNull User getUser(@NonNull T player);
|
||||
|
||||
/**
|
||||
* Loads the user of a player.
|
||||
*
|
||||
* @param player the player to load the user of
|
||||
* @return a future that completes with the user
|
||||
*/
|
||||
@NonNull CompletableFuture<User> loadUser(@NonNull T player);
|
||||
}
|
||||
|
|
|
@ -1,15 +1,31 @@
|
|||
package dev.xhyrom.lighteco.api.storage;
|
||||
|
||||
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.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface StorageProvider {
|
||||
/**
|
||||
* Initialize the storage provider.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
void init() throws Exception;
|
||||
|
||||
/**
|
||||
* Shutdown the storage provider.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
void shutdown() throws Exception;
|
||||
|
||||
@NonNull User loadUser(@NonNull UUID uniqueId, @Nullable String username) throws Exception;
|
||||
void saveUser(@NonNull User user) throws Exception;
|
||||
void saveUsers(@NonNull User... users) throws Exception;
|
||||
|
||||
@NonNull List<User> getTopUsers(Currency currency, int length) throws Exception;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ public class TestCurrency2 implements Currency {
|
|||
|
||||
@Override
|
||||
public boolean isPayable() {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -3,9 +3,17 @@ package dev.xhyrom.lighteco.bukkittest;
|
|||
import dev.xhyrom.lighteco.api.LightEco;
|
||||
import dev.xhyrom.lighteco.api.LightEcoProvider;
|
||||
import dev.xhyrom.lighteco.api.manager.CurrencyManager;
|
||||
import dev.xhyrom.lighteco.api.model.user.User;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
import org.bukkit.event.player.PlayerChatEvent;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class TestPlugin extends JavaPlugin {
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class TestPlugin extends JavaPlugin implements Listener {
|
||||
@Override
|
||||
public void onEnable() {
|
||||
getLogger().info("TestPlugin loaded!");
|
||||
|
@ -15,6 +23,7 @@ public class TestPlugin extends JavaPlugin {
|
|||
|
||||
currencyManager.registerCurrency(new TestCurrency());
|
||||
currencyManager.registerCurrency(new TestCurrency2());
|
||||
getServer().getPluginManager().registerEvents(this, this);
|
||||
|
||||
getLogger().info("TestCurrency registered!");
|
||||
|
||||
|
@ -23,4 +32,15 @@ public class TestPlugin extends JavaPlugin {
|
|||
provider.getCommandManager().registerCurrencyCommand(currencyManager.getCurrency("test"));
|
||||
provider.getCommandManager().registerCurrencyCommand(currencyManager.getCurrency("test2"));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onChat(AsyncPlayerChatEvent event) {
|
||||
LightEco provider = LightEcoProvider.get();
|
||||
CurrencyManager currencyManager = provider.getCurrencyManager();
|
||||
CompletableFuture<List<User>> topusers = currencyManager.getTopUsers(currencyManager.getCurrency("money"), 5);
|
||||
|
||||
for (User user : topusers.join()) {
|
||||
event.getPlayer().sendMessage(user.getUniqueId() + " ("+ user.getUsername() +") " + ": " + user.getBalance(currencyManager.getCurrency("money")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class ApiCurrencyManager extends ApiAbstractManager<dev.xhyrom.lighteco.common.manager.currency.CurrencyManager> implements CurrencyManager {
|
||||
public ApiCurrencyManager(LightEcoPlugin plugin, dev.xhyrom.lighteco.common.manager.currency.CurrencyManager handler) {
|
||||
|
@ -38,10 +38,8 @@ public class ApiCurrencyManager extends ApiAbstractManager<dev.xhyrom.lighteco.c
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<User> getTopUsers(@NonNull Currency currency, int length) {
|
||||
public CompletableFuture<List<User>> getTopUsers(@NonNull Currency currency, int length) {
|
||||
dev.xhyrom.lighteco.common.model.currency.Currency internal = this.handler.getIfLoaded(currency.getIdentifier());
|
||||
return this.handler.getTopUsers(internal, length)
|
||||
.stream().map(dev.xhyrom.lighteco.common.model.user.User::getProxy)
|
||||
.collect(Collectors.toList());
|
||||
return this.handler.getTopUsers(internal, length);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import dev.xhyrom.lighteco.api.model.user.User;
|
|||
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
@ -34,6 +35,11 @@ public class ApiUserManager extends ApiAbstractManager<dev.xhyrom.lighteco.commo
|
|||
return this.plugin.getStorage().saveUser(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull CompletableFuture<Void> saveUsers(@NotNull @NonNull User... users) {
|
||||
return this.plugin.getStorage().saveUsers(users);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable User getUser(@NonNull UUID uniqueId) {
|
||||
return wrap(this.handler.getIfLoaded(uniqueId));
|
||||
|
|
|
@ -12,13 +12,10 @@ public class CurrencyMessageConfig extends OkaeriConfig {
|
|||
public String give = "<currency> <dark_gray>| <gray>Gave <gold><target> <gold><amount> <dark_gray>| <gold><balance>";
|
||||
public String take = "<currency> <dark_gray>| <gray>Took <gold><amount> <yellow>from <gold><target>";
|
||||
|
||||
public String pay = "<currency> <dark_gray>| <gray>Paid <gold><amount> <yellow>to <gold><target> <dark_gray>(<gold><taxed_amount> <yellow>after tax)</gray>";
|
||||
public String pay = "<currency> <dark_gray>| <gray>Paid <gold><amount> <yellow>to <gold><target>";
|
||||
public String payWithTax = "<currency> <dark_gray>| <gray>Paid <gold><amount> <yellow>to <gold><target> <dark_gray>(<gold><taxed_amount> <yellow>after tax<dark_gray>)";
|
||||
|
||||
public String wait = "<red>Please wait a moment before using this command again.";
|
||||
public String notEnoughMoney = "<red>You don't have enough money!";
|
||||
public String cannotSetNegative = "<red>Cannot set negative money!";
|
||||
public String cannotGiveNegative = "<red>Cannot give negative money!";
|
||||
public String cannotTakeNegative = "<red>Cannot take negative money!";
|
||||
public String cannotPayNegative = "<red>Cannot pay negative money!";
|
||||
public String cannotPaySelf = "<red>You cannot pay yourself!";
|
||||
}
|
||||
|
|
|
@ -13,4 +13,19 @@ public class StorageDataConfig extends OkaeriConfig {
|
|||
@Comment("Credentials for connecting to the database.")
|
||||
public String username = "root";
|
||||
public String password = "password";
|
||||
|
||||
@Comment("Maximum number of connections in the pool.")
|
||||
public int maximumPoolSize = 10;
|
||||
|
||||
@Comment("Minimum idle connections in the pool.")
|
||||
public int minimumIdle = 5;
|
||||
|
||||
@Comment("Maximum lifetime of a connection in the pool.")
|
||||
public long maxLifetime = 1800000;
|
||||
|
||||
@Comment("Keep alive interval in milliseconds.")
|
||||
public long keepAliveTime = 0;
|
||||
|
||||
@Comment("Connection timeout in milliseconds.")
|
||||
public long connectionTimeout = 5000;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package dev.xhyrom.lighteco.common.manager;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public abstract class ConcurrentManager<I, T> implements Manager<I, T> {
|
||||
public final Map<I, T> map = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public Collection<I> keys() {
|
||||
return this.map.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<T> values() {
|
||||
return this.map.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getOrMake(I identifier) {
|
||||
return this.map.computeIfAbsent(identifier, this::apply);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getIfLoaded(I identifier) {
|
||||
return this.map.get(identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoaded(I identifier) {
|
||||
return this.map.containsKey(identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload(I identifier) {
|
||||
this.map.remove(identifier);
|
||||
}
|
||||
}
|
|
@ -15,6 +15,4 @@ public interface Manager<I, T> {
|
|||
boolean isLoaded(I identifier);
|
||||
|
||||
void unload(I identifier);
|
||||
|
||||
void unload(Collection<I> identifiers);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import java.util.Collection;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class AbstractManager<I, T> implements Manager<I, T> {
|
||||
public abstract class SingleManager<I, T> implements Manager<I, T> {
|
||||
public final Map<I, T> map = new HashMap<>();
|
||||
|
||||
@Override
|
||||
|
@ -36,9 +36,4 @@ public abstract class AbstractManager<I, T> implements Manager<I, T> {
|
|||
public void unload(I identifier) {
|
||||
this.map.remove(identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload(Collection<I> identifiers) {
|
||||
identifiers.forEach(this::unload);
|
||||
}
|
||||
}
|
|
@ -13,7 +13,6 @@ import java.math.RoundingMode;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public abstract class AbstractCommandManager implements CommandManager {
|
||||
public final LightEcoPlugin plugin;
|
||||
|
@ -102,16 +101,7 @@ public abstract class AbstractCommandManager implements CommandManager {
|
|||
addToMustWait(sender.getUniqueId(), target.getUniqueId());
|
||||
amount = amount.setScale(currency.getProxy().fractionalDigits(), RoundingMode.DOWN);
|
||||
|
||||
try {
|
||||
target.setBalance(currency, amount);
|
||||
} catch (IllegalArgumentException e) {
|
||||
sender.sendMessage(
|
||||
miniMessage.deserialize(this.getConfig(currency).cannotSetNegative)
|
||||
);
|
||||
|
||||
removeFromMustWait(target.getUniqueId(), sender.getUniqueId());
|
||||
return;
|
||||
}
|
||||
target.setBalance(currency, amount);
|
||||
|
||||
sender.sendMessage(
|
||||
miniMessage.deserialize(
|
||||
|
@ -131,16 +121,7 @@ public abstract class AbstractCommandManager implements CommandManager {
|
|||
addToMustWait(sender.getUniqueId(), target.getUniqueId());
|
||||
amount = amount.setScale(currency.getProxy().fractionalDigits(), RoundingMode.DOWN);
|
||||
|
||||
try {
|
||||
target.deposit(currency, amount);
|
||||
} catch (IllegalArgumentException e) {
|
||||
sender.sendMessage(
|
||||
miniMessage.deserialize(this.getConfig(currency).cannotGiveNegative)
|
||||
);
|
||||
|
||||
removeFromMustWait(target.getUniqueId(), sender.getUniqueId());
|
||||
return;
|
||||
}
|
||||
target.deposit(currency, amount);
|
||||
|
||||
sender.sendMessage(
|
||||
miniMessage.deserialize(
|
||||
|
@ -161,16 +142,7 @@ public abstract class AbstractCommandManager implements CommandManager {
|
|||
addToMustWait(sender.getUniqueId(), target.getUniqueId());
|
||||
amount = amount.setScale(currency.getProxy().fractionalDigits(), RoundingMode.DOWN);
|
||||
|
||||
try {
|
||||
target.withdraw(currency, amount);
|
||||
} catch (IllegalArgumentException e) {
|
||||
sender.sendMessage(
|
||||
miniMessage.deserialize(this.getConfig(currency).cannotTakeNegative)
|
||||
);
|
||||
|
||||
removeFromMustWait(target.getUniqueId(), sender.getUniqueId());
|
||||
return;
|
||||
}
|
||||
target.withdraw(currency, amount);
|
||||
|
||||
sender.sendMessage(
|
||||
miniMessage.deserialize(
|
||||
|
@ -196,14 +168,6 @@ public abstract class AbstractCommandManager implements CommandManager {
|
|||
return;
|
||||
}
|
||||
|
||||
if (amount.compareTo(BigDecimal.ZERO) < 0) {
|
||||
sender.sendMessage(
|
||||
miniMessage.deserialize(this.getConfig(currency).cannotPayNegative)
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
amount = amount.setScale(currency.getProxy().fractionalDigits(), RoundingMode.DOWN);
|
||||
|
||||
User user = this.plugin.getUserManager().getIfLoaded(sender.getUniqueId());
|
||||
|
@ -220,6 +184,7 @@ public abstract class AbstractCommandManager implements CommandManager {
|
|||
|
||||
// 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);
|
||||
|
@ -227,9 +192,14 @@ public abstract class AbstractCommandManager implements CommandManager {
|
|||
target.deposit(currency, taxedAmount);
|
||||
user.withdraw(currency, amount);
|
||||
|
||||
String template = tax.compareTo(BigDecimal.ZERO) > 0
|
||||
? this.getConfig(currency).payWithTax
|
||||
: this.getConfig(currency).pay;
|
||||
|
||||
|
||||
sender.sendMessage(
|
||||
miniMessage.deserialize(
|
||||
this.getConfig(currency).pay,
|
||||
template,
|
||||
Placeholder.parsed("currency", currency.getIdentifier()),
|
||||
Placeholder.parsed("target", target.getUsername()),
|
||||
Placeholder.parsed("amount", amount.toPlainString()),
|
||||
|
@ -239,9 +209,7 @@ public abstract class AbstractCommandManager implements CommandManager {
|
|||
)
|
||||
);
|
||||
|
||||
CompletableFuture.allOf(
|
||||
this.plugin.getUserManager().saveUser(user),
|
||||
this.plugin.getUserManager().saveUser(target)
|
||||
).thenAccept(v -> removeFromMustWait(sender.getUniqueId(), target.getUniqueId()));
|
||||
this.plugin.getUserManager().saveUsers(user, target)
|
||||
.thenAccept(v -> removeFromMustWait(sender.getUniqueId(), target.getUniqueId()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
package dev.xhyrom.lighteco.common.manager.currency;
|
||||
|
||||
import dev.xhyrom.lighteco.api.model.user.User;
|
||||
import dev.xhyrom.lighteco.common.manager.Manager;
|
||||
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.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface CurrencyManager extends Manager<String, Currency> {
|
||||
@NonNull Collection<Currency> getRegisteredCurrencies();
|
||||
|
||||
void registerCurrency(@NonNull Currency currency);
|
||||
|
||||
List<User> getTopUsers(@NonNull Currency currency, int length);
|
||||
CompletableFuture<List<User>> getTopUsers(@NonNull Currency currency, int length);
|
||||
}
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
package dev.xhyrom.lighteco.common.manager.currency;
|
||||
|
||||
import dev.xhyrom.lighteco.common.manager.AbstractManager;
|
||||
import dev.xhyrom.lighteco.api.model.user.User;
|
||||
import dev.xhyrom.lighteco.common.manager.SingleManager;
|
||||
import dev.xhyrom.lighteco.common.model.currency.Currency;
|
||||
import dev.xhyrom.lighteco.common.model.user.User;
|
||||
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class StandardCurrencyManager extends AbstractManager<String, Currency> implements CurrencyManager {
|
||||
public class StandardCurrencyManager extends SingleManager<String, Currency> implements CurrencyManager {
|
||||
private final LightEcoPlugin plugin;
|
||||
|
||||
public StandardCurrencyManager(LightEcoPlugin plugin) {
|
||||
|
@ -18,7 +19,7 @@ public class StandardCurrencyManager extends AbstractManager<String, Currency> i
|
|||
|
||||
@Override
|
||||
public Currency apply(String identifier) {
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -39,9 +40,8 @@ public class StandardCurrencyManager extends AbstractManager<String, Currency> i
|
|||
this.map.put(currency.getIdentifier(), currency);
|
||||
}
|
||||
|
||||
// TODO: finish
|
||||
@Override
|
||||
public List<User> getTopUsers(@NonNull Currency currency, int length) {
|
||||
return null;
|
||||
public CompletableFuture<List<User>> getTopUsers(@NonNull Currency currency, int length) {
|
||||
return this.plugin.getStorage().getTopUsers(currency.getProxy(), length);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
package dev.xhyrom.lighteco.common.manager.user;
|
||||
|
||||
import dev.xhyrom.lighteco.common.manager.AbstractManager;
|
||||
import dev.xhyrom.lighteco.common.manager.ConcurrentManager;
|
||||
import dev.xhyrom.lighteco.common.model.user.User;
|
||||
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class StandardUserManager extends AbstractManager<UUID, User> implements UserManager {
|
||||
public class StandardUserManager extends ConcurrentManager<UUID, User> implements UserManager {
|
||||
private final LightEcoPlugin plugin;
|
||||
|
||||
public StandardUserManager(LightEcoPlugin plugin) {
|
||||
|
@ -31,23 +30,17 @@ public class StandardUserManager extends AbstractManager<UUID, User> implements
|
|||
return this.plugin.getStorage().loadUser(uniqueId, username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> load() {
|
||||
Set<UUID> uniqueIds = new HashSet<>(keys());
|
||||
uniqueIds.addAll(this.plugin.getBootstrap().getOnlinePlayers());
|
||||
|
||||
return uniqueIds.stream()
|
||||
.map(id -> this.plugin.getStorage().loadUser(id))
|
||||
.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);
|
||||
public CompletableFuture<Void> saveUsers(User... users) {
|
||||
return this.plugin.getStorage().saveUsers(
|
||||
Arrays.stream(users)
|
||||
.map(User::getProxy)
|
||||
.toArray(dev.xhyrom.lighteco.api.model.user.User[]::new)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -8,11 +8,8 @@ import java.util.concurrent.CompletableFuture;
|
|||
|
||||
public interface UserManager extends Manager<UUID, User> {
|
||||
CompletableFuture<Void> saveUser(User user);
|
||||
|
||||
CompletableFuture<Void> load();
|
||||
CompletableFuture<Void> saveUsers(User... users);
|
||||
|
||||
CompletableFuture<User> loadUser(UUID uniqueId);
|
||||
CompletableFuture<User> loadUser(UUID uniqueId, String username);
|
||||
|
||||
void invalidateCaches();
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ import dev.xhyrom.lighteco.api.storage.StorageProvider;
|
|||
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
|
||||
import dev.xhyrom.lighteco.common.util.ThrowableRunnable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
@ -80,4 +82,14 @@ public class Storage {
|
|||
public CompletableFuture<Void> saveUser(dev.xhyrom.lighteco.api.model.user.User user) {
|
||||
return future(() -> this.provider.saveUser(user));
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> saveUsers(dev.xhyrom.lighteco.api.model.user.User... users) {
|
||||
return future(() -> this.provider.saveUsers(users));
|
||||
}
|
||||
|
||||
// Return ApiUser instead of User
|
||||
// We don't do anything with this
|
||||
public CompletableFuture<List<dev.xhyrom.lighteco.api.model.user.User>> getTopUsers(dev.xhyrom.lighteco.api.model.currency.Currency currency, int length) {
|
||||
return future(() -> this.provider.getTopUsers(currency, length));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
package dev.xhyrom.lighteco.common.storage.provider.memory;
|
||||
|
||||
import dev.xhyrom.lighteco.api.model.currency.Currency;
|
||||
import dev.xhyrom.lighteco.api.model.user.User;
|
||||
import dev.xhyrom.lighteco.api.storage.StorageProvider;
|
||||
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class MemoryStorageProvider implements StorageProvider {
|
||||
|
@ -41,6 +46,23 @@ public class MemoryStorageProvider implements StorageProvider {
|
|||
this.userDatabase.put(user.getUniqueId(), user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveUsers(@NotNull @NonNull User... users) {
|
||||
for (User user : users) {
|
||||
this.userDatabase.put(user.getUniqueId(), user);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull List<User> getTopUsers(Currency currency, int length) throws Exception {
|
||||
return userDatabase.values().stream().sorted((user1, user2) -> {
|
||||
BigDecimal balance1 = user1.getBalance(currency);
|
||||
BigDecimal balance2 = user2.getBalance(currency);
|
||||
|
||||
return balance1.compareTo(balance2);
|
||||
}).limit(length).toList();
|
||||
}
|
||||
|
||||
private User createUser(UUID uniqueId, String username, User data) {
|
||||
dev.xhyrom.lighteco.common.model.user.User user = this.plugin.getUserManager().getOrMake(uniqueId);
|
||||
if (username != null)
|
||||
|
|
|
@ -19,7 +19,7 @@ public enum SqlStatements {
|
|||
"SELECT currency_identifier, balance FROM ( SELECT currency_identifier, balance FROM '{prefix}_users' WHERE uuid = ?1 UNION ALL SELECT currency_identifier, balance FROM '{prefix}_{context}_users' WHERE uuid = ?1 ) AS combined_currencies;",
|
||||
"SELECT currency_identifier, balance FROM ( SELECT currency_identifier, balance FROM '{prefix}_users' WHERE uuid = ?1 UNION ALL SELECT currency_identifier, balance FROM '{prefix}_{context}_users' WHERE uuid = ?1 ) AS combined_currencies;",
|
||||
"SELECT currency_identifier, balance FROM ( SELECT currency_identifier, balance FROM '{prefix}_users' WHERE uuid = ? UNION ALL SELECT currency_identifier, balance FROM '{prefix}_{context}_users' WHERE uuid = ? ) AS combined_currencies;",
|
||||
null
|
||||
null // same as mariadb
|
||||
);
|
||||
|
||||
public final String sqlite;
|
||||
|
|
|
@ -8,11 +8,13 @@ import dev.xhyrom.lighteco.common.storage.StorageType;
|
|||
import dev.xhyrom.lighteco.common.storage.provider.sql.connection.ConnectionFactory;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
|
@ -21,7 +23,9 @@ public class SqlStorageProvider implements StorageProvider {
|
|||
private static String SAVE_USER_LOCAL_CURRENCY;
|
||||
private static String SAVE_USER_GLOBAL_CURRENCY;
|
||||
private static String LOAD_WHOLE_USER;
|
||||
|
||||
private static final String GET_TOP_X_USERS_LOCAL = "SELECT uuid, balance FROM {prefix}_{context}_users WHERE currency_identifier = ? ORDER BY balance DESC LIMIT ?;";
|
||||
private static final String GET_TOP_X_USERS_GLOBAL = "SELECT uuid, balance FROM {prefix}_users WHERE currency_identifier = ? ORDER BY balance DESC LIMIT ?;";
|
||||
|
||||
private final LightEcoPlugin plugin;
|
||||
private final ConnectionFactory connectionFactory;
|
||||
private final Function<String, String> statementProcessor;
|
||||
|
@ -109,37 +113,103 @@ public class SqlStorageProvider implements StorageProvider {
|
|||
try (PreparedStatement psGlobal = c.prepareStatement(this.statementProcessor.apply(SAVE_USER_GLOBAL_CURRENCY));
|
||||
PreparedStatement psLocal = c.prepareStatement(this.statementProcessor.apply(SAVE_USER_LOCAL_CURRENCY))) {
|
||||
|
||||
for (Currency currency : this.plugin.getCurrencyManager().getRegisteredCurrencies()) {
|
||||
BigDecimal balance = user.getBalance(currency.getProxy());
|
||||
|
||||
if (balance.compareTo(BigDecimal.ZERO) == 0) continue;
|
||||
|
||||
switch (currency.getType()) {
|
||||
case GLOBAL -> {
|
||||
psGlobal.setString(1, uniqueIdString);
|
||||
psGlobal.setString(2, currency.getIdentifier());
|
||||
psGlobal.setBigDecimal(3, balance);
|
||||
if (SqlStatements.mustDuplicateParameters(this.connectionFactory.getImplementationName()))
|
||||
psGlobal.setBigDecimal(4, balance);
|
||||
|
||||
psGlobal.addBatch();
|
||||
}
|
||||
case LOCAL -> {
|
||||
psLocal.setString(1, uniqueIdString);
|
||||
psLocal.setString(2, currency.getIdentifier());
|
||||
psLocal.setBigDecimal(3, balance);
|
||||
if (SqlStatements.mustDuplicateParameters(this.connectionFactory.getImplementationName()))
|
||||
psLocal.setBigDecimal(4, balance);
|
||||
|
||||
psLocal.addBatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
saveBalances(psGlobal, psLocal, user, uniqueIdString);
|
||||
|
||||
psGlobal.executeBatch();
|
||||
psLocal.executeBatch();
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("Failed to save user " + user.getUniqueId(), e);
|
||||
throw new SQLException("Failed to save user " + user.getUniqueId(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveUsers(@NotNull @NonNull User... users) throws Exception {
|
||||
// use transaction
|
||||
try (Connection c = this.connectionFactory.getConnection()) {
|
||||
try {
|
||||
c.setAutoCommit(false);
|
||||
|
||||
try (PreparedStatement psGlobal = c.prepareStatement(this.statementProcessor.apply(SAVE_USER_GLOBAL_CURRENCY));
|
||||
PreparedStatement psLocal = c.prepareStatement(this.statementProcessor.apply(SAVE_USER_LOCAL_CURRENCY))) {
|
||||
|
||||
for (User user : users) {
|
||||
String uniqueIdString = user.getUniqueId().toString();
|
||||
|
||||
saveBalances(psGlobal, psLocal, user, uniqueIdString);
|
||||
}
|
||||
|
||||
psGlobal.executeBatch();
|
||||
psLocal.executeBatch();
|
||||
} catch (SQLException e) {
|
||||
throw new SQLException("Failed to save users", e);
|
||||
}
|
||||
|
||||
c.commit();
|
||||
} catch (SQLException e) {
|
||||
c.rollback();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull List<User> getTopUsers(dev.xhyrom.lighteco.api.model.currency.Currency apiCurrency, int length) throws Exception {
|
||||
Currency currency = this.plugin.getCurrencyManager().getIfLoaded(apiCurrency.getIdentifier());
|
||||
String statement = currency.getType() == dev.xhyrom.lighteco.api.model.currency.Currency.Type.GLOBAL
|
||||
? GET_TOP_X_USERS_GLOBAL
|
||||
: GET_TOP_X_USERS_LOCAL;
|
||||
|
||||
try (Connection c = this.connectionFactory.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(statement))) {
|
||||
ps.setString(1, currency.getIdentifier());
|
||||
ps.setInt(2, length);
|
||||
|
||||
ResultSet rs = ps.executeQuery();
|
||||
|
||||
List<User> users = new ArrayList<>();
|
||||
while (rs.next()) {
|
||||
String uniqueIdString = rs.getString("uuid");
|
||||
UUID uniqueId = UUID.fromString(uniqueIdString);
|
||||
|
||||
BigDecimal balance = rs.getBigDecimal("balance");
|
||||
|
||||
dev.xhyrom.lighteco.common.model.user.User user = this.plugin.getUserManager().getOrMake(uniqueId);
|
||||
user.setBalance(currency, balance);
|
||||
|
||||
users.add(user.getProxy());
|
||||
}
|
||||
|
||||
return users;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void saveBalances(PreparedStatement psGlobal, PreparedStatement psLocal, User user, String uniqueIdString) throws SQLException {
|
||||
for (Currency currency : this.plugin.getCurrencyManager().getRegisteredCurrencies()) {
|
||||
BigDecimal balance = user.getBalance(currency.getProxy());
|
||||
|
||||
if (balance.compareTo(BigDecimal.ZERO) == 0) continue;
|
||||
|
||||
switch (currency.getType()) {
|
||||
case GLOBAL -> {
|
||||
psGlobal.setString(1, uniqueIdString);
|
||||
psGlobal.setString(2, currency.getIdentifier());
|
||||
psGlobal.setBigDecimal(3, balance);
|
||||
if (SqlStatements.mustDuplicateParameters(this.connectionFactory.getImplementationName()))
|
||||
psGlobal.setBigDecimal(4, balance);
|
||||
|
||||
psGlobal.addBatch();
|
||||
}
|
||||
case LOCAL -> {
|
||||
psLocal.setString(1, uniqueIdString);
|
||||
psLocal.setString(2, currency.getIdentifier());
|
||||
psLocal.setBigDecimal(3, balance);
|
||||
if (SqlStatements.mustDuplicateParameters(this.connectionFactory.getImplementationName()))
|
||||
psLocal.setBigDecimal(4, balance);
|
||||
|
||||
psLocal.addBatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,12 +64,12 @@ public abstract class HikariConnectionFactory implements ConnectionFactory {
|
|||
this.setProperties(config, properties);
|
||||
|
||||
// configure the connection pool
|
||||
// config.setMaximumPoolSize(1);
|
||||
// config.setMinimumIdle(10);
|
||||
// config.setMaxLifetime(1800000);
|
||||
// config.setKeepaliveTime(0);
|
||||
// config.setConnectionTimeout(5000);
|
||||
// config.setInitializationFailTimeout(-1);
|
||||
config.setMaximumPoolSize(this.configuration.maximumPoolSize);
|
||||
config.setMinimumIdle(this.configuration.minimumIdle);
|
||||
config.setMaxLifetime(this.configuration.maxLifetime);
|
||||
config.setKeepaliveTime(this.configuration.keepAliveTime);
|
||||
config.setConnectionTimeout(this.configuration.connectionTimeout);
|
||||
config.setInitializationFailTimeout(-1);
|
||||
|
||||
this.hikari = new HikariDataSource(config);
|
||||
|
||||
|
|
Loading…
Reference in a new issue