From d77cb08f53bb5175b980760b4d5ffda09f6ca8d5 Mon Sep 17 00:00:00 2001 From: jakub Date: Sat, 14 Jun 2025 23:08:52 +0200 Subject: [PATCH] ik --- .../xyz/soukup/ecoCraftCore/EcoCraftCore.java | 11 ++- .../ecoCraftCore/commands/MoneyCommand.java | 22 +++-- .../ecoCraftCore/commands/ShopCommand.java | 3 +- .../commands/TransactionCommand.java | 33 ------- .../ecoCraftCore/events/PreparePlayer.java | 1 - .../soukup/ecoCraftCore/events/ShopLogic.java | 1 - .../events/VirtualChestLogic.java | 8 +- .../soukup/ecoCraftCore/objects/Account.java | 95 ++++++++++++++++--- .../xyz/soukup/ecoCraftCore/objects/Shop.java | 11 +++ .../ecoCraftCore/objects/Transaction.java | 24 +---- .../ecoCraftCore/objects/VirtualChest.java | 44 ++++++--- src/main/resources/config.yml | 12 +++ src/main/resources/messages.yml | 29 ++++++ 13 files changed, 196 insertions(+), 98 deletions(-) delete mode 100644 src/main/java/xyz/soukup/ecoCraftCore/commands/TransactionCommand.java create mode 100644 src/main/resources/config.yml create mode 100644 src/main/resources/messages.yml diff --git a/src/main/java/xyz/soukup/ecoCraftCore/EcoCraftCore.java b/src/main/java/xyz/soukup/ecoCraftCore/EcoCraftCore.java index 34f86dc..957492c 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/EcoCraftCore.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/EcoCraftCore.java @@ -12,7 +12,6 @@ import org.jetbrains.annotations.NotNull; import xyz.soukup.ecoCraftCore.commands.MoneyCommand; import xyz.soukup.ecoCraftCore.commands.RulerCommand; import xyz.soukup.ecoCraftCore.commands.ShopCommand; -import xyz.soukup.ecoCraftCore.commands.TransactionCommand; import xyz.soukup.ecoCraftCore.events.PreparePlayer; import xyz.soukup.ecoCraftCore.events.RulerMarking; import xyz.soukup.ecoCraftCore.events.ShopLogic; @@ -25,6 +24,7 @@ import xyz.soukup.ecoCraftCore.objects.VirtualChest; import xyz.soukup.ecoCraftCore.utilities.DaoRegistry; import java.sql.SQLException; +import java.time.Duration; import java.util.logging.Level; import java.util.logging.Logger; @@ -44,10 +44,18 @@ public final class EcoCraftCore extends JavaPlugin { e.printStackTrace(); getLogger().severe("Failed to initialize database."); } + + this.getServer().getScheduler().runTaskTimer(this, /* Lambda: */ task -> { + VirtualChest.saveCache(); + } , 6000, 6000); + } @Override public void onDisable() { + + VirtualChest.saveCache(); + try { if (connectionSource != null) { connectionSource.close(); @@ -78,7 +86,6 @@ public final class EcoCraftCore extends JavaPlugin { private void registerCommands() { @NotNull LifecycleEventManager<@NotNull Plugin> lm = this.getLifecycleManager(); - lm.registerEventHandler(LifecycleEvents.COMMANDS, event -> event.registrar().register(TransactionCommand.createCommand().build())); lm.registerEventHandler(LifecycleEvents.COMMANDS, event -> event.registrar().register(ShopCommand.createCommand().build())); lm.registerEventHandler(LifecycleEvents.COMMANDS, event -> event.registrar().register(RulerCommand.createCommand().build())); lm.registerEventHandler(LifecycleEvents.COMMANDS, event -> event.registrar().register(MoneyCommand.createCommand().build())); diff --git a/src/main/java/xyz/soukup/ecoCraftCore/commands/MoneyCommand.java b/src/main/java/xyz/soukup/ecoCraftCore/commands/MoneyCommand.java index 6dcd0ec..61d76fb 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/commands/MoneyCommand.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/commands/MoneyCommand.java @@ -4,9 +4,11 @@ import com.mojang.brigadier.arguments.FloatArgumentType; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; import io.papermc.paper.command.brigadier.CommandSourceStack; import io.papermc.paper.command.brigadier.Commands; import io.papermc.paper.command.brigadier.argument.ArgumentTypes; +import io.papermc.paper.command.brigadier.argument.resolvers.selector.PlayerSelectorArgumentResolver; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import xyz.soukup.ecoCraftCore.objects.Account; @@ -57,9 +59,11 @@ public class MoneyCommand { } - private static int sendMoney(CommandContext context){ + private static int sendMoney(CommandContext context) throws CommandSyntaxException { + PlayerSelectorArgumentResolver receiverResolver = context.getArgument("player", PlayerSelectorArgumentResolver.class); + Player receiver = receiverResolver.resolve(context.getSource()).getFirst(); + Player sender = (Player) context.getSource().getSender(); - Player receiver = context.getArgument("player", Player.class); Float amount = context.getArgument("amount", Float.class); Account senderAccount = Account.getOrCreate(sender); @@ -75,9 +79,12 @@ public class MoneyCommand { return 1; } - private static int giveMoneyPlayer(CommandContext context){ + private static int giveMoneyPlayer(CommandContext context) throws CommandSyntaxException { CommandSender commandSender = context.getSource().getSender(); - Player receiver = context.getArgument("player", Player.class); + + PlayerSelectorArgumentResolver receiverResolver = context.getArgument("player", PlayerSelectorArgumentResolver.class); + Player receiver = receiverResolver.resolve(context.getSource()).getFirst(); + Float amount = context.getArgument("amount", Float.class); Transaction transaction = new Transaction(amount,"admin", commandSender.getName(), "player", receiver.getName(), "admin"); @@ -105,9 +112,12 @@ public class MoneyCommand { transaction.process(); return 1; } - private static int removeMoneyPlayer(CommandContext context){ + private static int removeMoneyPlayer(CommandContext context) throws CommandSyntaxException { CommandSender commandSender = context.getSource().getSender(); - Player sender = context.getArgument("player", Player.class); + + PlayerSelectorArgumentResolver senderResolver = context.getArgument("player", PlayerSelectorArgumentResolver.class); + Player sender = senderResolver.resolve(context.getSource()).getFirst(); + Float amount = context.getArgument("amount", Float.class); Transaction transaction = new Transaction(amount, "player", sender.getName(),"admin", commandSender.getName(), "admin"); diff --git a/src/main/java/xyz/soukup/ecoCraftCore/commands/ShopCommand.java b/src/main/java/xyz/soukup/ecoCraftCore/commands/ShopCommand.java index 104f898..01d9ef6 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/commands/ShopCommand.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/commands/ShopCommand.java @@ -5,7 +5,6 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import io.papermc.paper.command.brigadier.CommandSourceStack; import io.papermc.paper.command.brigadier.Commands; -import org.bukkit.Location; import org.bukkit.block.Chest; import org.bukkit.block.Sign; import org.bukkit.entity.Player; @@ -82,7 +81,7 @@ public class ShopCommand { VirtualChest virtualChest = VirtualChest.getOrCreate(chest); - virtualChest.save(); + virtualChest.databaseSave(); PDC.set(chest, "virtual", virtualChest.getId()); diff --git a/src/main/java/xyz/soukup/ecoCraftCore/commands/TransactionCommand.java b/src/main/java/xyz/soukup/ecoCraftCore/commands/TransactionCommand.java deleted file mode 100644 index a69658a..0000000 --- a/src/main/java/xyz/soukup/ecoCraftCore/commands/TransactionCommand.java +++ /dev/null @@ -1,33 +0,0 @@ -package xyz.soukup.ecoCraftCore.commands; - -import com.mojang.brigadier.arguments.FloatArgumentType; -import com.mojang.brigadier.arguments.StringArgumentType; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import com.mojang.brigadier.context.CommandContext; -import io.papermc.paper.command.brigadier.CommandSourceStack; -import io.papermc.paper.command.brigadier.Commands; -import xyz.soukup.ecoCraftCore.objects.Transaction; - -public class TransactionCommand { - - public static LiteralArgumentBuilder createCommand() { - return Commands.literal("transaction") - .then(Commands.literal("simulate") - .then(Commands.argument("sender", StringArgumentType.word()) - .then(Commands.argument("receiver", StringArgumentType.word()) - .then(Commands.argument("amount", FloatArgumentType.floatArg(0.1F)) - .executes(TransactionCommand::simulateTransaction))))); - } - - private static int simulateTransaction(CommandContext ctx) { - String sender = StringArgumentType.getString(ctx, "sender"); - String receiver = StringArgumentType.getString(ctx, "receiver"); - Float amount = FloatArgumentType.getFloat(ctx, "amount"); - - - Transaction tx = new Transaction(amount, "player", sender, "player", receiver, "command"); - tx.save(); - - return 1; - } -} diff --git a/src/main/java/xyz/soukup/ecoCraftCore/events/PreparePlayer.java b/src/main/java/xyz/soukup/ecoCraftCore/events/PreparePlayer.java index 966d5d3..a6509a7 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/events/PreparePlayer.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/events/PreparePlayer.java @@ -10,6 +10,5 @@ public class PreparePlayer implements Listener { @EventHandler public void preparePlayer(PlayerJoinEvent event){ Account account = Account.getOrCreate(event.getPlayer()); - account.save(); } } diff --git a/src/main/java/xyz/soukup/ecoCraftCore/events/ShopLogic.java b/src/main/java/xyz/soukup/ecoCraftCore/events/ShopLogic.java index 3ca1bd0..1e18ac6 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/events/ShopLogic.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/events/ShopLogic.java @@ -226,7 +226,6 @@ public class ShopLogic implements Listener { virtualChest.save(); Transaction transaction = new Transaction(price, "player", shop.getOwner(), "player", player.getName(), "playerShop", shop.getItemName() ,Integer.toString(amount)); - transaction.process(); } diff --git a/src/main/java/xyz/soukup/ecoCraftCore/events/VirtualChestLogic.java b/src/main/java/xyz/soukup/ecoCraftCore/events/VirtualChestLogic.java index 94a609b..7c9d93d 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/events/VirtualChestLogic.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/events/VirtualChestLogic.java @@ -1,26 +1,20 @@ package xyz.soukup.ecoCraftCore.events; -import com.destroystokyo.paper.utils.PaperPluginLogger; -import com.j256.ormlite.stmt.query.In; import org.bukkit.block.Chest; import org.bukkit.block.DoubleChest; import org.bukkit.block.TileState; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import org.bukkit.event.inventory.HopperInventorySearchEvent; import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.inventory.InventoryMoveItemEvent; import org.bukkit.event.inventory.InventoryOpenEvent; -import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import xyz.soukup.ecoCraftCore.objects.VirtualChest; import xyz.soukup.ecoCraftCore.utilities.PDC; import java.util.HashMap; -import java.util.List; -import java.util.Objects; public class VirtualChestLogic implements Listener { @@ -106,7 +100,7 @@ public class VirtualChestLogic implements Listener { return; } - virtualChest.setOpened(false); + virtualChest.setInventory(event.getInventory()); virtualChest.save(); } diff --git a/src/main/java/xyz/soukup/ecoCraftCore/objects/Account.java b/src/main/java/xyz/soukup/ecoCraftCore/objects/Account.java index 293f1a4..d174a84 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/objects/Account.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/objects/Account.java @@ -1,7 +1,9 @@ package xyz.soukup.ecoCraftCore.objects; import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.misc.TransactionManager; import com.j256.ormlite.stmt.QueryBuilder; +import com.j256.ormlite.stmt.UpdateBuilder; import com.j256.ormlite.table.DatabaseTable; import org.bukkit.entity.Player; @@ -9,6 +11,9 @@ import xyz.soukup.ecoCraftCore.EcoCraftCore; import xyz.soukup.ecoCraftCore.utilities.DaoRegistry; import java.sql.SQLException; +import java.util.HashMap; + +import static xyz.soukup.ecoCraftCore.EcoCraftCore.connectionSource; @DatabaseTable(tableName = "accounts") public class Account { @@ -24,6 +29,8 @@ public class Account { @DatabaseField(canBeNull = false, defaultValue = "0") private float balance; + private static final HashMap cache = new HashMap<>(); + public Account(){ } @@ -42,33 +49,90 @@ public class Account { } public float getBalance() { - return balance; + try { + Account fresh = DaoRegistry.getAccountDao().queryBuilder() + .selectColumns("balance") + .where().eq("id", this.id) + .queryForFirst(); + + return fresh.balance; + } catch (SQLException e) { + throw new RuntimeException("Failed to refresh balance from DB", e); + } } public int getId() { return id; } - public void setBalance(float balance) { - this.balance = balance; - } + public void deposit(float amount){ - this.balance += amount; + try { + TransactionManager.callInTransaction(connectionSource, () -> { + UpdateBuilder builder = DaoRegistry.getAccountDao().updateBuilder(); + builder.updateColumnExpression("balance", "balance + " + amount); + builder.where().idEq(this.id); + int updated = builder.update(); + return null; + }); + } catch (SQLException e) { + throw new RuntimeException("Failed to deposit funds", e); + } } public void withdraw(float amount){ - this.balance -= amount; + try { + TransactionManager.callInTransaction(connectionSource, () -> { + UpdateBuilder builder = DaoRegistry.getAccountDao().updateBuilder(); + builder.updateColumnExpression("balance", "balance - " + amount); + builder.where().idEq(this.id); + return null; + }); + } catch (SQLException e) { + throw new RuntimeException("Failed to deposit funds", e); + } + } + + public static void transferFunds(Account from, Account to, float amount) { + try { + TransactionManager.callInTransaction( + connectionSource, + () -> { + UpdateBuilder withdrawBuilder = DaoRegistry.getAccountDao().updateBuilder(); + withdrawBuilder.updateColumnExpression("balance", "balance - " + amount); + withdrawBuilder.where().eq("id", from.getId()); + withdrawBuilder.update(); + + UpdateBuilder depositBuilder = DaoRegistry.getAccountDao().updateBuilder(); + depositBuilder.updateColumnExpression("balance", "balance + " + amount); + depositBuilder.where().idEq(to.getId()); + depositBuilder.update(); + + return null; + } + ); + } catch (SQLException e) { + throw new RuntimeException("Fund transfer failed: " + e.getMessage(), e); + } } public static Account getOrCreate(String type, String owner){ + + Account account = cache.get(type + "." + owner); + + if (account != null){ + return account; + } + QueryBuilder queryBuilder = DaoRegistry.getAccountDao().queryBuilder(); + try { queryBuilder.where() .eq("type", type) .and() .eq("owner", owner); - Account account = DaoRegistry.getAccountDao().queryForFirst(queryBuilder.prepare()); + account = DaoRegistry.getAccountDao().queryForFirst(queryBuilder.prepare()); if (account == null){ account = new Account(owner, type); @@ -90,6 +154,15 @@ public class Account { if (account == null){ account = new Account(player.getName(), "player"); + + try { + DaoRegistry.getAccountDao().createOrUpdate(account); + } catch (SQLException e) { + throw new RuntimeException(e); + } + + cache.put(account.type + "." + account.owner, account); + } return account; } catch (SQLException e) { @@ -97,13 +170,5 @@ public class Account { } } - public void save(){ - try { - DaoRegistry.getAccountDao().createOrUpdate(this); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - } diff --git a/src/main/java/xyz/soukup/ecoCraftCore/objects/Shop.java b/src/main/java/xyz/soukup/ecoCraftCore/objects/Shop.java index ff1862c..b41ac1c 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/objects/Shop.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/objects/Shop.java @@ -14,6 +14,7 @@ import xyz.soukup.ecoCraftCore.utilities.PDC; import java.sql.SQLException; import java.sql.Timestamp; +import java.util.HashMap; @DatabaseTable(tableName = "shops") public class Shop { @@ -58,6 +59,8 @@ public class Shop { @DatabaseField(columnName = "active_on_server") private String activeServer; + private static final HashMap cache = new HashMap<>(); + public Shop() { } @@ -100,6 +103,12 @@ public class Shop { } public static Shop findById(int id) { + Shop shop = cache.get(id); + + if (shop != null){ + return shop; + } + try { return DaoRegistry.getShopDao().queryForId(id); } catch (SQLException e) { @@ -113,6 +122,8 @@ public class Shop { } catch (SQLException e) { throw new RuntimeException(e); } + + cache.put(this.id, this); } public ItemStack getItemStack() { diff --git a/src/main/java/xyz/soukup/ecoCraftCore/objects/Transaction.java b/src/main/java/xyz/soukup/ecoCraftCore/objects/Transaction.java index 3ce8e39..c2bff31 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/objects/Transaction.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/objects/Transaction.java @@ -49,14 +49,6 @@ public class Transaction { // ORMLite requires a no-arg constructor } - public void save(){ - try { - DaoRegistry.getTransactionDao().createOrUpdate(this); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - public void process(){ if (processed){ @@ -65,19 +57,13 @@ public class Transaction { this.processed = true; - if(!Objects.equals(this.senderType, "admin")){ - Account senderAccount = Account.getOrCreate(this.senderType, this.sender); - senderAccount.withdraw(this.amount); - senderAccount.save(); - } + Account.transferFunds(Account.getOrCreate(this.senderType, this.sender), Account.getOrCreate(this.receiverType, this.receiver), this.amount); - if (!Objects.equals(this.receiverType, "admin")){ - Account receiverAccount = Account.getOrCreate(this.receiverType, this.receiver); - receiverAccount.deposit(this.amount); - receiverAccount.save(); + try { + DaoRegistry.getTransactionDao().createOrUpdate(this); + } catch (SQLException e) { + throw new RuntimeException(e); } - - save(); } public static Transaction findById(int id) { diff --git a/src/main/java/xyz/soukup/ecoCraftCore/objects/VirtualChest.java b/src/main/java/xyz/soukup/ecoCraftCore/objects/VirtualChest.java index 8cb472b..92464e9 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/objects/VirtualChest.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/objects/VirtualChest.java @@ -12,6 +12,8 @@ import xyz.soukup.ecoCraftCore.utilities.InventoryUtils; import xyz.soukup.ecoCraftCore.utilities.PDC; import java.sql.SQLException; +import java.util.HashMap; +import java.util.HashSet; @DatabaseTable(tableName = "virtual_chests") public class VirtualChest { @@ -25,11 +27,10 @@ public class VirtualChest { @DatabaseField(columnName = "active_on_server") private String activeServer; - @DatabaseField(columnName = "is_opened") - private Boolean isOpened = false; - private Inventory inventory; + private static final HashMap cache = new HashMap<>(); + private static final HashSet cacheChanges = new HashSet<>(); public VirtualChest(){ @@ -59,14 +60,38 @@ public class VirtualChest { } public static VirtualChest findById(int id) { + + VirtualChest virtualChest = cache.get(id); + + if (virtualChest != null){ + return virtualChest; + } + try { return DaoRegistry.getVirtualChestDao().queryForId(id); } catch (SQLException e) { return null; } + + } - public void save(){ + public static void saveCache(){ + cache.forEach((key, value) -> { + if (!cacheChanges.contains(key)) return; + + value.databaseSave(); + }); + + + } + + public void save() { + cache.put(this.id, this); + cacheChanges.add(this.id); + } + + public void databaseSave(){ if (this.inventory != null){ this.inventoryString = Converter.toString(this.inventory); } @@ -75,6 +100,9 @@ public class VirtualChest { } catch (SQLException e) { throw new RuntimeException(e); } + + cache.put(this.id, this); + cacheChanges.remove(this.id); } public void setInventory(Inventory inventory) { @@ -110,18 +138,10 @@ public class VirtualChest { return id; } - public Boolean getOpened() { - return isOpened; - } - public String getActiveServer() { return activeServer; } - public void setOpened(Boolean opened) { - isOpened = opened; - } - public void setActiveServer(String activeServer) { this.activeServer = activeServer; } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..af80369 --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,12 @@ +version: 1.0 +server: + name: "test" + type: "island" +database: + host: localhost + port: 3306 + user: "ecc" + password: "ecc" + database: "ecc" +cache: + save-interval: 6000 \ No newline at end of file diff --git a/src/main/resources/messages.yml b/src/main/resources/messages.yml new file mode 100644 index 0000000..e638e5f --- /dev/null +++ b/src/main/resources/messages.yml @@ -0,0 +1,29 @@ +generic: + error: + no-funds: + self: "Nemáš dost pěněz" + shop: "Obchod nemá dost peněz" + no-space: + self: "Nemáš ve svém inventáři dostatek místa" + shop: "V obchodě není dostatek místa" + no-item: + self: "Nemáš dostatek itemů" + shop: "Obchod nemá dostatek itemů" +shop: + buy: "Koupil jsi x za " + sell: "Prodal jsi x za " + create: "Obchod vytvořen." +money: + give: + self: "Dal sis " + player: "Dal jsi hráči " + send: + player: "Poslal jsi hráči " + receive: + player: "Obdržel jsi od hráče " +marker: + marked: + chest: "Truhla označena (,,)" + sign: "Cedule označena (,,)" + primary: "První pozice označena (,,)" + secondary: "Druhá pozice označena (,,)" \ No newline at end of file