[BANKING] Some tested code that finally works for banking stuff. Much to go still, but more honed in. So much to do :(
Some checks are pending
build / build (21) (push) Waiting to run

This commit is contained in:
Jkibbels 2024-11-09 23:21:21 -05:00
parent 87afc5c8ab
commit a42d196c3c
7 changed files with 429 additions and 268 deletions

View File

@ -28,16 +28,24 @@ public class AccountNumberGenerator {
// Callers of this function are required to verify the given number is unique.
public static String GenerateNewAccountNumber(String symbol, Integer routingNumber, Integer accountType, String username) {
String generatedAccountNumber = symbol + "-" + routingNumber + "-" + accountType + "-";
String generatedAccountNumber = symbol + "-" + routingNumber + "-" + accountType;
// Block to translate part of username into number format
for (int i = 0; i < 3; i++) {
if (username.length() >= 3 && username.charAt(i) <= 255) { // 255 is largest ASCII value. Might be a sloppy check; can always test later (if I find someone with non ASCII)
generatedAccountNumber += (int) username.charAt(i);
Integer asciiValueOfLetter = (int) username.charAt(i);
String strValueOfAscii = asciiValueOfLetter.toString();
strValueOfAscii = strValueOfAscii.substring(0, 1);
generatedAccountNumber += strValueOfAscii;
} else if (username.charAt(i) <= 255) { // Case where length is less than 3 but is still in ASCII table
generatedAccountNumber += (int) username.charAt(i);
Integer asciiValueOfLetter = (int) username.charAt(i);
String strValueOfAscii = asciiValueOfLetter.toString();
strValueOfAscii = strValueOfAscii.substring(0, 1);
generatedAccountNumber += strValueOfAscii;
} else { // Case where the length is less than 3 and is not standard ASCII
generatedAccountNumber += '0';
generatedAccountNumber += "0";
}
}
@ -59,11 +67,11 @@ public class AccountNumberGenerator {
return Integer.parseInt(accountId.substring(5, 9));
}
public static Integer GetAccountNumberFromId(String accountId) {
return Integer.parseInt(accountId.substring(10, accountId.length()));
public static String GetAccountNumberFromId(String accountId) {
return accountId.substring(10);
}
public static Integer GetAccountTypeFromId(String accountId) {
return (int) accountId.charAt(10);
return ((int) accountId.charAt(10)) - 48; // ASCII 0 starts at 48. One must subtract 48 to be correct.
}
}

View File

@ -1,30 +1,110 @@
package jesse.keeblarcraft.BankMgr;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Map.Entry;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
// The bank manager takes care of routing any and all transactions throughout the server.
// It is a singleton object that is active throughout the mods lifetime and will cache players accounts
// when they log in to avoid constant look-ups through JSON (TODO for this).
//
public class BankManager {
// when they log in to avoid constant look-ups through JSON.
public final class BankManager {
private static BankManager static_inst;
public static BankManager GetInstance() {
if (static_inst == null) {
static_inst = new BankManager();
}
return static_inst;
}
private static Integer KEEBLARCRAFT_SERVER_BANK_ID = 1000;
ConfigManager config = new ConfigManager();
private HashMap<Integer, IndividualBank> banks = new HashMap<Integer, IndividualBank>();
private HashMap<String, Integer> bankNameFastMap = new HashMap<String, Integer>();
// Contains all account information for a given bank
private class BankAccountInformation {
public BankManager() {}
public void InitializeBanks() {
banks.put(KEEBLARCRAFT_SERVER_BANK_ID, new IndividualBank(Integer.toString(KEEBLARCRAFT_SERVER_BANK_ID), "KeeblarcraftGlobal"));
// Initialize fast map
for (Entry<Integer, IndividualBank> bank : banks.entrySet()) {
bankNameFastMap.put(bank.getValue().GetBankName(), bank.getValue().GetRoutingNumber());
}
}
// Structure of all the players banking information across all banks.
private class PlayerFinances {
public List<String> GetAllBankNames() {
List<String> names = new ArrayList<String>();
// Key = Bank UUID
// Value = The account information for THIS player
HashMap<String, BankAccountInformation> allBanks;
// Iterate through all banks in the list to get their names
for (Entry<Integer, IndividualBank> bank : banks.entrySet()) {
names.add(bank.getValue().GetBankName());
}
return names;
}
public BankManager() {
public IndividualBank GetBankByRoutingNumber(Integer number) {
IndividualBank bank = null;
if (banks.containsKey(number)) {
bank = banks.get(number);
}
return bank;
}
public IndividualBank GetBankByName(String name) {
IndividualBank bank = null;
System.out.println("GetBankByName called with value " + name);
if (bankNameFastMap.containsKey(name)) {
System.out.println("Value of bank with name is " + bankNameFastMap.get(name));
System.out.println("Banks map size is " + banks.size());
bank = banks.get(bankNameFastMap.get(name));
}
System.out.println("Returning bank information");
return bank;
}
public void InitiateBankAccountCreation(String bankIdentifier, ServerPlayerEntity player, String accountType) {
Boolean success = false;
System.out.println("initiating bank creation");
boolean defaultServerBank = bankIdentifier == null || bankIdentifier == "";
System.out.println("value of bankIdentifier is " + defaultServerBank);
System.out.println("The player name is " + player.getDisplayName().getString());
// DEBUG
System.out.println("BANK NAME: " + banks.get(KEEBLARCRAFT_SERVER_BANK_ID).GetBankName());
System.out.println("BANK BALANCE: " + banks.get(KEEBLARCRAFT_SERVER_BANK_ID).GetBankBalance());
// DEBUG END
// Create an account via the server-owned bank account
if (defaultServerBank) {
success = banks.get(KEEBLARCRAFT_SERVER_BANK_ID).CreateAccount(player.getUuidAsString(), player.getDisplayName().getString(), accountType);
} else {
System.out.println("Creating bank on non-server owned bank");
// Create an account via a specified bank identifier
Integer routingNumber = Integer.parseInt(bankIdentifier);
if (banks.containsKey(routingNumber)) {
banks.get(routingNumber).CreateAccount(player.getUuidAsString(), player.getDisplayName().getString(), accountType);
} else {
player.sendMessage(Text.of("That bank does not exist"));
}
}
if (success) {
player.sendMessage(Text.of("The banking operation was successful and your banking information has been updated"));
} else {
player.sendMessage(Text.of("The banking operating FAILED. You may need to visit the bank for more information!"));
}
}
}

View File

@ -6,32 +6,44 @@ import java.util.List;
// TODO: Add ability to store NBT data of items in the future so we can store not just money but items too
// like a safety deposit box
public class IndividualAccount {
private Integer accountNumber;
private String accountNumber;
private String accountNumberAlias;
private Integer routingNumber; // Will always be the bank it's in
private List<String> accountHolders;
private List<String> accountHolderUuids;
private Integer accountBalance;
private Boolean allowNegativeBalance;
private Boolean accountLocked;
private String accountType; // TODO: Replace with enum in future. Valid is "checking" and "savings" right now
private Integer accountType; // TODO: Replace with enum in future. Valid is "checking" and "savings" right now
public IndividualAccount() {}
public IndividualAccount(Integer accountNumber, Integer routingNumber, List<String> holders,
Boolean allowNegativeBalance, Integer initialBalance, String alias) {
public IndividualAccount(String accountNumber, Integer routingNumber, List<String> holders,
List<String> accountHolderUuids, Boolean allowNegativeBalance, Integer initialBalance,
String alias, Integer accountType) {
System.out.println("Called to create new IndividualAccount with following values: " + accountNumber + " " + routingNumber + " " + holders + " " +
accountHolderUuids + " " + allowNegativeBalance + " " + initialBalance + " " + alias + " " + accountType);
this.accountNumber = accountNumber;
this.routingNumber = routingNumber;
this.accountHolders = holders;
this.accountHolderUuids = accountHolderUuids;
this.allowNegativeBalance = allowNegativeBalance;
this.accountBalance = initialBalance;
this.accountNumberAlias = alias;
this.accountType = accountType;
}
public void AddAccountHolder(String newHolder) {
// TODO: Make this a map in the future
public void AddAccountHolder(String newHolder, String newHolderUuid) {
if (!accountHolders.contains(newHolder)) {
accountHolders.add(newHolder);
}
if (!accountHolderUuids.contains(newHolderUuid)) {
accountHolderUuids.add(newHolderUuid);
}
}
public void AliasAccount(String newAlias) {
@ -106,7 +118,7 @@ public class IndividualAccount {
return accountBalance;
}
public Integer GetAccountNumber() {
public String GetAccountNumber() {
return accountNumber;
}

View File

@ -1,12 +1,19 @@
package jesse.keeblarcraft.BankMgr;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import static java.util.Map.entry;
import java.io.File;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.Utils.ChatUtil;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR;
import jesse.keeblarcraft.Utils.CustomExceptions.FILE_WRITE_EXCEPTION;
// Contains the information of an individual bank
//
@ -18,12 +25,12 @@ public class IndividualBank {
entry("savings", 1)
);
ConfigManager config = new ConfigManager();
private ConfigManager config = new ConfigManager();
private Integer routingNumber; // this is the banks unique identifier
private Integer numberOfAccounts; // Total number of accounts the bank has. This includes only active accounts inside accountsList.
private String bankFourLetterIdentifier;
private Integer maxBankAccounts = 100_000_000; // Making this simple for myself any one type of account has 8 random numbers genereated so 10^8 possible accounts
private String bankFourLetterIdentifier;
private String registeredBankName;
// Think FDIC but from the servers account (keeblarcraft insurance corporation)
// KBIC will ensure an amount of money based on its trustworthiness to a bank and the number of holders it has.
@ -37,87 +44,207 @@ public class IndividualBank {
// Key = ACCOUNT NUMBER
// Value = ACCOUNT
private HashMap<Integer, IndividualAccount> accountsList;
private HashMap<String, List<Integer>> accountsListFromName; // This is a list that just points to a list of account numbers by person. USEFUL
private class Accounts {
private HashMap<String, IndividualAccount> accountsList = new HashMap<String, IndividualAccount>();
private HashMap<String, List<String>> accountsListFromName = new HashMap<String, List<String>>(); // This is a list that just points to a list of account numbers by person. USEFUL
}
Accounts accounts;
private List<String> lockedUsers; // A list of users who are locked out of the bank and are incapable of performing more actions within it
public IndividualBank(String routingNumber) {
accountsList = new HashMap<Integer, IndividualAccount>();
accountsListFromName = new HashMap<String, List<Integer>>();
// READ IN BANK CONFIG
public IndividualBank(String routingNumber, String nameOfBank) {
accounts = new Accounts();
lockedUsers = new ArrayList<String>();
registeredBankName = nameOfBank.toUpperCase();
bankFourLetterIdentifier = nameOfBank.substring(0, 4).toLowerCase();
this.routingNumber = Integer.parseInt(routingNumber);
System.out.println("CREATING BANK ACCOUNT WITH ROUTING NUMBER " + routingNumber + " AND NAME " + nameOfBank);
boolean existingFile = false;
try {
// Read in the global accounts list
String accountsListDir = "bank/" + routingNumber.toString() + "/accounts/";
System.out.println("accountsListDir + bankName is " + accountsListDir + nameOfBank);
accounts = config.GetJsonObjectFromFile(accountsListDir + nameOfBank, Accounts.class);
existingFile = true;
// TODO: REPLACE WITH SQL SERVER. DIRTY ITERATE OVER ALL FILES IN DIRECTORY TO LOAD STRUCTURE
File dir = new File(accountsListDir);
File[] allFiles = dir.listFiles();
if (allFiles != null) {
for (File file : allFiles ) {
// First grab file identifier as KEY
String accountIdentifier = file.getName();
String accountFromFile = accountsListDir + "/" + accountIdentifier;
System.out.println("accountIdentifier found in file is " + accountIdentifier);
System.out.println("account identifier with dir path is " + accountFromFile);
accounts.accountsList.put(accountIdentifier, config.GetJsonObjectFromFile(accountFromFile, IndividualAccount.class));
}
}
} catch (Exception e) {
System.out.println("The try-catch in IndividualBank.java failed to complete. Printing stack trace");
// e.printStackTrace();
// Falling into this catch just means the file needs to be made
}
if (!existingFile)
{
System.out.println(ChatUtil.ColoredString("Trying to create new file", CONSOLE_COLOR.BLUE));
try {
// We assume the bank dir is created by server. Create this banks dir
config.CreateDirectory("bank/" + routingNumber);
// Create this banks initial accounts dir
config.CreateDirectory("bank/" + routingNumber + "/accounts");
// Flash initial account configuration file for this bank
FlashConfig("accounts");
} catch (Exception e) {
System.out.println(ChatUtil.ColoredString("Could not write to file", CONSOLE_COLOR.RED));
}
} else {
System.out.println(ChatUtil.ColoredString("Moving on", CONSOLE_COLOR.BLUE));
}
// A modified config reader is needed here for when each IndividualAccount is read in - the name is taken from that and is attached to the
// 'accountsListFromName' structure. This makes it no worse than O(n) to fill these two structures in.
// NOTE: This is an *EXPENSIVE* operation! Future us might need to update this. Also note a method is needed for everytime a player opens a new account
// or gets put on one to update the map every time
for (Entry<Integer, IndividualAccount> account : accountsList.entrySet()) {
for (Entry<String, IndividualAccount> account : accounts.accountsList.entrySet()) {
// We must loop over the string of holders for each account as well to make the flattened accountsListFromName map
List<String> accountHolders = account.getValue().GetAccountHolders();
// Match each user to the secondary map & add to list-value if not existing
for (Integer holderIndex = 0; holderIndex < accountHolders.size(); holderIndex++) {
if (accountsListFromName.containsKey(accountHolders.get(holderIndex))) {
if (accounts.accountsListFromName.containsKey(accountHolders.get(holderIndex))) {
// Case 1: User exists, update map entry
accountsListFromName.get(accountHolders.get(holderIndex)).add(account.getKey()); // Add a new account id to this person in the new flat map
accounts.accountsListFromName.get(accountHolders.get(holderIndex)).add(account.getKey()); // Add a new account id to this person in the new flat map
} else {
// Case 2: User does not already exist; add a new map entry
accountsListFromName.put(accountHolders.get(holderIndex), List.of(account.getKey())); // Store name as key, and new List with the value of ACCOUNT #
accounts.accountsListFromName.put(accountHolders.get(holderIndex), List.of(account.getKey())); // Store name as key, and new List with the value of ACCOUNT #
}
}
}
numberOfAccounts = accounts.accountsList.size();
}
numberOfAccounts = accountsList.size();
public String GetBankName() {
return registeredBankName;
}
public List<IndividualAccount> GetAccountsOfUser(String uuid) {
System.out.println("UUID passed in: " + uuid);
List<IndividualAccount> accountsFromUser = new ArrayList<IndividualAccount>();
List<String> listOfAccounts = accounts.accountsListFromName.get(uuid);
System.out.println("Is list of accounts null? " + listOfAccounts == null);
if (listOfAccounts != null && listOfAccounts.size() > 0) {
for (int i = 0; i < listOfAccounts.size(); i++) {
accountsFromUser.add(accounts.accountsList.get(listOfAccounts.get(i)));
}
}
return accountsFromUser;
}
public Integer GetBankBalance() {
return bankMoney;
}
public void AddBankBalance(Integer amount) {
bankMoney += amount;
}
public void SubtractBankBalance(Integer amount) {
bankMoney -= amount;
}
public void SetBankBalance(Integer amount) {
bankMoney = amount;
}
public Boolean IsBankInsured() {
return kbicInsured;
}
public Integer InsuranceAmount() {
Integer insuredAmnt = 0;
if (kbicInsured) {
insuredAmnt = kbicInsuredAmount;
} else {
insuredAmnt = 0;
}
return insuredAmnt;
}
// Updates the regular bank account list & the fast-access bank account list
// NO values are allowed to be null. Manually update lists separately if that's the behaviour you want!
public void UpdateBankAccounts(String newHolderName, Integer accountIdentifier, IndividualAccount newAccountOnly) {
public void UpdateBankAccounts(String newHolderName, String newHolderUuid, String accountIdentifier, IndividualAccount newAccountOnly) {
// Update the fast-access map first
if (accountsListFromName.containsKey(newHolderName)) {
if (accounts.accountsListFromName.containsKey(newHolderName)) {
// Check if user is already in map
accountsListFromName.get(newHolderName).add(accountIdentifier);
System.out.println("User found in fast access map. Adding account identifier to fast-access map");
accounts.accountsListFromName.get(newHolderUuid).add(accountIdentifier);
} else {
// Add new entry to map
accountsListFromName.put(newHolderName, List.of(accountIdentifier));
System.out.println("User not found in fast access map. Adding completely new entry");
accounts.accountsListFromName.put(newHolderUuid, List.of(accountIdentifier));
}
// Update regular account list
if (accountsList.containsKey(accountIdentifier)) {
if (accounts.accountsList.containsKey(accountIdentifier)) {
// This path assumes we are adding a holder as opposed to adding an account (else, how else would this work?)
accountsList.get(accountIdentifier).AddAccountHolder(newHolderName);
System.out.println("Account found in accounts list, adding this person as a holder instead");
accounts.accountsList.get(accountIdentifier).AddAccountHolder(newHolderName, newHolderUuid);
} else {
// Non-existent account means a new one!
accountsList.put(accountIdentifier, newAccountOnly);
System.out.println("Brand new account creation, adding!");
accounts.accountsList.put(accountIdentifier, newAccountOnly);
numberOfAccounts++;
}
System.out.println("Flashing configuration file");
FlashConfig("bank/" + routingNumber + "/accounts");
}
public Boolean CreateAccount(String holderName, String accountTypeStr) {
public Integer GetRoutingNumber() {
return this.routingNumber;
}
public Boolean CreateAccount(String holderUuid, String holderName, String accountTypeStr) {
Boolean success = false;
if (accountsList.size() <= maxBankAccounts && ACCOUNT_TYPES.containsKey(accountTypeStr.toLowerCase())) {
System.out.println("Attempting to create new bank account given args UUID / NAME / TYPE : " + holderUuid + " " + holderName + " " + accountTypeStr);
System.out.println("accounts size is " + accounts.accountsList.size());
System.out.println("account string is { " + accountTypeStr + " }. Does this account type exist in this bank? => " + ACCOUNT_TYPES.containsKey(accountTypeStr.toLowerCase()));
if (accounts.accountsList.size() <= maxBankAccounts && ACCOUNT_TYPES.containsKey(accountTypeStr.toLowerCase())) {
// Verify this isn't a blacklisted user
System.out.println("Is user bank locked? " + lockedUsers.contains(holderName));
if (!lockedUsers.contains(holderName)) {
Integer maxAttempts = 1000; // Reasonably a unique bank account should pop up within 1000 generations. If not, the user may try again.
Integer maxAttempts = 15; // Reasonably a unique bank account should pop up within 1000 generations. If not, the user may try again.
String accountId = AccountNumberGenerator.GenerateNewAccountNumber(bankFourLetterIdentifier, routingNumber, ACCOUNT_TYPES.get(accountTypeStr), holderName);
System.out.println("Account generator came back with bank account id { " + accountId + " }");
System.out.println("4 letter bank: " + AccountNumberGenerator.GetFinancialSymbolFromId(accountId));
System.out.println("Routing: " + AccountNumberGenerator.GetRoutingNumberFromId(accountId));
System.out.println("Account type: " + AccountNumberGenerator.GetAccountTypeFromId(accountId));
System.out.println("RNG Account number: " + AccountNumberGenerator.GetAccountNumberFromId(accountId));
// TODO: Fix in future with a method that will guarentee a one-time necessary number generator. Statistically speaking; this will be okay for the
// entire life time of the server. BUT, you never know!
while (maxAttempts != 0 && !accountsList.containsKey(AccountNumberGenerator.GetAccountNumberFromId(accountId))) {
while (maxAttempts != 0 && !accounts.accountsList.containsKey(AccountNumberGenerator.GetAccountNumberFromId(accountId))) {
accountId = AccountNumberGenerator.GenerateNewAccountNumber(bankFourLetterIdentifier, routingNumber, ACCOUNT_TYPES.get(accountTypeStr), holderName);
System.out.println("Account generator came back with bank account id { " + accountId + " }");
maxAttempts--;
}
// Final check to add the account
Integer actualAccountNumber = AccountNumberGenerator.GetAccountNumberFromId(accountId);
if (!accountsList.containsKey(actualAccountNumber)) {
IndividualAccount newAccount = new IndividualAccount(actualAccountNumber, this.routingNumber, List.of(holderName), false, 0, "");
UpdateBankAccounts(holderName, actualAccountNumber, newAccount);
String actualAccountNumber = AccountNumberGenerator.GetAccountNumberFromId(accountId);
System.out.println("Bank account identifier is { " + actualAccountNumber + " }. Is this already an existing account? " + accounts.accountsList.containsKey(actualAccountNumber));
if (!accounts.accountsList.containsKey(actualAccountNumber)) {
IndividualAccount newAccount = new IndividualAccount(actualAccountNumber, this.routingNumber, List.of(holderName),
List.of(holderUuid), false, 0,
"", ACCOUNT_TYPES.get(accountTypeStr));
System.out.println("Updating accounts list for this bank");
UpdateBankAccounts(holderName, holderUuid, actualAccountNumber, newAccount);
success = true;
}
}
@ -126,9 +253,9 @@ public class IndividualBank {
}
public void AliasAccount(String accountId, String newAlias) {
Integer accountNumber = AccountNumberGenerator.GetAccountNumberFromId(accountId);
if (accountsList.containsKey(accountNumber)) {
accountsList.get(accountNumber).AliasAccount(newAlias);
String accountNumber = AccountNumberGenerator.GetAccountNumberFromId(accountId);
if (accounts.accountsList.containsKey(accountNumber)) {
accounts.accountsList.get(accountNumber).AliasAccount(newAlias);
}
}
@ -136,8 +263,8 @@ public class IndividualBank {
Boolean success = false;
Integer accountIter = 0;
for (Entry<String, List<Integer>> holderAccounts : accountsListFromName.entrySet()) {
accountsList.get(holderAccounts.getValue().get(accountIter++)).LockAccount();
for (Entry<String, List<String>> holderAccounts : accounts.accountsListFromName.entrySet()) {
accounts.accountsList.get(holderAccounts.getValue().get(accountIter++)).LockAccount();
}
return success;
}
@ -145,20 +272,53 @@ public class IndividualBank {
public Boolean CloseAccount(String accountId) {
Boolean success = false;
Integer accountNumber = AccountNumberGenerator.GetAccountNumberFromId(accountId);
String accountNumber = AccountNumberGenerator.GetAccountNumberFromId(accountId);
if (accountsList.get(accountNumber).GetAccountBalance() == 0) {
accountsList.remove(accountNumber);
if (accounts.accountsList.get(accountNumber).GetAccountBalance() == 0) {
accounts.accountsList.remove(accountNumber);
success = true;
}
return success;
}
public Boolean HasAccount(Integer accountIdentifier) {
public Boolean HasAccount(String accountIdentifier) {
Boolean containsAccount = false;
if (accountsList.containsKey(accountIdentifier)) {
if (accounts.accountsList.containsKey(accountIdentifier)) {
containsAccount = true;
}
return containsAccount;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn FlashConfig
///
/// @brief Flashes the config to the disk
///
/// @note dirName should be the relative full path to dir
/// @note Function will be removed in near future for SQL but is
/// expensive to run as it flashes everything even if un-updated
/////////////////////////////////////////////////////////////////////////////
public void FlashConfig(String dirName) {
for (Entry<String, IndividualAccount> singleAccount : accounts.accountsList.entrySet()) {
// Iterate over each one & verify if a file exists inside the dir. if it does;
// nuke it and
// replace it with the new contents in memory
String accountNum = singleAccount.getKey().toString();
// delete file
File file = new File(dirName + "/" + accountNum + ".json");
if (file.exists()) {
file.delete();
}
// Re-flash file
try {
config.WriteToJsonFile(dirName + "/" + accountNum + ".json", singleAccount.getValue());
} catch (FILE_WRITE_EXCEPTION e) {
System.out.println("Failed to flash configuration file properly. Printing stack trace");
e.printStackTrace();
}
}
}
}

View File

@ -1,15 +1,17 @@
package jesse.keeblarcraft.Commands;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.arguments.LongArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.context.CommandContext;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.Map.Entry;
import static java.util.Map.entry;
import jesse.keeblarcraft.BankMgr.BankManager;
import jesse.keeblarcraft.BankMgr.IndividualAccount;
import jesse.keeblarcraft.BankMgr.IndividualBank;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
@ -84,91 +86,19 @@ public class BankCommands {
// is just /bank ACTION-WORD [arguments...] [optionals]
var bankRoot = CommandManager.literal("bank").build();
var actionWord = CommandManager.argument("ACTION_WORD", StringArgumentType.greedyString()).build();
// Removing "argList" and just running the entire list as an argList from actionWord makes `/bank help` possible
var argList = CommandManager.argument("ARG_LIST", StringArgumentType.greedyString())
.executes(context -> ParseBankCommand
(
context,
StringArgumentType.getString(context, "ACTION_WORD"),
StringArgumentType.getString(context, "ARG_LIST"))
)
.build();
// Building the argument tree here
dispatcher.getRoot().addChild(bankRoot);
bankRoot.addChild(actionWord);
bankRoot.addChild(argList);
// Aliases
dispatcher.register(CommandManager.literal("wire").redirect(actionWord));
dispatcher.register(CommandManager.literal("balance").redirect(actionWord));
});
// Command: "/getbalance"
// CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
// dispatcher.register(CommandManager.literal("getbalance")
// .executes(context -> GetBalance(context)));
// });
// // Command: "/setbalance || rootSetBalance"
// CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
// final var rootSetBalance = dispatcher.register(CommandManager.literal("setbalance")
// .then(CommandManager.argument("newBalance", IntegerArgumentType.integer())
// .then(CommandManager.argument("reason", StringArgumentType.string())
// .then(CommandManager.argument("otherParty", StringArgumentType.string())
// .executes(context -> SetBalance(
// IntegerArgumentType.getInteger(context, "newBalance"),
// StringArgumentType.getString(context, "reason"),
// StringArgumentType.getString(context, "otherParty"),
// context))))));
// dispatcher.register(CommandManager.literal("setbalance").redirect(rootSetBalance));
// });
// // Command: "/AddMoney"
// CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
// dispatcher.register(CommandManager.literal("AddMoney")
// .then(CommandManager.argument("reason", StringArgumentType.string())
// .then(CommandManager.argument("payment", LongArgumentType.longArg())
// .then(CommandManager.argument("otherParty", StringArgumentType.string())
// .executes(context -> AddMoney(
// StringArgumentType.getString(context, "reason"),
// LongArgumentType.getLong(context, "payment"),
// StringArgumentType.getString(context, "otherParty"),
// context))))));
// });
// // Command: "/subtractbalance || /SubtractBalance"
// CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
// final var SubtractBalance = dispatcher.register(CommandManager.literal("subtractbalance")
// .then(CommandManager.argument("reason", StringArgumentType.string())
// .then(CommandManager.argument("payment", LongArgumentType.longArg())
// .then(CommandManager.argument("otherParty", StringArgumentType.string())
// .executes(context -> SubtractBalance(
// StringArgumentType.getString(context, "reason"),
// LongArgumentType.getLong(context, "payment"),
// StringArgumentType.getString(context, "otherParty"),
// context))))));
// dispatcher.register(CommandManager.literal("subtractbalance").redirect(SubtractBalance));
// });
// // Command: "/wire || /sendmoney"
// CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
// final var sendmoney = dispatcher.register(CommandManager.literal("wire")
// .then(CommandManager.argument("reason", StringArgumentType.string())
// .then(CommandManager.argument("payment", LongArgumentType.longArg())
// .then(CommandManager.argument("otherParty", StringArgumentType.string())
// .executes(context -> Wire(
// StringArgumentType.getString(context, "reason"),
// LongArgumentType.getLong(context, "payment"),
// StringArgumentType.getString(context, "otherParty"),
// context))))));
// dispatcher.register(CommandManager.literal("wire").redirect(sendmoney));
// });
}
// Remove filler words which only exist for human readability
@ -178,21 +108,28 @@ public class BankCommands {
if (FILLER_WORDS.contains(str)) {
argList.remove(index);
}
// Also make every word lower case
str = str.toLowerCase();
index++;
}
return argList;
}
public int ParseBankCommand(CommandContext<ServerCommandSource> context, String actionWord, String unformattedArgList) {
// String[] formattedArgList = unformattedArgList.split("\\s+"); // REGEX is matching 1+ whitespace characters
List<String> formattedArgList = List.of(unformattedArgList.split("\\s+"));
public int ParseBankCommand(CommandContext<ServerCommandSource> context, String unformattedArgList) {
List<String> formattedArgList = List.of(unformattedArgList.split("\\s+")); // REGEX is matching 1+ whitespace characters
System.out.println("After formatting the arg list, the size of arg list is size { " + formattedArgList.size() + " }");
formattedArgList = RemoveFillerWords(formattedArgList);
actionWord = actionWord.toLowerCase();
String actionWord = formattedArgList.get(0);
System.out.println("The action word for this operation is " + actionWord.toUpperCase());
System.out.println("Parsing bank command on action word { " + actionWord + " } with arg list { " + formattedArgList + " }");
switch(actionWord)
{
case "create":
CreateCommand(context.getSource().getPlayer(), formattedArgList);
System.out.println("Calling create command...");
CreateCommand(context.getSource().getPlayer(), formattedArgList.subList(1, formattedArgList.size()));
break;
case "close":
CloseCommand(context.getSource().getPlayer(), formattedArgList);
@ -207,7 +144,7 @@ public class BankCommands {
BalanceCommand(context.getSource().getPlayer(), formattedArgList);
break;
case "help":
HelpCommand(context.getSource().getPlayer(), "help");
HelpCommand(context.getSource().getPlayer(), formattedArgList);
break;
case "move":
MoveCommand(context.getSource().getPlayer(), formattedArgList);
@ -219,10 +156,17 @@ public class BankCommands {
ReportCommand(context.getSource().getPlayer(), formattedArgList);
break;
case "examples":
HelpCommand(context.getSource().getPlayer(), "examples");
HelpCommand(context.getSource().getPlayer(), List.of("examples"));
break;
case "syntax":
HelpCommand(context.getSource().getPlayer(), "syntax");
HelpCommand(context.getSource().getPlayer(), List.of("syntax"));
break;
case "list":
ListAllBanks(context.getSource().getPlayer(), formattedArgList);
break;
case "account":
case "accounts":
ManageAccounts(context.getSource().getPlayer(), formattedArgList.subList(1, formattedArgList.size()));
break;
default:
if (context.getSource().isExecutedByPlayer()) {
@ -234,7 +178,42 @@ public class BankCommands {
}
// Possible code paths:
// REQUIRED (path 1) = {AMOUNT} [FROM:{INTERNAL ACCOUNT #|ALIAS}] TO:{INTERNAL ACCOUNT #|ALIAS} ***Note: TO{} can be assumed to be SELECTED default if not specified
// REQUIRED = {Routing # or Bank name}
// OPTIONAL = []
public void ManageAccounts(ServerPlayerEntity sourcePlayer, List<String> argList) {
System.out.println("Manage accounts arg list is { " + argList + " }");
if (argList.size() > 0) {
// TODO: For now we assume they reference the bank name and not routing #
Boolean success = false;
String bankName = argList.get(0).toUpperCase();
IndividualBank bank = BankManager.GetInstance().GetBankByName(bankName);
System.out.println("Test print on memory");
Boolean isNull = bank == null;
System.out.println("isNull: " + isNull);
if (bank != null) {
System.out.println("Grabbing user account information");
List<IndividualAccount> userAccounts = bank.GetAccountsOfUser(sourcePlayer.getUuidAsString());
sourcePlayer.sendMessage(Text.of("------------[BANK INFO FOR " + bankName.toUpperCase() + "]------------"));
for (int i = 0; i < userAccounts.size(); i++) {
sourcePlayer.sendMessage(Text.of("ACCOUNT NUMBER: " + userAccounts.get(i).GetAccountNumber()));
sourcePlayer.sendMessage(Text.of("HOLDERS: " + userAccounts.get(i).GetAccountHolders()));
sourcePlayer.sendMessage(Text.of("BALANCE: " + userAccounts.get(i).GetAccountBalance()));
sourcePlayer.sendMessage(Text.of("\n"));
}
} else {
sourcePlayer.sendMessage(Text.of("That bank does not exist"));
}
} else {
sourcePlayer.sendMessage(Text.of("Unrecognized move command. Please use \"/bank help ACCOUNTS\" for more information."));
}
}
public void ListAllBanks(ServerPlayerEntity sourcePlayer, List<String> argList) {
sourcePlayer.sendMessage(Text.of("Here is a list of available banks on the server: " + BankManager.GetInstance().GetAllBankNames()));
}
// Possible code paths:
// REQUIRED (path 1) = {AMOUNT} [FROM:{INTERNAL ACCOUNT #|ALIAS}] TO:{INTERNAL ACCOUNT #|ALIAS} ***Note: can be assumed to be SELECTED default if not specified
// REQUIRED (path 2) = {INTERNAL ACCOUNT #|ALIAS} {EXTERNAL BANK/FACTION ID}
// OPTIONAL = []
public void MoveCommand(ServerPlayerEntity sourcePlayer, List<String> argList) {
@ -327,8 +306,12 @@ public class BankCommands {
// Create command - valid arg list types:
// /... CREATE {CA/checking/savings/checking-account/savings-account/report}
public int CreateCommand(ServerPlayerEntity sourcePlayer, List<String> argList) {
System.out.println("Attempting account creation given arg list { " + argList + " }.");
System.out.println("argList size is " + argList.size());
if (argList.size() > 0) {
String action = argList.get(0).toLowerCase();
System.out.println("action word is " + action);
switch (action) {
// Checking & Savings are handled in the same function so we can just "alias" all of these to the same call!
@ -338,14 +321,15 @@ public class BankCommands {
case "sa":
case "savings":
case "savings-account":
argList.remove(0); // Remove action word (all the above aliases)
System.out.println("Creating account. Removing index 0 in argList. New argList is { " + argList + " }");
CreateAccount(sourcePlayer, argList);
break;
case "rep":
case "report":
argList.remove(0); // Remove action word (all the above aliases)
GenerateAccountReport(sourcePlayer, argList);
break;
default:
// Unrecognized creation type
}
} else {
sourcePlayer.sendMessage(Text.of("Unrecognized create command formed on bank. Please run \"/bank help CREATE\" for more information"));
@ -415,7 +399,6 @@ public class BankCommands {
*
*
* CALL THROUGHS TO BANK MGR HERE
* CALL THROUGHS TO BANK MGR HERE
*
*/
} else {
@ -427,22 +410,33 @@ public class BankCommands {
// Possible code paths:
// REQUIRED = {}
// OPTIONAL = [command|subcommand]
public int HelpCommand(ServerPlayerEntity sourcePlayer, String helpCommand) {
if (helpCommand.length() > 0) {
// Specific command help message
/*
*
* A ChatUtil message needs to be created to better display messages to players. Once that is created; forward this string to that
*
*/
public int HelpCommand(ServerPlayerEntity sourcePlayer, List<String> helpCommand) {
System.out.println("Running help command");
// TODO: Make a prettier way of printing this to the player with color
if (helpCommand.size() == 0) {
// General help command
for (Entry<String, String> helpCmd : HELP_COMMANDS.entrySet()) {
sourcePlayer.sendMessage(Text.of(helpCmd.getKey() + " --> " + helpCmd.getValue()));
sourcePlayer.sendMessage(Text.of("\n"));
}
} else {
// General help message
/*
*
* A ChatUtil message needs to be created to better display messages to players. Once that is created; forward this string to that
*
*/
// Iterate over list; verifying what commands are found
List<String> unknownCmds = new ArrayList<String>();
for (int i = 0; i < helpCommand.size(); i++) {
String newHelpCmd = helpCommand.get(i);
if (HELP_COMMANDS.containsKey(newHelpCmd)) {
// Print help for this specific command
sourcePlayer.sendMessage(Text.of(newHelpCmd + " -> " + HELP_COMMANDS.get(newHelpCmd)));
} else {
// Add to unknown list at end
unknownCmds.add(newHelpCmd);
}
}
// After all prints have finished tell the player the commands they plugged in that we did not recognize
if (unknownCmds.size() > 0) {
sourcePlayer.sendMessage(Text.of("The following commands do not exist or were mispelt: " + unknownCmds));
}
}
return 0;
}
@ -450,6 +444,7 @@ public class BankCommands {
// Possible args:
// /bank create {SAVINGS/CHECKING} [optional: alias]
public void CreateAccount(ServerPlayerEntity player, List<String> accountArgs) {
System.out.println("Attempting to create checking account with arg list { " + accountArgs + " }");
if (accountArgs.size() > 0) {
String accountType = accountArgs.get(0);
String accountAlias = "NO_ALIAS";
@ -459,12 +454,9 @@ public class BankCommands {
accountAlias = accountArgs.get(1).toLowerCase();
}
/*
*
* Finally - calls to BankManager here for more
*
*/
System.out.println("ACCOUNT CREATION REQUESTED WITH TYPE " + accountType + " AND ALIAS " + accountAlias);
// FIXME: This is just a patch at the moment to let players make bank accounts in server bank
BankManager.GetInstance().InitiateBankAccountCreation(null, player, accountType);
} else {
player.sendMessage(Text.of("Unrecognized create account command. Please run /bank help create for more information"));
}
@ -486,100 +478,4 @@ public class BankCommands {
player.sendMessage(Text.of("Unrecognized report field data. Please run /bank help report for more information"));
}
}
// public Integer GetBalance(CommandContext<ServerCommandSource> context) {
// Integer ret = -1;
// if (context.getSource().isExecutedByPlayer()) {
// ServerPlayerEntity player = context.getSource().getPlayer();
// BankManager playerBank = new BankManager(player.getUuidAsString());
// player.sendMessage(Text.literal(String.valueOf(playerBank.GetBalance())));
// return 0;
// }
// return ret;
// }
// //SetBalance will be a ServerCommand only Perm level Op
// public Integer SetBalance(Integer newBalance, String reason, String otherParty, CommandContext<ServerCommandSource> context) {
// Integer ret = -1;
// if (context.getSource().hasPermissionLevel(1)) {
// ServerPlayerEntity player = context.getSource().getPlayer();
// BankManager playerBank = new BankManager(player.getUuidAsString());
// playerBank.SetBalance(newBalance, reason, otherParty);
// player.sendMessage(Text.literal(String.valueOf(playerBank.GetBalance())));
// }
// return ret;
// }
// //AddMoney will be a ServerCommand Only Perm level Op
// public Integer AddMoney(String reason, long payment, String otherParty, CommandContext<ServerCommandSource> context) {
// Integer ret = -1;
// if (context.getSource().hasPermissionLevel(1)) {
// ret = 0;
// ServerPlayerEntity player = context.getSource().getPlayer();
// BankManager playerBank = new BankManager(player.getUuidAsString());
// playerBank.AddMoney(reason, payment, otherParty);
// player.sendMessage(Text.literal(String.valueOf(playerBank.GetBalance())));
// }
// return ret;
// }
// //SubtractBalance will be a ServerCommand Perm leve Op
// public Integer SubtractBalance(String reason, long payment, String otherParty, CommandContext<ServerCommandSource> context) {
// Integer ret = -1;
// if (context.getSource().hasPermissionLevel(1)) {
// ret = 0;
// ServerPlayerEntity player = context.getSource().getPlayer();
// BankManager playerBank = new BankManager(player.getUuidAsString());
// playerBank.SubtractBalance(reason, payment, otherParty);
// player.sendMessage(Text.literal(String.valueOf(playerBank.GetBalance())));
// }
// return ret;
// }
// public Integer Wire(String reason, long payment, String otherParty, CommandContext<ServerCommandSource> context) {
// Integer ret = -1;
// if (context.getSource().isExecutedByPlayer()) {
// ret = 0;
// ServerPlayerEntity player = context.getSource().getPlayer();
// BankManager playerBank = new BankManager(player.getUuidAsString());
// playerBank.Wire(reason, payment, otherParty);
// player.sendMessage(Text.literal(String.valueOf(playerBank.GetBalance())));
// }
// return ret;
// }
}

View File

@ -182,6 +182,7 @@ public class ConfigManager {
Boolean ret = false;
File dir = new File(dirName);
System.out.println("Attempting to create dir with name " + dirName);
try {
if ( ! dir.exists()) {

View File

@ -24,6 +24,7 @@ import org.slf4j.LoggerFactory;
import jesse.keeblarcraft.AttributeMgr.AttributeMgr;
import jesse.keeblarcraft.AttributeMgr.AttributeTree;
import jesse.keeblarcraft.BankMgr.BankManager;
import jesse.keeblarcraft.Commands.CustomCommandManager;
import jesse.keeblarcraft.CustomBlocks.BlockList;
import jesse.keeblarcraft.CustomItems.ItemManager;
@ -90,6 +91,9 @@ public class Keeblarcraft implements ModInitializer {
// Register attributes
AttributeMgr.RegisterAttributes();
// Register the banking system
BankManager.GetInstance().InitializeBanks();
/// THE BELOW ITEMS MUST BE DONE LAST IN THE STEPS
// Register items