From 1842387ec862491c5b2f2602153cbc5b04d363c1 Mon Sep 17 00:00:00 2001 From: Aria Date: Fri, 21 Apr 2023 17:44:33 -0700 Subject: [PATCH] Add a custom currency API --- .../dev/zontreck/libzontreck/LibZontreck.java | 7 + .../libzontreck/currency/Account.java | 85 +++++++ .../currency/AccountReference.java | 17 ++ .../zontreck/libzontreck/currency/Bank.java | 214 ++++++++++++++++++ .../libzontreck/currency/CurrencyHelper.java | 7 - .../LongTermTransactionHistoryRecord.java | 72 ++++++ .../libzontreck/currency/Transaction.java | 42 ++++ .../events/BankAccountCreatedEvent.java | 19 ++ .../currency/events/BankReadyEvent.java | 17 ++ .../events/CurrencyBalanceCheckEvent.java | 20 -- .../currency/events/TransactionEvent.java | 26 +++ .../events/TransactionHistoryFlushEvent.java | 27 +++ .../currency/events/WalletSyncEvent.java | 25 ++ .../currency/events/WalletUpdatedEvent.java | 30 +++ .../events/ForgeEventHandlers.java | 10 +- .../libzontreck/networking/ModMessages.java | 14 +- .../libzontreck/networking/NetworkEvents.java | 18 ++ .../packets/S2CPlaySoundPacket.java | 7 +- .../packets/S2CWalletInitialSyncPacket.java | 70 ++++++ .../packets/S2CWalletUpdatedPacket.java | 80 +++++++ .../libzontreck/profiles/Profile.java | 5 + .../libzontreck/util/ChatHelpers.java | 3 + .../libzontreck/util/ServerUtilities.java | 10 +- 23 files changed, 783 insertions(+), 42 deletions(-) create mode 100644 src/main/java/dev/zontreck/libzontreck/currency/Account.java create mode 100644 src/main/java/dev/zontreck/libzontreck/currency/AccountReference.java create mode 100644 src/main/java/dev/zontreck/libzontreck/currency/Bank.java create mode 100644 src/main/java/dev/zontreck/libzontreck/currency/LongTermTransactionHistoryRecord.java create mode 100644 src/main/java/dev/zontreck/libzontreck/currency/Transaction.java create mode 100644 src/main/java/dev/zontreck/libzontreck/currency/events/BankAccountCreatedEvent.java create mode 100644 src/main/java/dev/zontreck/libzontreck/currency/events/BankReadyEvent.java delete mode 100644 src/main/java/dev/zontreck/libzontreck/currency/events/CurrencyBalanceCheckEvent.java create mode 100644 src/main/java/dev/zontreck/libzontreck/currency/events/TransactionEvent.java create mode 100644 src/main/java/dev/zontreck/libzontreck/currency/events/TransactionHistoryFlushEvent.java create mode 100644 src/main/java/dev/zontreck/libzontreck/currency/events/WalletSyncEvent.java create mode 100644 src/main/java/dev/zontreck/libzontreck/currency/events/WalletUpdatedEvent.java create mode 100644 src/main/java/dev/zontreck/libzontreck/networking/NetworkEvents.java create mode 100644 src/main/java/dev/zontreck/libzontreck/networking/packets/S2CWalletInitialSyncPacket.java create mode 100644 src/main/java/dev/zontreck/libzontreck/networking/packets/S2CWalletUpdatedPacket.java diff --git a/src/main/java/dev/zontreck/libzontreck/LibZontreck.java b/src/main/java/dev/zontreck/libzontreck/LibZontreck.java index 6715d3b..0f26134 100644 --- a/src/main/java/dev/zontreck/libzontreck/LibZontreck.java +++ b/src/main/java/dev/zontreck/libzontreck/LibZontreck.java @@ -6,9 +6,12 @@ import java.nio.file.Path; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.UUID; import dev.zontreck.ariaslib.events.EventBus; +import dev.zontreck.libzontreck.currency.Bank; import dev.zontreck.libzontreck.currency.CurrencyHelper; +import dev.zontreck.libzontreck.networking.NetworkEvents; import org.slf4j.Logger; import com.mojang.logging.LogUtils; @@ -44,6 +47,7 @@ public class LibZontreck { public static final Path BASE_CONFIG; public static final String PLAYER_INFO_URL = "https://api.mojang.com/users/profiles/minecraft/"; public static final String PLAYER_SKIN_URL = "https://sessionserver.mojang.com/session/minecraft/profile/"; + public static final UUID NULL_ID; public static LogicalSide CURRENT_SIDE; @@ -51,6 +55,7 @@ public class LibZontreck { static{ + NULL_ID = new UUID(0,0); PROFILES = new HashMap<>(); BASE_CONFIG = FileTreeDatastore.of("libzontreck"); @@ -74,7 +79,9 @@ public class LibZontreck { MinecraftForge.EVENT_BUS.register(this); MinecraftForge.EVENT_BUS.register(new ForgeEventHandlers()); MinecraftForge.EVENT_BUS.register(new Commands()); + MinecraftForge.EVENT_BUS.register(new NetworkEvents()); EventBus.BUS.register(CurrencyHelper.class); + EventBus.BUS.register(Bank.class); } private void setup(final FMLCommonSetupEvent event) diff --git a/src/main/java/dev/zontreck/libzontreck/currency/Account.java b/src/main/java/dev/zontreck/libzontreck/currency/Account.java new file mode 100644 index 0000000..f934deb --- /dev/null +++ b/src/main/java/dev/zontreck/libzontreck/currency/Account.java @@ -0,0 +1,85 @@ +package dev.zontreck.libzontreck.currency; + +import dev.zontreck.ariaslib.events.EventBus; +import dev.zontreck.libzontreck.currency.events.TransactionHistoryFlushEvent; +import net.minecraft.core.UUIDUtil; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.nbt.Tag; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class Account +{ + public UUID player_id; + public List history; + public int balance; + + public AccountReference getRef() + { + return new AccountReference(player_id); + } + + protected Account(UUID ID) + { + player_id=ID; + history=new ArrayList<>(); + balance=0; + } + + public CompoundTag save() + { + CompoundTag tag = new CompoundTag(); + tag.put("id", NbtUtils.createUUID(player_id)); + tag.putInt("balance", balance); + ListTag txs = new ListTag(); + for(Transaction tx : history) + { + txs.add(tx.save()); + } + + tag.put("history", txs); + + return tag; + } + + public Account(CompoundTag tag) + { + player_id = NbtUtils.loadUUID(tag.get("id")); + balance = tag.getInt("balance"); + history=new ArrayList<>(); + ListTag lst = tag.getList("history", Tag.TAG_COMPOUND); + for(Tag t : lst){ + CompoundTag lTag = (CompoundTag) t; + history.add(new Transaction(lTag)); + } + } + + /** + * Internal function for use only by the garbage collector to reduce memory footprint. Maximum of 20 transactions will be retained in the memory + * + * When the TX history grows beyond 20, the history should clear and it should get transferred to the long-term tx history storage. That file is not retained in memory, and only gets loaded when clearing to merge the lists. It is immediately saved and unloaded + * @see LongTermTransactionHistoryRecord + */ + public void flushTxHistory() + { + LongTermTransactionHistoryRecord rec = LongTermTransactionHistoryRecord.of(player_id); + rec.addHistory(history); + rec.commit(); + EventBus.BUS.post(new TransactionHistoryFlushEvent(this, rec, history)); + rec = null; + history = new ArrayList<>(); + } + + /** + * Checks if the account is a player or system account + * @return True if the player has a valid UUID + */ + public boolean isValidPlayer() + { + return !player_id.equals(new UUID(0,0)); + } +} diff --git a/src/main/java/dev/zontreck/libzontreck/currency/AccountReference.java b/src/main/java/dev/zontreck/libzontreck/currency/AccountReference.java new file mode 100644 index 0000000..74200dd --- /dev/null +++ b/src/main/java/dev/zontreck/libzontreck/currency/AccountReference.java @@ -0,0 +1,17 @@ +package dev.zontreck.libzontreck.currency; + +import java.util.UUID; + +public class AccountReference +{ + public UUID id; + public Account get() + { + return Bank.getAccount(id); + } + + protected AccountReference(UUID ID) + { + id=ID; + } +} diff --git a/src/main/java/dev/zontreck/libzontreck/currency/Bank.java b/src/main/java/dev/zontreck/libzontreck/currency/Bank.java new file mode 100644 index 0000000..da77f82 --- /dev/null +++ b/src/main/java/dev/zontreck/libzontreck/currency/Bank.java @@ -0,0 +1,214 @@ +package dev.zontreck.libzontreck.currency; + +import com.google.common.collect.Lists; +import dev.zontreck.ariaslib.events.Event; +import dev.zontreck.ariaslib.events.EventBus; +import dev.zontreck.ariaslib.events.annotations.Subscribe; +import dev.zontreck.libzontreck.LibZontreck; +import dev.zontreck.libzontreck.chat.ChatColor; +import dev.zontreck.libzontreck.chat.ChatColorFactory; +import dev.zontreck.libzontreck.currency.events.BankAccountCreatedEvent; +import dev.zontreck.libzontreck.currency.events.BankReadyEvent; +import dev.zontreck.libzontreck.currency.events.TransactionEvent; +import dev.zontreck.libzontreck.currency.events.WalletUpdatedEvent; +import dev.zontreck.libzontreck.exceptions.InvalidSideException; +import dev.zontreck.libzontreck.networking.ModMessages; +import dev.zontreck.libzontreck.networking.packets.S2CWalletUpdatedPacket; +import dev.zontreck.libzontreck.profiles.Profile; +import dev.zontreck.libzontreck.profiles.UserProfileNotYetExistsException; +import dev.zontreck.libzontreck.util.ChatHelpers; +import dev.zontreck.libzontreck.util.ServerUtilities; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.Tag; +import net.minecraftforge.common.MinecraftForge; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +public class Bank +{ + public static final Path BANK_DATA; + + static { + BANK_DATA = LibZontreck.BASE_CONFIG.resolve("bank.nbt"); + } + + private Bank(){ + load(); + } + + /** + * Internal function to deserialize NBT + */ + private void load() + { + try { + CompoundTag data = NbtIo.read(BANK_DATA.toFile()); + accounts=new ArrayList<>(); + ListTag acts = data.getList("accounts", Tag.TAG_COMPOUND); + for(Tag t : acts) + { + accounts.add(new Account((CompoundTag) t)); + } + + EventBus.BUS.post(new BankReadyEvent()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Do not use manually, this saves the bank data to disk. This is fired automatically when transactions are posted to accounts. + */ + public void commit() + { + CompoundTag tag = new CompoundTag(); + ListTag lst = new ListTag(); + for(Account act : accounts) + { + lst.add(act.save()); + } + tag.put("accounts", lst); + + try { + NbtIo.write(tag, BANK_DATA.toFile()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static final Bank instance = new Bank(); + + public List accounts = new ArrayList<>(); + + public static Account getAccount(UUID ID) + { + if(!hasAccount(ID))return null; + return instance.accounts.stream().filter(c->c.player_id.equals(ID)).collect(Collectors.toList()).get(0); + } + + public static boolean hasAccount(UUID ID) + { + return instance.accounts.stream().filter(c->c.player_id.equals(ID)).collect(Collectors.toList()).stream().count()>0; + } + + public static void makeAccount(UUID ID) + { + if(!hasAccount(ID)){ + instance.accounts.add(new Account(ID)); + + instance.commit(); + EventBus.BUS.post(new BankAccountCreatedEvent(getAccount(ID))); + }else return; + } + + /** + * Attempts to post a transaction and perform the money transfer + * + * Please post your reason to the Reasons list when cancelling. + * @param tx The transaction being attempted + * @return True if the transaction has been accepted. False if the transaction was rejected, or insufficient funds. + */ + public static boolean postTx(Transaction tx) throws InvalidSideException { + if(ServerUtilities.isClient())return false; + TransactionEvent ev = new TransactionEvent(tx); + if(EventBus.BUS.post(ev)) + { + // Send the list of reasons to the user + String reasonStr = String.join("\n", ev.reasons); + + Account from = ev.tx.from.get(); + Account to = ev.tx.to.get(); + + if(from.isValidPlayer()) + { + ChatHelpers.broadcastTo(from.player_id, ChatHelpers.macro("!Dark_Gray![!Dark_Blue!Bank!Dark_Gray!] !Dark_Red!The transaction could not be completed because of the following reasons: " + reasonStr), LibZontreck.THE_SERVER); + } + if(to.isValidPlayer()) + { + ChatHelpers.broadcastTo(to.player_id, ChatHelpers.macro("!Dark_Gray![!Dark_Blue!Bank!Dark_Gray!] !Dark_Red!The transaction could not be completed because of the following reasons: " + reasonStr), LibZontreck.THE_SERVER); + } + + return false; + }else { + // Tx accepted + // Process funds now + Account from = ev.tx.from.get(); + Account to = ev.tx.to.get(); + int fromOld = from.balance; + int toOld = to.balance; + from.balance -= tx.amount; + to.balance += tx.amount; + + from.history.add(tx); + to.history.add(tx); + + Profile toProf = null; + Profile fromProf = null; + try{ + fromProf = Profile.get_profile_of(from.player_id.toString()); + }catch(UserProfileNotYetExistsException e){ + e.printStackTrace(); + } + try { + toProf = Profile.get_profile_of(to.player_id.toString()); + } catch (UserProfileNotYetExistsException e) { + e.printStackTrace(); + } + + if(!from.isValidPlayer()) + { + fromProf = Profile.SYSTEM; + } + + if(!to.isValidPlayer()) + { + toProf = Profile.SYSTEM; + } + + if(from.isValidPlayer()) + ChatHelpers.broadcastTo(from.player_id, ChatHelpers.macro("!Dark_Gray![!Dark_Blue!Bank!Dark_Gray!] !Dark_Green!You sent !White!${0} !Dark_green!to {1}", String.valueOf(tx.amount), toProf.name_color+toProf.nickname), LibZontreck.THE_SERVER); + + if(to.isValidPlayer()) + ChatHelpers.broadcastTo(from.player_id, ChatHelpers.macro("!Dark_Gray![!Dark_Blue!Bank!Dark_Gray!] {0} !Dark_Green!paid you ${1}", String.valueOf(tx.amount), toProf.name_color+toProf.nickname), LibZontreck.THE_SERVER); + + if(to.isValidPlayer() && ServerUtilities.playerIsOffline(to.player_id)) Profile.unload(toProf); + if(from.isValidPlayer() && ServerUtilities.playerIsOffline(from.player_id)) + Profile.unload(fromProf); + + + EventBus.BUS.post(new WalletUpdatedEvent(from.player_id, fromOld, from.balance, tx)); + EventBus.BUS.post(new WalletUpdatedEvent(to.player_id, toOld, to.balance, tx)); + + if(from.isValidPlayer() && !ServerUtilities.playerIsOffline(from.player_id)) + { + ModMessages.sendToPlayer(new S2CWalletUpdatedPacket(from.player_id, tx, from.balance, fromOld), ServerUtilities.getPlayerByID(from.player_id.toString())); + } + if(to.isValidPlayer() && !ServerUtilities.playerIsOffline(to.player_id)) + { + ModMessages.sendToPlayer(new S2CWalletUpdatedPacket(to.player_id, tx, to.balance, toOld), ServerUtilities.getPlayerByID(to.player_id.toString())); + } + + instance.commit(); + + } + return true; + + } + + /** + * This event is fired when wallets get updated. It cannot be cancelled + * @param ev The event containing the player ID and new+old wallet data + */ + @Subscribe + public static void onWalletUpdate(WalletUpdatedEvent ev) + { + + } +} diff --git a/src/main/java/dev/zontreck/libzontreck/currency/CurrencyHelper.java b/src/main/java/dev/zontreck/libzontreck/currency/CurrencyHelper.java index 8dc1168..16c73bf 100644 --- a/src/main/java/dev/zontreck/libzontreck/currency/CurrencyHelper.java +++ b/src/main/java/dev/zontreck/libzontreck/currency/CurrencyHelper.java @@ -1,14 +1,7 @@ package dev.zontreck.libzontreck.currency; import dev.zontreck.ariaslib.events.annotations.Subscribe; -import dev.zontreck.libzontreck.currency.events.CurrencyBalanceCheckEvent; - -import java.util.List; public class CurrencyHelper { - @Subscribe - public static void onCurrencyBalanceCheck(CurrencyBalanceCheckEvent ev) - { - } } diff --git a/src/main/java/dev/zontreck/libzontreck/currency/LongTermTransactionHistoryRecord.java b/src/main/java/dev/zontreck/libzontreck/currency/LongTermTransactionHistoryRecord.java new file mode 100644 index 0000000..ccfb2e0 --- /dev/null +++ b/src/main/java/dev/zontreck/libzontreck/currency/LongTermTransactionHistoryRecord.java @@ -0,0 +1,72 @@ +package dev.zontreck.libzontreck.currency; + +import dev.zontreck.libzontreck.LibZontreck; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.Tag; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class LongTermTransactionHistoryRecord +{ + public static final Path BASE; + static{ + BASE = LibZontreck.BASE_CONFIG.resolve("transaction_history"); + if(!BASE.toFile().exists()) + { + BASE.toFile().mkdir(); + } + } + public static Path ofPath(String name) + { + return BASE.resolve(name); + } + public void commit() + { + ListTag txs = new ListTag(); + for(Transaction tx : history) + { + txs.add(tx.save()); + } + CompoundTag tag = new CompoundTag(); + tag.put("history", txs); + try { + NbtIo.write(tag, ofPath(player_id.toString()+".nbt").toFile()); + + }catch(IOException e){} + } + public UUID player_id; + + public List history; + private LongTermTransactionHistoryRecord(UUID ID) + { + player_id=ID; + try { + CompoundTag tag = NbtIo.read(ofPath(ID.toString()+".nbt").toFile()); + ListTag hist = tag.getList("history", Tag.TAG_COMPOUND); + history = new ArrayList<>(); + for(Tag t : hist){ + history.add(new Transaction((CompoundTag) t)); + } + } catch (IOException e) { + history = new ArrayList<>(); + } + } + + public void addHistory(List other) + { + for (Transaction tx : other) + { + history.add(tx); + } + } + public static LongTermTransactionHistoryRecord of(UUID ID) + { + return new LongTermTransactionHistoryRecord(ID); + } +} diff --git a/src/main/java/dev/zontreck/libzontreck/currency/Transaction.java b/src/main/java/dev/zontreck/libzontreck/currency/Transaction.java new file mode 100644 index 0000000..ff8941c --- /dev/null +++ b/src/main/java/dev/zontreck/libzontreck/currency/Transaction.java @@ -0,0 +1,42 @@ +package dev.zontreck.libzontreck.currency; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; + +import java.util.Date; + +public class Transaction +{ + public AccountReference from; + public AccountReference to; + public int amount; + public long timestamp; + + + public CompoundTag save() + { + CompoundTag tag = new CompoundTag(); + tag.put("from", NbtUtils.createUUID(from.id)); + tag.put("to", NbtUtils.createUUID(to.id)); + tag.putInt("amount", amount); + tag.putLong("timestamp", timestamp); + + return tag; + } + + public Transaction(CompoundTag tag) + { + from = new AccountReference(NbtUtils.loadUUID(tag.get("from"))); + to = new AccountReference(NbtUtils.loadUUID(tag.get("to"))); + amount = tag.getInt("amount"); + timestamp = tag.getLong("timestamp"); + } + + public Transaction(Account from, Account to, int amount, long ts) + { + this.from = from.getRef(); + this.to = to.getRef(); + this.amount=amount; + timestamp = ts; + } +} diff --git a/src/main/java/dev/zontreck/libzontreck/currency/events/BankAccountCreatedEvent.java b/src/main/java/dev/zontreck/libzontreck/currency/events/BankAccountCreatedEvent.java new file mode 100644 index 0000000..0b65f89 --- /dev/null +++ b/src/main/java/dev/zontreck/libzontreck/currency/events/BankAccountCreatedEvent.java @@ -0,0 +1,19 @@ +package dev.zontreck.libzontreck.currency.events; + + +import dev.zontreck.ariaslib.events.Event; +import dev.zontreck.libzontreck.currency.Account; + +public class BankAccountCreatedEvent extends Event +{ + public Account account; + public BankAccountCreatedEvent(Account act) + { + account=act; + } + + @Override + public boolean isCancellable() { + return false; + } +} diff --git a/src/main/java/dev/zontreck/libzontreck/currency/events/BankReadyEvent.java b/src/main/java/dev/zontreck/libzontreck/currency/events/BankReadyEvent.java new file mode 100644 index 0000000..a3e07b1 --- /dev/null +++ b/src/main/java/dev/zontreck/libzontreck/currency/events/BankReadyEvent.java @@ -0,0 +1,17 @@ +package dev.zontreck.libzontreck.currency.events; + +import dev.zontreck.ariaslib.events.Event; + +/** + * Contains no information by itself, it only signals that the Bank is open for business + * + * @see dev.zontreck.libzontreck.currency.Bank + */ +public class BankReadyEvent extends Event +{ + + @Override + public boolean isCancellable() { + return false; + } +} diff --git a/src/main/java/dev/zontreck/libzontreck/currency/events/CurrencyBalanceCheckEvent.java b/src/main/java/dev/zontreck/libzontreck/currency/events/CurrencyBalanceCheckEvent.java deleted file mode 100644 index dc857f2..0000000 --- a/src/main/java/dev/zontreck/libzontreck/currency/events/CurrencyBalanceCheckEvent.java +++ /dev/null @@ -1,20 +0,0 @@ -package dev.zontreck.libzontreck.currency.events; - -import dev.zontreck.ariaslib.events.Event; -import net.minecraft.world.entity.player.Player; - - -public class CurrencyBalanceCheckEvent extends Event -{ - public final Player player; - public String balance; - - public CurrencyBalanceCheckEvent(Player player) - { - this.player=player; - } - @Override - public boolean isCancellable() { - return false; - } -} diff --git a/src/main/java/dev/zontreck/libzontreck/currency/events/TransactionEvent.java b/src/main/java/dev/zontreck/libzontreck/currency/events/TransactionEvent.java new file mode 100644 index 0000000..455b55a --- /dev/null +++ b/src/main/java/dev/zontreck/libzontreck/currency/events/TransactionEvent.java @@ -0,0 +1,26 @@ +package dev.zontreck.libzontreck.currency.events; + +import dev.zontreck.ariaslib.events.Event; +import dev.zontreck.libzontreck.currency.Transaction; + +import java.util.List; + +public class TransactionEvent extends Event +{ + public Transaction tx; + + /** + * This is the list of reasons why a transaction was aborted or blocked + */ + public List reasons; + + public TransactionEvent(Transaction txNew) + { + tx=txNew; + } + + @Override + public boolean isCancellable() { + return true; + } +} diff --git a/src/main/java/dev/zontreck/libzontreck/currency/events/TransactionHistoryFlushEvent.java b/src/main/java/dev/zontreck/libzontreck/currency/events/TransactionHistoryFlushEvent.java new file mode 100644 index 0000000..38fb5e9 --- /dev/null +++ b/src/main/java/dev/zontreck/libzontreck/currency/events/TransactionHistoryFlushEvent.java @@ -0,0 +1,27 @@ +package dev.zontreck.libzontreck.currency.events; + +import dev.zontreck.ariaslib.events.Event; +import dev.zontreck.libzontreck.currency.Account; +import dev.zontreck.libzontreck.currency.LongTermTransactionHistoryRecord; +import dev.zontreck.libzontreck.currency.Transaction; + +import java.util.List; + +public class TransactionHistoryFlushEvent extends Event +{ + public LongTermTransactionHistoryRecord txHistory; + public Account associatedAccount; + public List flushed; + + public TransactionHistoryFlushEvent(Account act, LongTermTransactionHistoryRecord txHistory, List flushed) + { + associatedAccount=act; + this.txHistory=txHistory; + this.flushed=flushed; + } + + @Override + public boolean isCancellable() { + return false; + } +} diff --git a/src/main/java/dev/zontreck/libzontreck/currency/events/WalletSyncEvent.java b/src/main/java/dev/zontreck/libzontreck/currency/events/WalletSyncEvent.java new file mode 100644 index 0000000..5200ac3 --- /dev/null +++ b/src/main/java/dev/zontreck/libzontreck/currency/events/WalletSyncEvent.java @@ -0,0 +1,25 @@ +package dev.zontreck.libzontreck.currency.events; + +import dev.zontreck.libzontreck.currency.Account; +import dev.zontreck.libzontreck.currency.Bank; +import net.minecraftforge.eventbus.api.Event; + +import java.util.UUID; + +/** + * This event is not cancellable!! + */ +public class WalletSyncEvent extends Event +{ + public Account walletInformation; + + public WalletSyncEvent(UUID player) + { + walletInformation = Bank.getAccount(player); + } + + public WalletSyncEvent(Account act) + { + walletInformation = act; + } +} diff --git a/src/main/java/dev/zontreck/libzontreck/currency/events/WalletUpdatedEvent.java b/src/main/java/dev/zontreck/libzontreck/currency/events/WalletUpdatedEvent.java new file mode 100644 index 0000000..9608a2c --- /dev/null +++ b/src/main/java/dev/zontreck/libzontreck/currency/events/WalletUpdatedEvent.java @@ -0,0 +1,30 @@ +package dev.zontreck.libzontreck.currency.events; + +import dev.zontreck.ariaslib.events.Event; +import dev.zontreck.libzontreck.currency.Transaction; +import net.minecraft.world.entity.player.Player; + +import java.util.UUID; + +/** + * This event is dispatched on both the Client and the Server + */ +public class WalletUpdatedEvent extends Event +{ + public int newBal; + public int oldBal; + public UUID player; + public Transaction tx; + + public WalletUpdatedEvent(UUID player, int old, int newBal, Transaction tx) + { + this.player = player; + this.oldBal = old; + this.newBal = newBal; + this.tx=tx; + } + @Override + public boolean isCancellable() { + return false; + } +} diff --git a/src/main/java/dev/zontreck/libzontreck/events/ForgeEventHandlers.java b/src/main/java/dev/zontreck/libzontreck/events/ForgeEventHandlers.java index 147ff6c..767c3fc 100644 --- a/src/main/java/dev/zontreck/libzontreck/events/ForgeEventHandlers.java +++ b/src/main/java/dev/zontreck/libzontreck/events/ForgeEventHandlers.java @@ -1,11 +1,13 @@ package dev.zontreck.libzontreck.events; -import dev.zontreck.ariaslib.events.Event; import dev.zontreck.ariaslib.events.EventBus; import dev.zontreck.ariaslib.util.DelayedExecutorService; import dev.zontreck.libzontreck.LibZontreck; -import dev.zontreck.libzontreck.currency.events.CurrencyBalanceCheckEvent; +import dev.zontreck.libzontreck.currency.Account; +import dev.zontreck.libzontreck.currency.Bank; import dev.zontreck.libzontreck.memory.PlayerContainer; +import dev.zontreck.libzontreck.networking.ModMessages; +import dev.zontreck.libzontreck.networking.packets.S2CWalletInitialSyncPacket; import dev.zontreck.libzontreck.profiles.Profile; import dev.zontreck.libzontreck.profiles.UserProfileNotYetExistsException; import net.minecraft.server.level.ServerLevel; @@ -53,8 +55,8 @@ public class ForgeEventHandlers { DelayedExecutorService.getInstance().schedule(new Runnable() { @Override public void run() { - CurrencyBalanceCheckEvent event= new CurrencyBalanceCheckEvent(ev.getEntity()); - EventBus.BUS.post(event); + // Check player wallet, then send wallet to client + ModMessages.sendToPlayer(new S2CWalletInitialSyncPacket(player.getUUID()), player); } }, 10); } diff --git a/src/main/java/dev/zontreck/libzontreck/networking/ModMessages.java b/src/main/java/dev/zontreck/libzontreck/networking/ModMessages.java index f32449c..624682d 100644 --- a/src/main/java/dev/zontreck/libzontreck/networking/ModMessages.java +++ b/src/main/java/dev/zontreck/libzontreck/networking/ModMessages.java @@ -12,19 +12,20 @@ import net.minecraftforge.network.NetworkRegistry; import net.minecraftforge.network.PacketDistributor; import net.minecraftforge.network.simple.SimpleChannel; +import java.util.concurrent.atomic.AtomicInteger; + /** * Networking system! */ public class ModMessages { private static SimpleChannel INSTANCE; - private static int PACKET_ID=0; /** - * INTERNAL USE ONLY. DO NOT USE THIS, IF YOU ARE NOT LIBZONTRECK!!!!!! - * @return + * INTERNAL USE ONLY */ + private static AtomicInteger PACKET_ID=new AtomicInteger(0); public static int id() { - return PACKET_ID++; + return PACKET_ID.getAndIncrement(); } public static void register() { @@ -44,12 +45,13 @@ public class ModMessages { packet.register(net); } - net.messageBuilder(ChestGUIOpenC2S.class, id(), NetworkDirection.PLAY_TO_SERVER) + net.messageBuilder(ChestGUIOpenC2S.class, PACKET_ID.getAndIncrement(), NetworkDirection.PLAY_TO_SERVER) .decoder(ChestGUIOpenC2S::new) .encoder(ChestGUIOpenC2S::toBytes) - .consumer(ChestGUIOpenC2S::handle) + .consumerMainThread(ChestGUIOpenC2S::handle) .add(); + } diff --git a/src/main/java/dev/zontreck/libzontreck/networking/NetworkEvents.java b/src/main/java/dev/zontreck/libzontreck/networking/NetworkEvents.java new file mode 100644 index 0000000..ad473f9 --- /dev/null +++ b/src/main/java/dev/zontreck/libzontreck/networking/NetworkEvents.java @@ -0,0 +1,18 @@ +package dev.zontreck.libzontreck.networking; + +import dev.zontreck.libzontreck.events.RegisterPacketsEvent; +import dev.zontreck.libzontreck.networking.packets.S2CPlaySoundPacket; +import dev.zontreck.libzontreck.networking.packets.S2CWalletInitialSyncPacket; +import dev.zontreck.libzontreck.networking.packets.S2CWalletUpdatedPacket; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +public class NetworkEvents +{ + @SubscribeEvent + public void onRegisterPackets(RegisterPacketsEvent ev) + { + ev.packets.add(new S2CWalletUpdatedPacket()); + ev.packets.add(new S2CPlaySoundPacket()); + ev.packets.add(new S2CWalletInitialSyncPacket()); + } +} diff --git a/src/main/java/dev/zontreck/libzontreck/networking/packets/S2CPlaySoundPacket.java b/src/main/java/dev/zontreck/libzontreck/networking/packets/S2CPlaySoundPacket.java index 0b5f17e..4d79616 100644 --- a/src/main/java/dev/zontreck/libzontreck/networking/packets/S2CPlaySoundPacket.java +++ b/src/main/java/dev/zontreck/libzontreck/networking/packets/S2CPlaySoundPacket.java @@ -6,6 +6,7 @@ import dev.zontreck.libzontreck.util.BinUtil; import dev.zontreck.libzontreck.util.ServerUtilities; import net.minecraft.client.Minecraft; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvent; @@ -25,17 +26,15 @@ public class S2CPlaySoundPacket implements IPacket public S2CPlaySoundPacket(ResourceLocation loc) { sound=loc; } + public S2CPlaySoundPacket(){} @Override public void deserialize(CompoundTag data) { - // Deserializes the play sound packet - throw new UnsupportedOperationException("This operation is not supported in the play sound packet!"); + } @Override public void serialize(CompoundTag data) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'serialize'"); } @Override diff --git a/src/main/java/dev/zontreck/libzontreck/networking/packets/S2CWalletInitialSyncPacket.java b/src/main/java/dev/zontreck/libzontreck/networking/packets/S2CWalletInitialSyncPacket.java new file mode 100644 index 0000000..f8bf3f4 --- /dev/null +++ b/src/main/java/dev/zontreck/libzontreck/networking/packets/S2CWalletInitialSyncPacket.java @@ -0,0 +1,70 @@ +package dev.zontreck.libzontreck.networking.packets; + +import dev.zontreck.libzontreck.currency.Account; +import dev.zontreck.libzontreck.currency.Bank; +import dev.zontreck.libzontreck.currency.events.WalletSyncEvent; +import dev.zontreck.libzontreck.util.ServerUtilities; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.EventBus; +import net.minecraftforge.network.NetworkDirection; +import net.minecraftforge.network.NetworkEvent; +import net.minecraftforge.network.simple.SimpleChannel; + +import java.util.UUID; +import java.util.function.Supplier; + +public class S2CWalletInitialSyncPacket implements IPacket +{ + public Account act; + public S2CWalletInitialSyncPacket(FriendlyByteBuf buf) + { + act = new Account(buf.readNbt()); + } + public S2CWalletInitialSyncPacket(Account act) + { + this.act=act; + } + public S2CWalletInitialSyncPacket(UUID ID) + { + this.act= Bank.getAccount(ID); + } + public S2CWalletInitialSyncPacket(){} + + @Override + public void deserialize(CompoundTag data) { + + } + + @Override + public void serialize(CompoundTag data) { + + } + + @Override + public void toBytes(FriendlyByteBuf buf) { + buf.writeNbt(act.save()); + } + + @Override + public boolean handle(Supplier supplier) { + return ServerUtilities.handlePacket(supplier, new Runnable() { + @Override + public void run() { + MinecraftForge.EVENT_BUS.post(new WalletSyncEvent(act)); + + } + }); + } + + @Override + public NetworkDirection getDirection() { + return NetworkDirection.PLAY_TO_CLIENT; + } + + @Override + public void register(SimpleChannel chan) { + ServerUtilities.registerPacket(chan, S2CWalletInitialSyncPacket.class, this, S2CWalletInitialSyncPacket::new); + } +} diff --git a/src/main/java/dev/zontreck/libzontreck/networking/packets/S2CWalletUpdatedPacket.java b/src/main/java/dev/zontreck/libzontreck/networking/packets/S2CWalletUpdatedPacket.java new file mode 100644 index 0000000..cb731bd --- /dev/null +++ b/src/main/java/dev/zontreck/libzontreck/networking/packets/S2CWalletUpdatedPacket.java @@ -0,0 +1,80 @@ +package dev.zontreck.libzontreck.networking.packets; + +import dev.zontreck.ariaslib.events.EventBus; +import dev.zontreck.libzontreck.currency.Transaction; +import dev.zontreck.libzontreck.currency.events.WalletUpdatedEvent; +import dev.zontreck.libzontreck.util.ServerUtilities; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.network.NetworkDirection; +import net.minecraftforge.network.NetworkEvent; +import net.minecraftforge.network.simple.SimpleChannel; + +import java.util.UUID; +import java.util.function.Supplier; + +public class S2CWalletUpdatedPacket implements IPacket +{ + public UUID ID; + public Transaction tx; + public int balance; + public int oldBal; + + public S2CWalletUpdatedPacket(FriendlyByteBuf buf) + { + ID = buf.readUUID(); + tx = new Transaction(buf.readNbt()); + balance = buf.readInt(); + oldBal = buf.readInt(); + } + + public S2CWalletUpdatedPacket(UUID ID, Transaction tx, int bal, int old) + { + this.ID= ID; + this.tx=tx; + this.balance=bal; + oldBal=old; + } + + public S2CWalletUpdatedPacket(){} + + + @Override + public void deserialize(CompoundTag data) { + + } + + @Override + public void serialize(CompoundTag data) { + + } + + @Override + public void toBytes(FriendlyByteBuf buf) { + buf.writeUUID(ID); + buf.writeNbt(tx.save()); + buf.writeInt(balance); + buf.writeInt(oldBal); + } + + @Override + public boolean handle(Supplier supplier) { + return ServerUtilities.handlePacket(supplier, new Runnable() { + @Override + public void run() { + EventBus.BUS.post(new WalletUpdatedEvent(ID, oldBal, balance, tx)); + + } + }); + } + + @Override + public NetworkDirection getDirection() { + return NetworkDirection.PLAY_TO_CLIENT; + } + + @Override + public void register(SimpleChannel chan) { + ServerUtilities.registerPacket(chan, S2CWalletUpdatedPacket.class, this, S2CWalletUpdatedPacket::new); + } +} diff --git a/src/main/java/dev/zontreck/libzontreck/profiles/Profile.java b/src/main/java/dev/zontreck/libzontreck/profiles/Profile.java index 6b9b78a..0ce7493 100644 --- a/src/main/java/dev/zontreck/libzontreck/profiles/Profile.java +++ b/src/main/java/dev/zontreck/libzontreck/profiles/Profile.java @@ -27,11 +27,14 @@ public class Profile { public Boolean flying; public int available_vaults; public int deaths; + + public ServerPlayer player; private File accessor; private CompoundTag miscData; public static final Path BASE; + public static final Profile SYSTEM; static{ BASE = LibZontreck.BASE_CONFIG.resolve("profiles"); if(!BASE.toFile().exists()) @@ -44,6 +47,8 @@ public class Profile { LibZontreck.LOGGER.error("Failed to create profiles base directory"); } } + + SYSTEM = new Profile("SYSTEM", "", "SYSTEM", ChatColor.DARK_RED, LibZontreck.NULL_ID.toString(), "", "", false, 0, null, 0, null, null); } public Profile(String username, String prefix, String nickname, String name_color, String ID, String prefix_color, String chat_color, Boolean isFlying, int vaults, File vaultFile, int deathCount, ServerPlayer player, CompoundTag misc) { diff --git a/src/main/java/dev/zontreck/libzontreck/util/ChatHelpers.java b/src/main/java/dev/zontreck/libzontreck/util/ChatHelpers.java index fb0859d..511f65e 100644 --- a/src/main/java/dev/zontreck/libzontreck/util/ChatHelpers.java +++ b/src/main/java/dev/zontreck/libzontreck/util/ChatHelpers.java @@ -45,6 +45,9 @@ public class ChatHelpers { public void run() { ServerPlayer play = server.getPlayerList().getPlayer(ID); + if(play==null)return; + + play.displayClientMessage(message, actionBar); LibZontreck.LOGGER.info("[SERVER] -> ["+play.getName().getContents()+"] "+message.getContents()); diff --git a/src/main/java/dev/zontreck/libzontreck/util/ServerUtilities.java b/src/main/java/dev/zontreck/libzontreck/util/ServerUtilities.java index 342e222..be9cadb 100644 --- a/src/main/java/dev/zontreck/libzontreck/util/ServerUtilities.java +++ b/src/main/java/dev/zontreck/libzontreck/util/ServerUtilities.java @@ -5,6 +5,7 @@ import java.util.function.Function; import java.util.function.Supplier; import dev.zontreck.libzontreck.LibZontreck; +import dev.zontreck.libzontreck.exceptions.InvalidSideException; import dev.zontreck.libzontreck.networking.ModMessages; import dev.zontreck.libzontreck.networking.packets.IPacket; import net.minecraft.network.FriendlyByteBuf; @@ -39,7 +40,7 @@ public class ServerUtilities channel.messageBuilder(type, ModMessages.id(), packet.getDirection()) .decoder(decoder) .encoder(X::toBytes) - .consumer(X::handle) + .consumerMainThread(X::handle) .add(); } @@ -74,4 +75,11 @@ public class ServerUtilities { return !isServer(); } + + public static boolean playerIsOffline(UUID ID) throws InvalidSideException { + if(isClient())throw new InvalidSideException("This can only be called on the server"); + + if(LibZontreck.THE_SERVER.getPlayerList().getPlayer(ID) == null) return true; + else return false; + } } \ No newline at end of file