diff --git a/src/main/java/io/github/flibio/economylite/LockUtils.java b/src/main/java/io/github/flibio/economylite/LockUtils.java new file mode 100644 index 0000000..ccf5e9c --- /dev/null +++ b/src/main/java/io/github/flibio/economylite/LockUtils.java @@ -0,0 +1,35 @@ +/* + * This file is part of EconomyLite, licensed under the MIT License (MIT). See the LICENSE file at the root of this project for more information. + */ +package io.github.flibio.economylite; + +import java.util.concurrent.Semaphore; + +public class LockUtils implements AutoCloseable { + static private Semaphore lock = new Semaphore(1); + static private long threadID = 0; + static private int numLock = 0; + + public LockUtils() { + if (threadID > 0 && Thread.currentThread().getId() == threadID) { + numLock++; + return; + } + try { + lock.acquire(); + threadID = Thread.currentThread().getId(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + @Override + public void close() { + if (numLock == 0) { + threadID = 0; + lock.release(); + } else { + numLock--; + } + } +} diff --git a/src/main/java/io/github/flibio/economylite/impl/economy/account/LiteUniqueAccount.java b/src/main/java/io/github/flibio/economylite/impl/economy/account/LiteUniqueAccount.java index e2bd0a8..60f6ffe 100644 --- a/src/main/java/io/github/flibio/economylite/impl/economy/account/LiteUniqueAccount.java +++ b/src/main/java/io/github/flibio/economylite/impl/economy/account/LiteUniqueAccount.java @@ -5,6 +5,7 @@ import io.github.flibio.economylite.CauseFactory; import io.github.flibio.economylite.EconomyLite; +import io.github.flibio.economylite.LockUtils; import io.github.flibio.economylite.api.CurrencyEconService; import io.github.flibio.economylite.api.PlayerEconService; import io.github.flibio.economylite.impl.economy.event.LiteEconomyTransactionEvent; @@ -76,8 +77,10 @@ public boolean hasBalance(Currency currency, Set contexts) { @Override public BigDecimal getBalance(Currency currency, Set contexts) { - if (!hasBalance(currency, contexts)) { - playerService.setBalance(uuid, getDefaultBalance(currency), currency, CauseFactory.create("New Account")); + try (LockUtils lock = new LockUtils()) { + if (!hasBalance(currency, contexts)) { + playerService.setBalance(uuid, getDefaultBalance(currency), currency, CauseFactory.create("New Account")); + } } return playerService.getBalance(uuid, currency, CauseFactory.create("Get Balance")); } @@ -99,84 +102,96 @@ public TransactionResult setBalance(Currency currency, BigDecimal amount, Cause if (amount.compareTo(BigDecimal.ZERO) == -1 || amount.compareTo(BigDecimal.valueOf(999999999)) == 1) { return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_SPACE, TransactionTypes.DEPOSIT, cause); } - if (playerService.setBalance(uuid, amount, currency, cause)) { - return resultAndEvent(this, amount, currency, ResultType.SUCCESS, TransactionTypes.DEPOSIT, cause); - } else { - return resultAndEvent(this, amount, currency, ResultType.FAILED, TransactionTypes.DEPOSIT, cause); + try (LockUtils lock = new LockUtils()) { + if (playerService.setBalance(uuid, amount, currency, cause)) { + return resultAndEvent(this, amount, currency, ResultType.SUCCESS, TransactionTypes.DEPOSIT, cause); + } else { + return resultAndEvent(this, amount, currency, ResultType.FAILED, TransactionTypes.DEPOSIT, cause); + } } } @Override public Map resetBalances(Cause cause, Set contexts) { HashMap results = new HashMap<>(); - for (Currency currency : currencyService.getCurrencies()) { - if (playerService.accountExists(uuid, currency, cause)) { - if (playerService.setBalance(uuid, getDefaultBalance(currency), currency, cause)) { - results.put(currency, resultAndEvent(this, getBalance(currency), currency, ResultType.SUCCESS, TransactionTypes.WITHDRAW, cause)); - } else { - results.put(currency, resultAndEvent(this, getBalance(currency), currency, ResultType.FAILED, TransactionTypes.WITHDRAW, cause)); + try (LockUtils lock = new LockUtils()) { + for (Currency currency : currencyService.getCurrencies()) { + if (playerService.accountExists(uuid, currency, cause)) { + if (playerService.setBalance(uuid, getDefaultBalance(currency), currency, cause)) { + results.put(currency, resultAndEvent(this, getBalance(currency), currency, ResultType.SUCCESS, TransactionTypes.WITHDRAW, cause)); + } else { + results.put(currency, resultAndEvent(this, getBalance(currency), currency, ResultType.FAILED, TransactionTypes.WITHDRAW, cause)); + } } } + return results; } - return results; } @Override public TransactionResult resetBalance(Currency currency, Cause cause, Set contexts) { - if (playerService.setBalance(uuid, getDefaultBalance(currency), currency, cause)) { - return resultAndEvent(this, BigDecimal.ZERO, currency, ResultType.SUCCESS, TransactionTypes.WITHDRAW, cause); - } else { - return resultAndEvent(this, BigDecimal.ZERO, currency, ResultType.FAILED, TransactionTypes.WITHDRAW, cause); + try (LockUtils lock = new LockUtils()) { + if (playerService.setBalance(uuid, getDefaultBalance(currency), currency, cause)) { + return resultAndEvent(this, BigDecimal.ZERO, currency, ResultType.SUCCESS, TransactionTypes.WITHDRAW, cause); + } else { + return resultAndEvent(this, BigDecimal.ZERO, currency, ResultType.FAILED, TransactionTypes.WITHDRAW, cause); + } } } @Override public TransactionResult deposit(Currency currency, BigDecimal amount, Cause cause, Set contexts) { - BigDecimal newBal = getBalance(currency).add(amount); - // Check if the new balance is in bounds - if (newBal.compareTo(BigDecimal.ZERO) == -1 || newBal.compareTo(BigDecimal.valueOf(999999999)) == 1) { - return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_SPACE, TransactionTypes.DEPOSIT, cause); - } - if (playerService.deposit(uuid, amount, currency, cause)) { - return resultAndEvent(this, amount, currency, ResultType.SUCCESS, TransactionTypes.DEPOSIT, cause); - } else { - return resultAndEvent(this, amount, currency, ResultType.FAILED, TransactionTypes.DEPOSIT, cause); + try (LockUtils lock = new LockUtils()) { + BigDecimal newBal = getBalance(currency).add(amount); + // Check if the new balance is in bounds + if (newBal.compareTo(BigDecimal.ZERO) == -1 || newBal.compareTo(BigDecimal.valueOf(999999999)) == 1) { + return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_SPACE, TransactionTypes.DEPOSIT, cause); + } + if (playerService.deposit(uuid, amount, currency, cause)) { + return resultAndEvent(this, amount, currency, ResultType.SUCCESS, TransactionTypes.DEPOSIT, cause); + } else { + return resultAndEvent(this, amount, currency, ResultType.FAILED, TransactionTypes.DEPOSIT, cause); + } } } @Override public TransactionResult withdraw(Currency currency, BigDecimal amount, Cause cause, Set contexts) { - BigDecimal newBal = getBalance(currency).subtract(amount); - // Check if the new balance is in bounds - if (newBal.compareTo(BigDecimal.ZERO) == -1) { - return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_FUNDS, TransactionTypes.WITHDRAW, cause); - } - if (newBal.compareTo(BigDecimal.valueOf(999999999)) == 1) { - return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_SPACE, TransactionTypes.WITHDRAW, cause); - } - if (playerService.withdraw(uuid, amount, currency, cause)) { - return resultAndEvent(this, amount, currency, ResultType.SUCCESS, TransactionTypes.WITHDRAW, cause); - } else { - return resultAndEvent(this, amount, currency, ResultType.FAILED, TransactionTypes.WITHDRAW, cause); + try (LockUtils lock = new LockUtils()) { + BigDecimal newBal = getBalance(currency).subtract(amount); + // Check if the new balance is in bounds + if (newBal.compareTo(BigDecimal.ZERO) == -1) { + return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_FUNDS, TransactionTypes.WITHDRAW, cause); + } + if (newBal.compareTo(BigDecimal.valueOf(999999999)) == 1) { + return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_SPACE, TransactionTypes.WITHDRAW, cause); + } + if (playerService.withdraw(uuid, amount, currency, cause)) { + return resultAndEvent(this, amount, currency, ResultType.SUCCESS, TransactionTypes.WITHDRAW, cause); + } else { + return resultAndEvent(this, amount, currency, ResultType.FAILED, TransactionTypes.WITHDRAW, cause); + } } } @Override public TransferResult transfer(Account to, Currency currency, BigDecimal amount, Cause cause, Set contexts) { - BigDecimal newBal = to.getBalance(currency).add(amount); - // Check if the new balance is in bounds - if (newBal.compareTo(BigDecimal.ZERO) == -1 || newBal.compareTo(BigDecimal.valueOf(999999999)) == 1) { - return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_SPACE, to, cause); - } - // Check if the account has enough funds - if (amount.compareTo(getBalance(currency)) == 1) { - return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_FUNDS, to, cause); - } - if (withdraw(currency, amount, cause).getResult().equals(ResultType.SUCCESS) - && to.deposit(currency, amount, cause).getResult().equals(ResultType.SUCCESS)) { - return resultAndEvent(this, amount, currency, ResultType.SUCCESS, to, cause); - } else { - return resultAndEvent(this, amount, currency, ResultType.FAILED, to, cause); + try (LockUtils lock = new LockUtils()) { + BigDecimal newBal = to.getBalance(currency).add(amount); + // Check if the new balance is in bounds + if (newBal.compareTo(BigDecimal.ZERO) == -1 || newBal.compareTo(BigDecimal.valueOf(999999999)) == 1) { + return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_SPACE, to, cause); + } + // Check if the account has enough funds + if (amount.compareTo(getBalance(currency)) == 1) { + return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_FUNDS, to, cause); + } + if (withdraw(currency, amount, cause).getResult().equals(ResultType.SUCCESS) + && to.deposit(currency, amount, cause).getResult().equals(ResultType.SUCCESS)) { + return resultAndEvent(this, amount, currency, ResultType.SUCCESS, to, cause); + } else { + return resultAndEvent(this, amount, currency, ResultType.FAILED, to, cause); + } } } @@ -207,5 +222,4 @@ private TransferResult resultAndEvent(Account account, BigDecimal amount, Curren public UUID getUniqueId() { return uuid; } - } diff --git a/src/main/java/io/github/flibio/economylite/impl/economy/account/LiteVirtualAccount.java b/src/main/java/io/github/flibio/economylite/impl/economy/account/LiteVirtualAccount.java index add6589..1f7f10c 100644 --- a/src/main/java/io/github/flibio/economylite/impl/economy/account/LiteVirtualAccount.java +++ b/src/main/java/io/github/flibio/economylite/impl/economy/account/LiteVirtualAccount.java @@ -5,6 +5,7 @@ import io.github.flibio.economylite.CauseFactory; import io.github.flibio.economylite.EconomyLite; +import io.github.flibio.economylite.LockUtils; import io.github.flibio.economylite.api.CurrencyEconService; import io.github.flibio.economylite.api.VirtualEconService; import io.github.flibio.economylite.impl.economy.event.LiteEconomyTransactionEvent; @@ -63,8 +64,10 @@ public boolean hasBalance(Currency currency, Set contexts) { @Override public BigDecimal getBalance(Currency currency, Set contexts) { - if (!hasBalance(currency, contexts)) { - virtualService.setBalance(name, getDefaultBalance(currency), currency, CauseFactory.create("New Account")); + try (LockUtils lock = new LockUtils()) { + if (!hasBalance(currency, contexts)) { + virtualService.setBalance(name, getDefaultBalance(currency), currency, CauseFactory.create("New Account")); + } } return virtualService.getBalance(name, currency, CauseFactory.create("Get Balance")); } @@ -86,22 +89,26 @@ public TransactionResult setBalance(Currency currency, BigDecimal amount, Cause if (amount.compareTo(BigDecimal.ZERO) == -1 || amount.compareTo(BigDecimal.valueOf(999999999)) == 1) { return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_SPACE, TransactionTypes.DEPOSIT, cause); } - if (virtualService.setBalance(name, amount, currency, cause)) { - return resultAndEvent(this, amount, currency, ResultType.SUCCESS, TransactionTypes.DEPOSIT, cause); - } else { - return resultAndEvent(this, amount, currency, ResultType.FAILED, TransactionTypes.DEPOSIT, cause); + try (LockUtils lock = new LockUtils()) { + if (virtualService.setBalance(name, amount, currency, cause)) { + return resultAndEvent(this, amount, currency, ResultType.SUCCESS, TransactionTypes.DEPOSIT, cause); + } else { + return resultAndEvent(this, amount, currency, ResultType.FAILED, TransactionTypes.DEPOSIT, cause); + } } } @Override public Map resetBalances(Cause cause, Set contexts) { HashMap results = new HashMap<>(); - for (Currency currency : currencyService.getCurrencies()) { - if (virtualService.accountExists(name, currency, cause)) { - if (virtualService.setBalance(name, getDefaultBalance(currency), currency, cause)) { - results.put(currency, resultAndEvent(this, getBalance(currency), currency, ResultType.SUCCESS, TransactionTypes.WITHDRAW, cause)); - } else { - results.put(currency, resultAndEvent(this, getBalance(currency), currency, ResultType.FAILED, TransactionTypes.WITHDRAW, cause)); + try (LockUtils lock = new LockUtils()) { + for (Currency currency : currencyService.getCurrencies()) { + if (virtualService.accountExists(name, currency, cause)) { + if (virtualService.setBalance(name, getDefaultBalance(currency), currency, cause)) { + results.put(currency, resultAndEvent(this, getBalance(currency), currency, ResultType.SUCCESS, TransactionTypes.WITHDRAW, cause)); + } else { + results.put(currency, resultAndEvent(this, getBalance(currency), currency, ResultType.FAILED, TransactionTypes.WITHDRAW, cause)); + } } } } @@ -110,60 +117,68 @@ public Map resetBalances(Cause cause, Set @Override public TransactionResult resetBalance(Currency currency, Cause cause, Set contexts) { - if (virtualService.setBalance(name, getDefaultBalance(currency), currency, cause)) { - return resultAndEvent(this, BigDecimal.ZERO, currency, ResultType.SUCCESS, TransactionTypes.WITHDRAW, cause); - } else { - return resultAndEvent(this, BigDecimal.ZERO, currency, ResultType.FAILED, TransactionTypes.WITHDRAW, cause); + try (LockUtils lock = new LockUtils()) { + if (virtualService.setBalance(name, getDefaultBalance(currency), currency, cause)) { + return resultAndEvent(this, BigDecimal.ZERO, currency, ResultType.SUCCESS, TransactionTypes.WITHDRAW, cause); + } else { + return resultAndEvent(this, BigDecimal.ZERO, currency, ResultType.FAILED, TransactionTypes.WITHDRAW, cause); + } } } @Override public TransactionResult deposit(Currency currency, BigDecimal amount, Cause cause, Set contexts) { - BigDecimal newBal = getBalance(currency).add(amount); - // Check if the new balance is in bounds - if (newBal.compareTo(BigDecimal.ZERO) == -1 || newBal.compareTo(BigDecimal.valueOf(999999999)) == 1) { - return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_SPACE, TransactionTypes.DEPOSIT, cause); - } - if (virtualService.deposit(name, amount, currency, cause)) { - return resultAndEvent(this, amount, currency, ResultType.SUCCESS, TransactionTypes.DEPOSIT, cause); - } else { - return resultAndEvent(this, amount, currency, ResultType.FAILED, TransactionTypes.DEPOSIT, cause); + try (LockUtils lock = new LockUtils()) { + BigDecimal newBal = getBalance(currency).add(amount); + // Check if the new balance is in bounds + if (newBal.compareTo(BigDecimal.ZERO) == -1 || newBal.compareTo(BigDecimal.valueOf(999999999)) == 1) { + return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_SPACE, TransactionTypes.DEPOSIT, cause); + } + if (virtualService.deposit(name, amount, currency, cause)) { + return resultAndEvent(this, amount, currency, ResultType.SUCCESS, TransactionTypes.DEPOSIT, cause); + } else { + return resultAndEvent(this, amount, currency, ResultType.FAILED, TransactionTypes.DEPOSIT, cause); + } } } @Override public TransactionResult withdraw(Currency currency, BigDecimal amount, Cause cause, Set contexts) { - BigDecimal newBal = getBalance(currency).subtract(amount); - // Check if the new balance is in bounds - if (newBal.compareTo(BigDecimal.ZERO) == -1) { - return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_FUNDS, TransactionTypes.WITHDRAW, cause); - } - if (newBal.compareTo(BigDecimal.valueOf(999999999)) == 1) { - return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_SPACE, TransactionTypes.WITHDRAW, cause); - } - if (virtualService.withdraw(name, amount, currency, cause)) { - return resultAndEvent(this, amount, currency, ResultType.SUCCESS, TransactionTypes.WITHDRAW, cause); - } else { - return resultAndEvent(this, amount, currency, ResultType.FAILED, TransactionTypes.WITHDRAW, cause); + try (LockUtils lock = new LockUtils()) { + BigDecimal newBal = getBalance(currency).subtract(amount); + // Check if the new balance is in bounds + if (newBal.compareTo(BigDecimal.ZERO) == -1) { + return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_FUNDS, TransactionTypes.WITHDRAW, cause); + } + if (newBal.compareTo(BigDecimal.valueOf(999999999)) == 1) { + return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_SPACE, TransactionTypes.WITHDRAW, cause); + } + if (virtualService.withdraw(name, amount, currency, cause)) { + return resultAndEvent(this, amount, currency, ResultType.SUCCESS, TransactionTypes.WITHDRAW, cause); + } else { + return resultAndEvent(this, amount, currency, ResultType.FAILED, TransactionTypes.WITHDRAW, cause); + } } } @Override public TransferResult transfer(Account to, Currency currency, BigDecimal amount, Cause cause, Set contexts) { - BigDecimal newBal = to.getBalance(currency).add(amount); - // Check if the new balance is in bounds - if (newBal.compareTo(BigDecimal.ZERO) == -1 || newBal.compareTo(BigDecimal.valueOf(999999999)) == 1) { - return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_SPACE, to, cause); - } - // Check if the account has enough funds - if (amount.compareTo(getBalance(currency)) == 1) { - return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_FUNDS, to, cause); - } - if (withdraw(currency, amount, cause).getResult().equals(ResultType.SUCCESS) - && to.deposit(currency, amount, cause).getResult().equals(ResultType.SUCCESS)) { - return resultAndEvent(this, amount, currency, ResultType.SUCCESS, to, cause); - } else { - return resultAndEvent(this, amount, currency, ResultType.FAILED, to, cause); + try (LockUtils lock = new LockUtils()) { + BigDecimal newBal = to.getBalance(currency).add(amount); + // Check if the new balance is in bounds + if (newBal.compareTo(BigDecimal.ZERO) == -1 || newBal.compareTo(BigDecimal.valueOf(999999999)) == 1) { + return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_SPACE, to, cause); + } + // Check if the account has enough funds + if (amount.compareTo(getBalance(currency)) == 1) { + return resultAndEvent(this, amount, currency, ResultType.ACCOUNT_NO_FUNDS, to, cause); + } + if (withdraw(currency, amount, cause).getResult().equals(ResultType.SUCCESS) + && to.deposit(currency, amount, cause).getResult().equals(ResultType.SUCCESS)) { + return resultAndEvent(this, amount, currency, ResultType.SUCCESS, to, cause); + } else { + return resultAndEvent(this, amount, currency, ResultType.FAILED, to, cause); + } } } @@ -189,5 +204,4 @@ private TransferResult resultAndEvent(Account account, BigDecimal amount, Curren Sponge.getEventManager().post(new LiteEconomyTransactionEvent(result, cause)); return result; } - }