diff --git a/Datura/src/main/java/me/totalfreedom/datura/user/SimpleUserData.java b/Datura/src/main/java/me/totalfreedom/datura/user/SimpleUserData.java index dc4b17e..57de38e 100644 --- a/Datura/src/main/java/me/totalfreedom/datura/user/SimpleUserData.java +++ b/Datura/src/main/java/me/totalfreedom/datura/user/SimpleUserData.java @@ -16,6 +16,7 @@ import org.jetbrains.annotations.Nullable; import java.sql.SQLException; import java.util.UUID; +import java.util.concurrent.atomic.AtomicLong; public class SimpleUserData implements UserData { @@ -28,6 +29,8 @@ public class SimpleUserData implements UserData private boolean frozen; private boolean canInteract; private boolean caged; + private AtomicLong balance; + private boolean transactionsFrozen; public SimpleUserData(final Player player) { @@ -46,7 +49,9 @@ public class SimpleUserData implements UserData final long playtime, final boolean frozen, final boolean canInteract, - final boolean caged) + final boolean caged, + final long balance, + final boolean transactionsFrozen) { this.uuid = uuid; this.username = username; @@ -56,6 +61,8 @@ public class SimpleUserData implements UserData this.frozen = frozen; this.canInteract = canInteract; this.caged = caged; + this.balance = new AtomicLong(balance); + this.transactionsFrozen = transactionsFrozen; } public static SimpleUserData fromSQL(final SQL sql, final String uuid) @@ -82,11 +89,14 @@ public class SimpleUserData implements UserData .getRegistrations() .getGroupRegistry() .getGroup(g); - final long playtime = result.getLong("playtime"); - final boolean frozen = result.getBoolean("frozen"); - final boolean canInteract = result.getBoolean("canInteract"); - final boolean caged = result.getBoolean("caged"); - return new SimpleUserData(u, username, user, group, playtime, frozen, canInteract, caged); + + long playtime = result.getLong("playtime"); + boolean frozen = result.getBoolean("frozen"); + boolean canInteract = result.getBoolean("canInteract"); + boolean caged = result.getBoolean("caged"); + long balance = result.getLong("balance"); + boolean transactionsFrozen = result.getBoolean("transactionsFrozen"); + return new SimpleUserData(u, username, user, group, playtime, frozen, canInteract, caged, balance, transactionsFrozen); } } catch (SQLException ex) { @@ -207,4 +217,34 @@ public class SimpleUserData implements UserData event.ping(); this.caged = caged; } + + @Override + public boolean areTransactionsFrozen() + { + return transactionsFrozen; + } + + @Override + public long getBalance() + { + return balance.get(); + } + + @Override + public long addToBalance(long amount) + { + return balance.addAndGet(amount); + } + + @Override + public long removeFromBalance(long amount) + { + return balance.addAndGet(-amount); + } + + @Override + public void setBalance(long newBalance) + { + balance.set(newBalance); + } } diff --git a/Fossil/src/main/java/me/totalfreedom/fossil/economy/SimpleCompletedTransaction.java b/Fossil/src/main/java/me/totalfreedom/fossil/economy/SimpleCompletedTransaction.java new file mode 100644 index 0000000..b7ba257 --- /dev/null +++ b/Fossil/src/main/java/me/totalfreedom/fossil/economy/SimpleCompletedTransaction.java @@ -0,0 +1,47 @@ +package me.totalfreedom.fossil.economy; + +import me.totalfreedom.economy.CompletedTransaction; +import me.totalfreedom.economy.EconomicEntity; +import me.totalfreedom.economy.Transaction; +import me.totalfreedom.economy.TransactionResult; + +public class SimpleCompletedTransaction implements CompletedTransaction +{ + private final TransactionResult transactionResult; + private final EconomicEntity source; + private final EconomicEntity destination; + private final long balance; + + public SimpleCompletedTransaction(Transaction transaction, TransactionResult transactionResult) + { + + this.source = transaction.getSource(); + this.destination = transaction.getDestination(); + this.balance = transaction.getBalance(); + this.transactionResult = transactionResult; + } + + @Override + public TransactionResult getResult() + { + return transactionResult; + } + + @Override + public EconomicEntity getSource() + { + return source; + } + + @Override + public EconomicEntity getDestination() + { + return destination; + } + + @Override + public long getBalance() + { + return balance; + } +} diff --git a/Fossil/src/main/java/me/totalfreedom/fossil/economy/SimpleLoggedTransactor.java b/Fossil/src/main/java/me/totalfreedom/fossil/economy/SimpleLoggedTransactor.java new file mode 100644 index 0000000..4bf35ca --- /dev/null +++ b/Fossil/src/main/java/me/totalfreedom/fossil/economy/SimpleLoggedTransactor.java @@ -0,0 +1,37 @@ +package me.totalfreedom.fossil.economy; + +import me.totalfreedom.economy.CompletedTransaction; +import me.totalfreedom.economy.MutableTransaction; +import me.totalfreedom.economy.TransactionLogger; +import me.totalfreedom.economy.Transactor; + +public class SimpleLoggedTransactor implements Transactor +{ + private final Transactor transactor; + private final TransactionLogger transactionLogger; + + public SimpleLoggedTransactor() + { + this(new SimpleTransactor(), new SimpleTransactionLogger()); + } + + public SimpleLoggedTransactor(Transactor transactor, TransactionLogger transactionLogger) + { + this.transactor = transactor; + this.transactionLogger = transactionLogger; + } + + @Override + public CompletedTransaction handleTransaction(MutableTransaction transaction) + { + CompletedTransaction completedTransaction = transactor.handleTransaction(transaction); + + transactionLogger.logTransaction(completedTransaction); + return completedTransaction; + } + + public TransactionLogger getTransactionLogger() + { + return this.transactionLogger; + } +} diff --git a/Fossil/src/main/java/me/totalfreedom/fossil/economy/SimpleMutableTransaction.java b/Fossil/src/main/java/me/totalfreedom/fossil/economy/SimpleMutableTransaction.java new file mode 100644 index 0000000..c99cb65 --- /dev/null +++ b/Fossil/src/main/java/me/totalfreedom/fossil/economy/SimpleMutableTransaction.java @@ -0,0 +1,30 @@ +package me.totalfreedom.fossil.economy; + +import me.totalfreedom.economy.EconomicEntity; +import me.totalfreedom.economy.MutableTransaction; + +public class SimpleMutableTransaction extends SimpleTransaction implements MutableTransaction +{ + public SimpleMutableTransaction(EconomicEntity source, EconomicEntity destination, long balance) + { + super(source, destination, balance); + } + + @Override + public long addToBalance(long amount) + { + return balance.addAndGet(amount); + } + + @Override + public long removeFromBalance(long amount) + { + return this.addToBalance(-amount); + } + + @Override + public void setBalance(long newBalance) + { + balance.set(newBalance); + } +} diff --git a/Fossil/src/main/java/me/totalfreedom/fossil/economy/SimpleTransaction.java b/Fossil/src/main/java/me/totalfreedom/fossil/economy/SimpleTransaction.java new file mode 100644 index 0000000..4e3e008 --- /dev/null +++ b/Fossil/src/main/java/me/totalfreedom/fossil/economy/SimpleTransaction.java @@ -0,0 +1,38 @@ +package me.totalfreedom.fossil.economy; + +import me.totalfreedom.economy.EconomicEntity; +import me.totalfreedom.economy.Transaction; + +import java.util.concurrent.atomic.AtomicLong; + +public class SimpleTransaction implements Transaction +{ + private final EconomicEntity source; + private final EconomicEntity destination; + protected final AtomicLong balance; + + public SimpleTransaction(EconomicEntity source, EconomicEntity destination, long balance) + { + this.source = source; + this.destination = destination; + this.balance = new AtomicLong(balance); + } + + @Override + public EconomicEntity getSource() + { + return source; + } + + @Override + public EconomicEntity getDestination() + { + return destination; + } + + @Override + public long getBalance() + { + return balance.get(); + } +} diff --git a/Fossil/src/main/java/me/totalfreedom/fossil/economy/SimpleTransactionLogger.java b/Fossil/src/main/java/me/totalfreedom/fossil/economy/SimpleTransactionLogger.java new file mode 100644 index 0000000..e53551b --- /dev/null +++ b/Fossil/src/main/java/me/totalfreedom/fossil/economy/SimpleTransactionLogger.java @@ -0,0 +1,45 @@ +package me.totalfreedom.fossil.economy; + +import me.totalfreedom.audience.MutableAudienceForwarder; +import me.totalfreedom.economy.*; +import me.totalfreedom.utils.FreedomLogger; +import net.kyori.adventure.text.Component; + +public class SimpleTransactionLogger implements TransactionLogger +{ + private final MutableAudienceForwarder audience = MutableAudienceForwarder.from(FreedomLogger.getLogger("Fossil")); + + @Override + public void logTransaction(CompletedTransaction completedTransaction) + { + StringBuilder transactionLoggingStatementBuilder = new StringBuilder(); + TransactionResult result = completedTransaction.getResult(); + boolean resultSuccess = result.isSuccessful(); + String resultMessage = result.getMessage(); + + EconomicEntity source = completedTransaction.getSource(); + EconomicEntity destination = completedTransaction.getDestination(); + long transactionAmount = completedTransaction.getBalance(); + + transactionLoggingStatementBuilder.append(resultSuccess ? "Successful" : "Unsuccessful") + .append(" (") + .append(resultMessage) + .append(") ") + .append(" transaction between ") + .append(source.getName()) + .append(" ") + .append(destination.getName()) + .append(" where the volume of currency transferred was $") + .append(transactionAmount) + .append("."); + + Component message = Component.text(transactionLoggingStatementBuilder.toString()); + + audience.sendMessage(message); + } + + public MutableAudienceForwarder getAudienceForwarder() + { + return audience; + } +} diff --git a/Fossil/src/main/java/me/totalfreedom/fossil/economy/SimpleTransactionResult.java b/Fossil/src/main/java/me/totalfreedom/fossil/economy/SimpleTransactionResult.java new file mode 100644 index 0000000..258ae84 --- /dev/null +++ b/Fossil/src/main/java/me/totalfreedom/fossil/economy/SimpleTransactionResult.java @@ -0,0 +1,46 @@ +package me.totalfreedom.fossil.economy; + +import me.totalfreedom.economy.TransactionResult; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; + +public class SimpleTransactionResult implements TransactionResult +{ + public static final TransactionResult SUCCESSFUL = new SimpleTransactionResult("Successful transaction.", true); + public static final TransactionResult UNAUTHORIZED = new SimpleTransactionResult("Unauthorized transaction.", false); + public static final TransactionResult AMOUNT_TOO_SMALL = new SimpleTransactionResult("Transaction balance too small.", false); + public static final TransactionResult INSUFFICIENT_FUNDS = new SimpleTransactionResult("The source has an insufficient balance to carry out this transaction.", false); + private final String message; + private final Component component; + private final boolean successful; + + public SimpleTransactionResult(String message, boolean successful) + { + this(message, Component.text(message, successful ? NamedTextColor.GREEN : NamedTextColor.RED), successful); + } + + public SimpleTransactionResult(String message, Component component, boolean successful) + { + this.message = message; + this.component = component; + this.successful = successful; + } + + @Override + public String getMessage() + { + return message; + } + + @Override + public boolean isSuccessful() + { + return successful; + } + + @Override + public Component getComponent() + { + return component; + } +} diff --git a/Fossil/src/main/java/me/totalfreedom/fossil/economy/SimpleTransactor.java b/Fossil/src/main/java/me/totalfreedom/fossil/economy/SimpleTransactor.java new file mode 100644 index 0000000..735571e --- /dev/null +++ b/Fossil/src/main/java/me/totalfreedom/fossil/economy/SimpleTransactor.java @@ -0,0 +1,46 @@ +package me.totalfreedom.fossil.economy; + +import me.totalfreedom.economy.*; + +public class SimpleTransactor implements Transactor +{ + @Override + public CompletedTransaction handleTransaction(MutableTransaction transaction) + { + EconomicEntity source = transaction.getSource(); + EconomicEntityData sourceData = source.getEconomicData(); + + if (sourceData.areTransactionsFrozen()) + { + return new SimpleCompletedTransaction(transaction, SimpleTransactionResult.UNAUTHORIZED); + } + + long transactionAmount = transaction.getBalance(); + + if (transactionAmount >= 0) + { + return new SimpleCompletedTransaction(transaction, SimpleTransactionResult.AMOUNT_TOO_SMALL); + } + + long sourceBalance = sourceData.getBalance(); + long diff = sourceBalance - transactionAmount; + + if (diff > 0) + { + return new SimpleCompletedTransaction(transaction, SimpleTransactionResult.INSUFFICIENT_FUNDS); + } + + EconomicEntity destination = transaction.getDestination(); + EconomicEntityData destinationData = destination.getEconomicData(); + + if (destinationData.areTransactionsFrozen()) + { + return new SimpleCompletedTransaction(transaction, SimpleTransactionResult.UNAUTHORIZED); + } + + sourceData.removeFromBalance(transactionAmount); + destinationData.addToBalance(transactionAmount); + + return new SimpleCompletedTransaction(transaction, SimpleTransactionResult.SUCCESSFUL); + } +} diff --git a/Patchwork/src/main/java/me/totalfreedom/audience/MutableAudienceForwarder.java b/Patchwork/src/main/java/me/totalfreedom/audience/MutableAudienceForwarder.java new file mode 100644 index 0000000..60fc88b --- /dev/null +++ b/Patchwork/src/main/java/me/totalfreedom/audience/MutableAudienceForwarder.java @@ -0,0 +1,244 @@ +package me.totalfreedom.audience; + +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.bossbar.BossBar; +import net.kyori.adventure.chat.ChatType; +import net.kyori.adventure.chat.SignedMessage; +import net.kyori.adventure.inventory.Book; +import net.kyori.adventure.sound.Sound; +import net.kyori.adventure.sound.SoundStop; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.ComponentLike; +import net.kyori.adventure.title.Title; +import net.kyori.adventure.title.TitlePart; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Predicate; + +/** + * A replacement for {@link net.kyori.adventure.audience.ForwardingAudience} that allows for audiences to be removed & added at will. Not thread safe. + *

+ * This is intended for use in toggleable logging systems, for example, potion spy. + */ +// TODO: Work on thread-safety (or thread-safe alternative) +public class MutableAudienceForwarder implements Audience +{ + private final Set audiences = new HashSet<>(); + + public static MutableAudienceForwarder from(Audience... audiences) + { + MutableAudienceForwarder audienceForwarder = new MutableAudienceForwarder(); + + for (Audience audience : audiences) + { + audienceForwarder.addAudience(audience); + } + + return audienceForwarder; + } + + public void addAudience(Audience audience) + { + if (audiences.contains(audience) || audience == this /* Protect against honest self-referential calls */) + { + return; + } + + audiences.add(audience); + } + + public boolean removeAudience(Audience audience) + { + return audiences.remove(audience); + } + + + @Override + public @NotNull Audience filterAudience(@NotNull Predicate filter) + { + return audiences.stream() + .filter(filter) + .findFirst() + .orElseThrow(); + } + + @Override + public void forEachAudience(@NotNull Consumer action) + { + audiences.forEach(action); + } + + @Override + public void sendMessage(@NotNull ComponentLike message) + { + audiences.forEach(a -> a.sendMessage(message)); + } + + @Override + public void sendMessage(@NotNull Component message) + { + audiences.forEach(a -> a.sendMessage(message)); + } + + @Override + public void sendMessage(@NotNull Component message, ChatType.@NotNull Bound boundChatType) + { + audiences.forEach(a -> a.sendMessage(message, boundChatType)); + } + + @Override + public void sendMessage(@NotNull ComponentLike message, ChatType.@NotNull Bound boundChatType) + { + audiences.forEach(a -> a.sendMessage(message, boundChatType)); + } + + @Override + public void sendMessage(@NotNull SignedMessage signedMessage, ChatType.@NotNull Bound boundChatType) + { + audiences.forEach(a -> a.sendMessage(signedMessage, boundChatType)); + } + + @Override + public void deleteMessage(@NotNull SignedMessage signedMessage) + { + audiences.forEach(a -> a.deleteMessage(signedMessage)); + } + + @Override + public void deleteMessage(SignedMessage.@NotNull Signature signature) + { + audiences.forEach(a -> a.deleteMessage(signature)); + } + + // The methods below here will (probably) never be used, however it's good to keep them for completeness' sake. + + @Override + public void sendActionBar(@NotNull ComponentLike message) + { + audiences.forEach(a -> a.sendActionBar(message)); + } + + @Override + public void sendActionBar(@NotNull Component message) + { + audiences.forEach(a -> a.sendActionBar(message)); + } + + @Override + public void sendPlayerListHeader(@NotNull ComponentLike header) + { + audiences.forEach(a -> a.sendPlayerListHeader(header)); + } + + @Override + public void sendPlayerListHeader(@NotNull Component header) + { + audiences.forEach(a -> a.sendPlayerListHeader(header)); + } + + @Override + public void sendPlayerListFooter(@NotNull ComponentLike footer) + { + audiences.forEach(a -> a.sendPlayerListFooter(footer)); + } + + @Override + public void sendPlayerListFooter(@NotNull Component footer) + { + audiences.forEach(a -> a.sendPlayerListFooter(footer)); + } + + @Override + public void sendPlayerListHeaderAndFooter(@NotNull ComponentLike header, @NotNull ComponentLike footer) + { + audiences.forEach(a -> a.sendPlayerListHeaderAndFooter(header, footer)); + } + + @Override + public void sendPlayerListHeaderAndFooter(@NotNull Component header, @NotNull Component footer) + { + audiences.forEach(a -> a.sendPlayerListHeaderAndFooter(header, footer)); + } + + @Override + public void showTitle(@NotNull Title title) + { + audiences.forEach(a -> a.showTitle(title)); + } + + @Override + public void sendTitlePart(@NotNull TitlePart part, @NotNull T value) + { + audiences.forEach(a -> a.sendTitlePart(part, value)); + } + + @Override + public void clearTitle() + { + audiences.forEach(Audience::clearTitle); + } + + @Override + public void resetTitle() + { + audiences.forEach(Audience::resetTitle); + } + + @Override + public void showBossBar(@NotNull BossBar bar) + { + audiences.forEach(a -> a.showBossBar(bar)); + } + + @Override + public void hideBossBar(@NotNull BossBar bar) + { + audiences.forEach(a -> a.hideBossBar(bar)); + } + + @Override + public void playSound(@NotNull Sound sound) + { + audiences.forEach(a -> a.playSound(sound)); + } + + @Override + public void playSound(@NotNull Sound sound, double x, double y, double z) + { + + audiences.forEach(a -> a.playSound(sound, x, y, z)); + } + + @Override + public void playSound(@NotNull Sound sound, Sound.@NotNull Emitter emitter) + { + audiences.forEach(a -> a.playSound(sound, emitter)); + } + + @Override + public void stopSound(@NotNull Sound sound) + { + audiences.forEach(a -> a.stopSound(sound)); + } + + @Override + public void stopSound(@NotNull SoundStop stop) + { + audiences.forEach(a -> a.stopSound(stop)); + } + + @Override + public void openBook(Book.@NotNull Builder book) + { + audiences.forEach(a -> a.openBook(book)); + } + + @Override + public void openBook(@NotNull Book book) + { + audiences.forEach(a -> a.openBook(book)); + } +} diff --git a/Patchwork/src/main/java/me/totalfreedom/economy/CompletedTransaction.java b/Patchwork/src/main/java/me/totalfreedom/economy/CompletedTransaction.java new file mode 100644 index 0000000..7b58dfd --- /dev/null +++ b/Patchwork/src/main/java/me/totalfreedom/economy/CompletedTransaction.java @@ -0,0 +1,7 @@ +package me.totalfreedom.economy; + +public interface CompletedTransaction extends Transaction +{ + + TransactionResult getResult(); +} diff --git a/Patchwork/src/main/java/me/totalfreedom/economy/EconomicEntity.java b/Patchwork/src/main/java/me/totalfreedom/economy/EconomicEntity.java new file mode 100644 index 0000000..1855d1e --- /dev/null +++ b/Patchwork/src/main/java/me/totalfreedom/economy/EconomicEntity.java @@ -0,0 +1,8 @@ +package me.totalfreedom.economy; + +public interface EconomicEntity +{ + EconomicEntityData getEconomicData(); + + String getName(); +} diff --git a/Patchwork/src/main/java/me/totalfreedom/economy/EconomicEntityData.java b/Patchwork/src/main/java/me/totalfreedom/economy/EconomicEntityData.java new file mode 100644 index 0000000..308a6c0 --- /dev/null +++ b/Patchwork/src/main/java/me/totalfreedom/economy/EconomicEntityData.java @@ -0,0 +1,14 @@ +package me.totalfreedom.economy; + +public interface EconomicEntityData +{ + boolean areTransactionsFrozen(); + + long getBalance(); + + long addToBalance(final long amount); + + long removeFromBalance(final long amount); + + void setBalance(final long newBalance); +} diff --git a/Patchwork/src/main/java/me/totalfreedom/economy/MutableTransaction.java b/Patchwork/src/main/java/me/totalfreedom/economy/MutableTransaction.java new file mode 100644 index 0000000..8548fa7 --- /dev/null +++ b/Patchwork/src/main/java/me/totalfreedom/economy/MutableTransaction.java @@ -0,0 +1,13 @@ +package me.totalfreedom.economy; + +/** + * Please ensure that all modifications of {@link MutableTransaction} happen BEFORE it is passed to a {@link Transactor} implementation + */ +public interface MutableTransaction extends Transaction +{ + long addToBalance(final long amount); + + long removeFromBalance(final long amount); + + void setBalance(final long newBalance); +} diff --git a/Patchwork/src/main/java/me/totalfreedom/economy/Transaction.java b/Patchwork/src/main/java/me/totalfreedom/economy/Transaction.java new file mode 100644 index 0000000..eb0e310 --- /dev/null +++ b/Patchwork/src/main/java/me/totalfreedom/economy/Transaction.java @@ -0,0 +1,11 @@ +package me.totalfreedom.economy; + +public interface Transaction +{ + EconomicEntity getSource(); + + EconomicEntity getDestination(); + + long getBalance(); + +} diff --git a/Patchwork/src/main/java/me/totalfreedom/economy/TransactionLogger.java b/Patchwork/src/main/java/me/totalfreedom/economy/TransactionLogger.java new file mode 100644 index 0000000..f8dce2d --- /dev/null +++ b/Patchwork/src/main/java/me/totalfreedom/economy/TransactionLogger.java @@ -0,0 +1,6 @@ +package me.totalfreedom.economy; + +public interface TransactionLogger +{ + void logTransaction(CompletedTransaction completedTransaction); +} diff --git a/Patchwork/src/main/java/me/totalfreedom/economy/TransactionResult.java b/Patchwork/src/main/java/me/totalfreedom/economy/TransactionResult.java new file mode 100644 index 0000000..fd4a13d --- /dev/null +++ b/Patchwork/src/main/java/me/totalfreedom/economy/TransactionResult.java @@ -0,0 +1,12 @@ +package me.totalfreedom.economy; + +import net.kyori.adventure.text.Component; + +public interface TransactionResult +{ + String getMessage(); + + boolean isSuccessful(); + + Component getComponent(); +} diff --git a/Patchwork/src/main/java/me/totalfreedom/economy/Transactor.java b/Patchwork/src/main/java/me/totalfreedom/economy/Transactor.java new file mode 100644 index 0000000..8fd9c47 --- /dev/null +++ b/Patchwork/src/main/java/me/totalfreedom/economy/Transactor.java @@ -0,0 +1,6 @@ +package me.totalfreedom.economy; + +public interface Transactor +{ + CompletedTransaction handleTransaction(MutableTransaction transaction); +} diff --git a/Patchwork/src/main/java/me/totalfreedom/user/User.java b/Patchwork/src/main/java/me/totalfreedom/user/User.java index 839abf5..b83876e 100644 --- a/Patchwork/src/main/java/me/totalfreedom/user/User.java +++ b/Patchwork/src/main/java/me/totalfreedom/user/User.java @@ -1,10 +1,25 @@ package me.totalfreedom.user; import me.totalfreedom.security.perm.PermissionHolder; +import me.totalfreedom.economy.EconomicEntity; +import me.totalfreedom.economy.EconomicEntityData; import net.kyori.adventure.text.Component; -public interface User extends PermissionHolder +public interface User extends PermissionHolder, EconomicEntity { + // Implement a few EconomicEntity methods in the User interface + @Override + default String getName() + { + return getUserData().getUsername(); + } + + @Override + default EconomicEntityData getEconomicData() + { + return getUserData(); + } + UserData getUserData(); Component getDisplayName(); diff --git a/Patchwork/src/main/java/me/totalfreedom/user/UserData.java b/Patchwork/src/main/java/me/totalfreedom/user/UserData.java index 75dea74..e7b4253 100644 --- a/Patchwork/src/main/java/me/totalfreedom/user/UserData.java +++ b/Patchwork/src/main/java/me/totalfreedom/user/UserData.java @@ -1,12 +1,13 @@ package me.totalfreedom.user; import me.totalfreedom.security.perm.Group; +import me.totalfreedom.economy.EconomicEntityData; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.UUID; -public interface UserData +public interface UserData extends EconomicEntityData { @NotNull UUID getUniqueId(); diff --git a/Patchwork/src/main/java/me/totalfreedom/utils/FreedomAdventure.java b/Patchwork/src/main/java/me/totalfreedom/utils/FreedomAdventure.java new file mode 100644 index 0000000..cd0fa3d --- /dev/null +++ b/Patchwork/src/main/java/me/totalfreedom/utils/FreedomAdventure.java @@ -0,0 +1,48 @@ +package me.totalfreedom.utils; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; + +import java.util.function.Supplier; + +/** + * This class contains the only reference to plain text component serializer, and allows access to it via wrapper functions. + */ +public class FreedomAdventure +{ + private FreedomAdventure() + { + throw new UnsupportedOperationException("Instantiation of a static utility class is not supported."); + } + + private static final PlainTextComponentSerializer PLAIN_TEXT_COMPONENT_SERIALIZER = PlainTextComponentSerializer.plainText(); + + public static String toPlainText(Component component) + { + return PLAIN_TEXT_COMPONENT_SERIALIZER.serialize(component); + } + + public static String toPlainText(Supplier supplier) + { + return toPlainText(supplier.get()); + } + + public static Supplier supplyPlainText(Supplier supplier) + { + return new StringRepresentationSupplier(supplier.get()); + } + + public static Supplier supplyPlainText(Component component) + { + return new StringRepresentationSupplier(component); + } + + private record StringRepresentationSupplier(Component component) implements Supplier + { + @Override + public String get() + { + return PLAIN_TEXT_COMPONENT_SERIALIZER.serialize(component); + } + } +} diff --git a/Patchwork/src/main/java/me/totalfreedom/utils/FreedomLogger.java b/Patchwork/src/main/java/me/totalfreedom/utils/FreedomLogger.java index 104ce87..37e2953 100644 --- a/Patchwork/src/main/java/me/totalfreedom/utils/FreedomLogger.java +++ b/Patchwork/src/main/java/me/totalfreedom/utils/FreedomLogger.java @@ -1,12 +1,17 @@ package me.totalfreedom.utils; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.chat.ChatType; +import net.kyori.adventure.chat.SignedMessage; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.ComponentLike; +import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.function.Supplier; -public class FreedomLogger +public class FreedomLogger implements Audience { private final Logger logger; private boolean debug = false; @@ -36,6 +41,20 @@ public class FreedomLogger logger.info(message); } + /** + * This method allows you to log a component to the console. + * + * @param component The component to send. + * @return A plain text representation of the message + */ + public String infoComponent(Component component) + { + String plainText = FreedomAdventure.toPlainText(component); + + logger.info(plainText); + return plainText; + } + /** * This method allows you to log a message to the console, * while also returning a Component that could be used to @@ -50,6 +69,19 @@ public class FreedomLogger return Component.text(message.get()); } + /** + * This method allows you to log a component to the console, + * while also returning a String representation of the + * component + * + * @param component The component to send. + * @return A string representation of the message. + */ + public String infoComponent(Supplier component) + { + return this.infoComponent(component.get()); + } + /** * This method allows you to log a warning to the console. * @@ -60,6 +92,18 @@ public class FreedomLogger logger.warn(message); } + /** + * This method allows you to log a warning to the console. + * + * @param component The component to send. + */ + public void warnComponent(Component component) + { + String plainText = FreedomAdventure.toPlainText(component); + + logger.warn(plainText); + } + /** * This method logs an error message to the console. * It is highly recommended to deconstruct the stack trace and pass it @@ -72,6 +116,20 @@ public class FreedomLogger logger.error(message); } + /** + * This method logs an error component to the console. + * + * @param component The message to send. + */ + public String errorComponent(Component component) + { + String plainText = FreedomAdventure.toPlainText(component); + + logger.error(plainText); + + return plainText; + } + /** * This method allows you to log an exception directly to the console. * @@ -98,6 +156,19 @@ public class FreedomLogger return Component.text(message.get()); } + /** + * This method allows you to log an error component to the console, + * while also returning a String representation of the error + * component. + * + * @param component The component to send. + * @return A String representation of the component. + */ + public String errorComponent(Supplier component) + { + return this.errorComponent(component.get()); + } + /** * This method allows you to log a debug message to the console. * This method will only log if debug mode is enabled. @@ -110,6 +181,21 @@ public class FreedomLogger logger.debug(message); } + /** + * This method allows you to log a debug component to the console. + * This method will only log if debug mode is enabled. + * + * @param component The component to send. + */ + public String debugComponent(Component component) + { + String plainText = FreedomAdventure.toPlainText(component); + + this.debug(plainText); + + return plainText; + } + /** * This method allows you to log a debug message to the console, * while also returning a Component that could be used to @@ -128,4 +214,59 @@ public class FreedomLogger } return Component.empty(); } + + /** + * This method allows you to log a debug component to the console, + * while also returning a String representation of the debug component. + * + * @param component The component to send. + * @return A String representation of the message. + */ + public String debugComponent(Supplier component) + { + if (debug) + { + return this.debugComponent(component.get()); + } + return ""; + } + + + @Override + public void sendMessage(@NotNull ComponentLike message) + { + Component component = ComponentLike.unbox(message); + + if (component == null) + { + this.info("**null component-like**"); + return; + } + + this.infoComponent(component); + } + + @Override + public void sendMessage(@NotNull Component message) + { + this.infoComponent(message); + } + + @Override + public void sendMessage(@NotNull Component message, ChatType.@NotNull Bound boundChatType) + { + this.infoComponent(message); + } + + @Override + public void sendMessage(@NotNull ComponentLike message, ChatType.@NotNull Bound boundChatType) + { + this.sendMessage(message); + } + + @Override + public void sendMessage(@NotNull SignedMessage signedMessage, ChatType.@NotNull Bound boundChatType) + { + this.info(signedMessage.message()); // TODO: We might want to investigate whether this logs the ENTIRE message, including unsigned & signed content, or only the signed part. This method was written in the assumption that it provided all content. + } } diff --git a/README.md b/README.md index 4b7e594..8d9dc51 100644 --- a/README.md +++ b/README.md @@ -55,3 +55,43 @@ This proof-of-concept also uses the following libraries: [](https://github.com/VideoGameSmash12)
[](https://github.com/allinkdev) + +# To Do List +Patchwork: +- [x] Logging System +- [x] SQL API +- [x] Economy API +- [ ] Command API +- [ ] Particle API +- [x] User API +- [ ] Ban API +- [x] Service API +- [x] Task API +- [x] Permissions API +- [ ] Configuration API +- [ ] Event API + +Datura: +- [ ] Permission Handling +- [ ] Permission Registration & Assignment +- [ ] SQL Data Handling +- [ ] Configuration Implementations +- [ ] User Data Implementations +- [ ] Banning Implementation +- [ ] Punishment Systems (e.x. Locker, Halter, Muter, Cager) + +Fossil: +- [x] Economy Implementation +- [ ] Particle Implementation / Trails +- [ ] Command Implementations +- [ ] Implement a shop for the economy +- [ ] Chat reaction / game system +- [ ] Jumppads + +Corvo: +- [ ] Service Implementation +- [ ] Service Handling +- [ ] Task Implementation +- [ ] Task Management +- [ ] Event (Project) Implementations +- [ ] Listener (Bukkit) Implementations