From 0b601d9bb7b45044fc6cc5e0f91e578d13b55625 Mon Sep 17 00:00:00 2001 From: EpicKnarvik97 Date: Tue, 9 Jan 2024 18:22:50 +0100 Subject: [PATCH] Adds a highly configurable option for deciding the base payout --- README.md | 33 ++-- .../playerpayouts/PlayerPayouts.java | 2 +- .../command/SetGroupPaymentCommand.java | 16 +- .../command/SetPlayerPaymentCommand.java | 16 +- .../playerpayouts/config/Configuration.java | 166 ++++++++++++++++-- .../config/ConfigurationKey.java | 5 + .../config/payout/PayoutAction.java | 15 ++ .../config/payout/PayoutActionParser.java | 127 ++++++++++++++ .../config/payout/PayoutComponent.java | 7 + .../config/payout/PayoutDelimiter.java | 45 +++++ .../config/payout/PayoutTarget.java | 62 +++++++ src/main/resources/config.yml | 9 + src/main/resources/plugin.yml | 18 +- 13 files changed, 455 insertions(+), 66 deletions(-) create mode 100644 src/main/java/net/knarcraft/playerpayouts/config/payout/PayoutAction.java create mode 100644 src/main/java/net/knarcraft/playerpayouts/config/payout/PayoutActionParser.java create mode 100644 src/main/java/net/knarcraft/playerpayouts/config/payout/PayoutComponent.java create mode 100644 src/main/java/net/knarcraft/playerpayouts/config/payout/PayoutDelimiter.java create mode 100644 src/main/java/net/knarcraft/playerpayouts/config/payout/PayoutTarget.java diff --git a/README.md b/README.md index 0ef9b71..6e2320a 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,9 @@ plugin is a configurable bonus once players reach a specified total play-time on configurable. You can alter the base payout per-group or per-player, you can adjust how often players are paid, how big a percentage is paid to AFK players and whether players are alerted upon receiving a payout. -The logic for which payout is used is as follows: - -- If a payout is set for a player, that payout will be used. -- If a payout is set for one or more of a player's group, the highest value will be used. -- If none of the above apply, the base pay is used. +You can configure how the base pay is combined from the four components of: the base payout, the highest group payout, +the sum of group payouts and the player payout. You can combine several, or have some as fallback if the others aren't +set. Once a second, any players that have played longer than the specified payout delay are paid, and their internally tracked playtime is reset. This is an improvement over plugins that simply pay players on a set delay, as that just ends @@ -30,7 +28,7 @@ up being a game of chance. If you are lucky, you are paid immediately after join | Command | Arguments | Description | |--------------------------------------|-------------------|------------------------------------------| -| /timeismoney:reload | | Reloads the configuration file from disk | +| /playerpayouts:reload | | Reloads the configuration file from disk | | [/setgrouppayout](#setgrouppayout) | | Sets the payout for a specific group | | [/setplayerpayout](#setplayerpayout) | | Sets the payout for a specific player | @@ -66,11 +64,24 @@ This command is used to override the payout for a specific group. | hoursUntilBonus | number / -1 | The amount of hours a player must play until they start receiving a payout bonus, or -1 to disable the feature | | bonusMultiplier | decimal number | A multiplier used to increase or decrease the time bonus ((hours played / hours until bonus) * bonusMultiplier) + payout | | afkPercentage | percentage (0-100) | The percentage of their normal payout to pay AFK players | +| payoutRules | special string | The rules for how a player's base pay (before the bonus multiplier) is calculated. See [this section](#payoutrules) | + +### payoutRules + +The rules for how the base payout is calculated. "," = OR, "+" = AND. "p" or "player" is the override for a specific +player. "g" or "groups" is the sum of all group overrides for a specific player. "hg" or "HighestGroup" is the highest +sum of all of a specific player's groups. "b" or "base" is the default base payment. + +If you wanted to give players the sum of everything, you'd set it to "p+g+b", which is read as "player override and sum +of group overrides + base payout". If you wanted to give players the sum of their personal override and their highest +group, but fall back to the base pay, you'd set it to: "p+hg,b" (personal override and highest group override, or the +base payout). If the payout rule you set ends up giving 0 as the payment, it will fall back to the default of "p,hg,b" ( +player override, or highest group override, or base payout) ## Permissions -| Permission | Description | -|--------------------|----------------------------------------| -| timeismoney.* | Grants all permissions | -| timeismoney.reload | Allows usage of the reload command | -| timeismoney.admin | Allows usage of configuration commands | \ No newline at end of file +| Permission | Description | +|----------------------|----------------------------------------| +| playerpayouts.* | Grants all permissions | +| playerpayouts.reload | Allows usage of the reload command | +| playerpayouts.admin | Allows usage of configuration commands | \ No newline at end of file diff --git a/src/main/java/net/knarcraft/playerpayouts/PlayerPayouts.java b/src/main/java/net/knarcraft/playerpayouts/PlayerPayouts.java index d87ee04..3c45d75 100644 --- a/src/main/java/net/knarcraft/playerpayouts/PlayerPayouts.java +++ b/src/main/java/net/knarcraft/playerpayouts/PlayerPayouts.java @@ -111,7 +111,7 @@ public final class PlayerPayouts extends JavaPlugin { public static void reload() { playerPayouts.reloadConfig(); playerPayouts.saveConfig(); - playerPayouts.configuration = new Configuration(playerPayouts.getConfig()); + playerPayouts.configuration.load(playerPayouts.getConfig()); } /** diff --git a/src/main/java/net/knarcraft/playerpayouts/command/SetGroupPaymentCommand.java b/src/main/java/net/knarcraft/playerpayouts/command/SetGroupPaymentCommand.java index 2199c42..e716aeb 100644 --- a/src/main/java/net/knarcraft/playerpayouts/command/SetGroupPaymentCommand.java +++ b/src/main/java/net/knarcraft/playerpayouts/command/SetGroupPaymentCommand.java @@ -7,7 +7,6 @@ import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** * A command for overriding payments for specific groups @@ -41,11 +40,11 @@ public class SetGroupPaymentCommand implements CommandExecutor { try { String group = arguments[0]; if (StringHelper.isNonValue(arguments[1])) { - setPayout(group, null); + configuration.setGroupPayout(group, null); commandSender.sendMessage(String.format("Group payout for group %s has been cleared", group)); } else { Double payout = Double.parseDouble(arguments[1]); - setPayout(group, payout); + configuration.setGroupPayout(group, payout); commandSender.sendMessage(String.format("Group payout for group %s has been set to %s", group, payout)); } return true; @@ -55,15 +54,4 @@ public class SetGroupPaymentCommand implements CommandExecutor { } } - /** - * Sets the payout for the given group - * - * @param group

The group to set payout for

- * @param payout

The payout to set

- */ - private void setPayout(@NotNull String group, @Nullable Double payout) { - configuration.setGroupPayout(group, payout); - configuration.save(); - } - } diff --git a/src/main/java/net/knarcraft/playerpayouts/command/SetPlayerPaymentCommand.java b/src/main/java/net/knarcraft/playerpayouts/command/SetPlayerPaymentCommand.java index c1b47a4..957c58e 100644 --- a/src/main/java/net/knarcraft/playerpayouts/command/SetPlayerPaymentCommand.java +++ b/src/main/java/net/knarcraft/playerpayouts/command/SetPlayerPaymentCommand.java @@ -9,7 +9,6 @@ import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.UUID; @@ -66,11 +65,11 @@ public class SetPlayerPaymentCommand implements CommandExecutor { // Parse the payout value try { if (StringHelper.isNonValue(arguments[1])) { - setPayout(playerId, null); + configuration.setPlayerPayout(playerId, null); commandSender.sendMessage(String.format("Player payout for player %s has been cleared", playerName)); } else { Double payout = Double.parseDouble(arguments[1]); - setPayout(playerId, payout); + configuration.setPlayerPayout(playerId, payout); commandSender.sendMessage(String.format("Player payout for player %s has been set to %s", playerName, payout)); } @@ -81,15 +80,4 @@ public class SetPlayerPaymentCommand implements CommandExecutor { } } - /** - * Sets the payout for the given player - * - * @param playerId

The player to set payout for

- * @param payout

The payout to set

- */ - private void setPayout(@NotNull UUID playerId, @Nullable Double payout) { - configuration.setPlayerPayout(playerId, payout); - configuration.save(); - } - } diff --git a/src/main/java/net/knarcraft/playerpayouts/config/Configuration.java b/src/main/java/net/knarcraft/playerpayouts/config/Configuration.java index 6e7c1c8..73046b1 100644 --- a/src/main/java/net/knarcraft/playerpayouts/config/Configuration.java +++ b/src/main/java/net/knarcraft/playerpayouts/config/Configuration.java @@ -1,32 +1,41 @@ package net.knarcraft.playerpayouts.config; import net.knarcraft.playerpayouts.PlayerPayouts; +import net.knarcraft.playerpayouts.config.payout.PayoutAction; +import net.knarcraft.playerpayouts.config.payout.PayoutActionParser; +import net.knarcraft.playerpayouts.config.payout.PayoutComponent; +import net.knarcraft.playerpayouts.config.payout.PayoutDelimiter; +import net.knarcraft.playerpayouts.config.payout.PayoutTarget; import net.knarcraft.playerpayouts.manager.PermissionManager; +import org.apache.commons.lang.NotImplementedException; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.text.ParseException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.logging.Level; /** * This plugin's configuration */ public class Configuration { - private final FileConfiguration fileConfiguration; - private final Map groupPayouts; - private final Map playerPayouts; - private final double defaultPayout; - private final int hoursUntilBonus; - private final double bonusMultiplier; - private final int payoutDelay; - private final double afkPercentage; - private final boolean displayPaymentMessage; + private FileConfiguration fileConfiguration; + private Map groupPayouts; + private Map playerPayouts; + private double defaultPayout; + private int hoursUntilBonus; + private double bonusMultiplier; + private int payoutDelay; + private double afkPercentage; + private boolean displayPaymentMessage; + private PayoutComponent payoutComponent; /** * Instantiates a new configuration @@ -34,6 +43,15 @@ public class Configuration { * @param fileConfiguration

The file configuration to read values from

*/ public Configuration(@NotNull FileConfiguration fileConfiguration) { + load(fileConfiguration); + } + + /** + * Loads the configuration specified in the given file configuration + * + * @param fileConfiguration

The file configuration to load

+ */ + public void load(@NotNull FileConfiguration fileConfiguration) { groupPayouts = new HashMap<>(); playerPayouts = new HashMap<>(); this.fileConfiguration = fileConfiguration; @@ -57,6 +75,19 @@ public class Configuration { this.payoutDelay = fileConfiguration.getInt(ConfigurationKey.PAYOUT_DELAY.getPath(), 60); this.afkPercentage = fileConfiguration.getDouble(ConfigurationKey.AFK_PERCENTAGE.getPath(), 0); this.displayPaymentMessage = fileConfiguration.getBoolean(ConfigurationKey.DISPLAY_PAYMENT_MESSAGE.getPath(), true); + try { + this.payoutComponent = PayoutActionParser.matchPayoutComponent(fileConfiguration.getString( + ConfigurationKey.PAYOUT_RULES.getPath(), "p,hg,b")); + } catch (ParseException exception) { + PlayerPayouts.getInstance().getLogger().log(Level.SEVERE, "Unable to parse your payout rules! Please " + + "check your configuration file! Falling back to default!"); + PlayerPayouts.getInstance().getLogger().log(Level.SEVERE, exception.getMessage()); + try { + this.payoutComponent = PayoutActionParser.matchPayoutComponent("p,hg,b"); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } } /** @@ -81,37 +112,86 @@ public class Configuration { return bonusMultiplier; } + /** + * Gets the base pay for the given player + * + * @param player

The player to get the base pay for

+ * @return

The base pay for the player

+ */ + public double getBasePay(@NotNull Player player) { + double pay = calculatePayoutFromComponent(payoutComponent, player); + if (pay != 0) { + return pay; + } else { + return getDefaultBasePay(player); + } + } + /** * Gets the base payout to pay the given player * * @param player

The player to get the base payout for

* @return

The player's base pay

*/ - public double getBasePay(@NotNull Player player) { + public double getDefaultBasePay(@NotNull Player player) { if (playerPayouts.get(player.getUniqueId()) != null) { return playerPayouts.get(player.getUniqueId()); } - double groupPayout = -1; + double groupPayout = 0; if (PermissionManager.isInitialized()) { - groupPayout = getGroupPayout(player); + groupPayout = getGroupPayout(player, true); } - if (groupPayout == -1) { + if (groupPayout == 0) { return defaultPayout; } else { return groupPayout; } } + /** + * Gets the max payout of the given player's permission groups + * + * @param player

The player to get the group payout for

+ * @param highest

Whether to just get the highest value, instead of the sum

+ * @return

The group payout, or -1 if no groups has a set payout

+ */ + private double getGroupPayout(@NotNull Player player, boolean highest) { + if (highest) { + return getHighestGroupPayout(player); + } else { + return getSumGroupPayout(player); + } + } + /** * Gets the max payout of the given player's permission groups * * @param player

The player to get the group payout for

* @return

The group payout, or -1 if no groups has a set payout

*/ - private double getGroupPayout(@NotNull Player player) { - double maxPay = -1; + private double getSumGroupPayout(@NotNull Player player) { + double total = 0; + for (String group : PermissionManager.getPlayerGroups(player)) { + if (groupPayouts.containsKey(group)) { + Double groupPayout = groupPayouts.get(group); + if (groupPayout != null) { + total += groupPayout; + } + } + } + return total; + } + + /** + * Gets the max payout of the given player's permission groups + * + * @param player

The player to get the group payout for

+ * @return

The group payout, or -1 if no groups has a set payout

+ */ + private double getHighestGroupPayout(@NotNull Player player) { + double maxPay = 0; for (String group : PermissionManager.getPlayerGroups(player)) { if (groupPayouts.containsKey(group)) { Double groupPayout = groupPayouts.get(group); @@ -162,6 +242,7 @@ public class Configuration { } else { this.playerPayouts.put(playerId, payout); } + this.save(); } /** @@ -176,6 +257,7 @@ public class Configuration { } else { this.groupPayouts.put(groupName, payout); } + this.save(); } /** @@ -188,7 +270,8 @@ public class Configuration { fileConfiguration.set(ConfigurationKey.BONUS_MULTIPLIER.getPath(), this.bonusMultiplier); fileConfiguration.setComments(ConfigurationKey.BONUS_MULTIPLIER.getPath(), - List.of("A multiplier used to increase or decrease the time bonus ((hours played / hours until bonus) * bonusMultiplier) + payout")); + List.of("A multiplier used to increase or decrease the time bonus ((hours played / hours until " + + "bonus) * bonusMultiplier) + payout")); fileConfiguration.set(ConfigurationKey.DEFAULT_PAYOUT.getPath(), this.defaultPayout); fileConfiguration.setComments(ConfigurationKey.DEFAULT_PAYOUT.getPath(), @@ -224,9 +307,18 @@ public class Configuration { fileConfiguration.setComments(ConfigurationKey.GROUP_PAYOUTS.getPath(), List.of("Overrides for specific groups")); + fileConfiguration.setComments(ConfigurationKey.PAYOUT_RULES.getPath(), List.of("The rules for how the base payout " + + "is calculated. \",\" = OR, \"+\" = AND. \"p\" or \"player\" is the override for a specific player. \"g\"", + " or \"groups\" is the sum of all group overrides for a specific player. \"hg\" or \"HighestGroup\" " + + "is the highest sum of all", " of a specific player's groups. \"b\" or \"base\" is the default" + + " base payment.", "", "If you wanted to give players the sum of everything, you'd set it to " + + "\"p+g+b\".", "If you wanted to give players the sum of their personal override and their " + + "highest group, but fall back to the base", " pay, you'd set it to: \"p+hg,b\"", "If the payout" + + " rule you set ends up giving 0 as the payment, it will fall back to the default of \"p,hg,b\"")); + PlayerPayouts.getInstance().saveConfig(); - // Null values are necessary for updating removed keys, but should not appear otherwise + // Remove any null values, as those aren't useful except for clearing values for (Map.Entry entry : groupPayouts.entrySet()) { if (entry.getValue() == null) { groupPayouts.remove(entry.getKey()); @@ -239,4 +331,44 @@ public class Configuration { } } + /** + * Calculates payment from the given payout component + * + * @param payoutComponent

The payout component to calculate from

+ * @param player

The player to calculate payment for

+ * @return

+ */ + private double calculatePayoutFromComponent(@NotNull PayoutComponent payoutComponent, @NotNull Player player) { + if (payoutComponent instanceof PayoutTarget target) { + // Get the value of the payout target + return switch (target) { + case BASE -> defaultPayout; + case PLAYER -> playerPayouts.getOrDefault(player.getUniqueId(), 0d); + case GROUPS -> getGroupPayout(player, false); + case HIGHEST_GROUP -> getGroupPayout(player, true); + }; + } else if (payoutComponent instanceof PayoutAction action) { + PayoutDelimiter delimiter = action.delimiter(); + if (delimiter == PayoutDelimiter.ADD) { + // Return the sum of the two components + return calculatePayoutFromComponent(action.component1(), player) + + calculatePayoutFromComponent(action.component2(), player); + } else if (delimiter == PayoutDelimiter.OR) { + // Get the result of the first component, or the second one if the first is zero + double value = calculatePayoutFromComponent(action.component1(), player); + if (value > 0) { + return value; + } else { + return calculatePayoutFromComponent(action.component2(), player); + } + } else { + throw new NotImplementedException("The encountered payout delimiter is not implemented. " + + "Please inform the developer!"); + } + } else { + throw new NotImplementedException("An unknown type of payout component was encountered." + + "Please inform the developer!"); + } + } + } diff --git a/src/main/java/net/knarcraft/playerpayouts/config/ConfigurationKey.java b/src/main/java/net/knarcraft/playerpayouts/config/ConfigurationKey.java index a636a3e..5bd9411 100644 --- a/src/main/java/net/knarcraft/playerpayouts/config/ConfigurationKey.java +++ b/src/main/java/net/knarcraft/playerpayouts/config/ConfigurationKey.java @@ -34,6 +34,11 @@ public enum ConfigurationKey { */ DISPLAY_PAYMENT_MESSAGE("displayPaymentMessage"), + /** + * The rules for how the base payouts are calculated + */ + PAYOUT_RULES("payoutRules"), + /** * Payout overrides for each group */ diff --git a/src/main/java/net/knarcraft/playerpayouts/config/payout/PayoutAction.java b/src/main/java/net/knarcraft/playerpayouts/config/payout/PayoutAction.java new file mode 100644 index 0000000..cd4b87e --- /dev/null +++ b/src/main/java/net/knarcraft/playerpayouts/config/payout/PayoutAction.java @@ -0,0 +1,15 @@ +package net.knarcraft.playerpayouts.config.payout; + +import org.jetbrains.annotations.NotNull; + +/** + * Instantiates a new payout action + * + * @param component1

The component "to the left of" the delimiter

+ * @param delimiter

The delimiter between the two components

+ * @param component2

The component "to the right of" the delimiter

+ */ +public record PayoutAction(@NotNull PayoutComponent component1, @NotNull PayoutDelimiter delimiter, + @NotNull PayoutComponent component2) implements PayoutComponent { + +} diff --git a/src/main/java/net/knarcraft/playerpayouts/config/payout/PayoutActionParser.java b/src/main/java/net/knarcraft/playerpayouts/config/payout/PayoutActionParser.java new file mode 100644 index 0000000..c842e87 --- /dev/null +++ b/src/main/java/net/knarcraft/playerpayouts/config/payout/PayoutActionParser.java @@ -0,0 +1,127 @@ +package net.knarcraft.playerpayouts.config.payout; + +import org.apache.commons.lang.NotImplementedException; +import org.jetbrains.annotations.NotNull; + +import java.text.ParseException; +import java.util.ArrayList; +import java.util.List; + +/** + * A parser for the payout mode string + */ +public class PayoutActionParser { + + /** + * Matches a payout component from the input string + * + * @param toMatch

The string to match

+ * @return

A payout component describing how to handle payouts

+ * @throws ParseException

If unable to parse the input string

+ */ + public static PayoutComponent matchPayoutComponent(@NotNull String toMatch) throws ParseException { + List parts = tokenize(toMatch); + return parsePayoutComponent(parts, 0); + } + + /** + * Parses a payout component from the given input + * + * @param parts

The list of components to parse

+ * @param index

The index of the list to start at

+ * @return

The parsed payout component

+ * @throws ParseException

If unable to parse the input

+ */ + private static @NotNull PayoutComponent parsePayoutComponent(@NotNull List parts, + int index) throws ParseException { + PayoutComponent payoutComponent = null; + + if (parts.size() <= index) { + throw new ParseException("Found no payout mode information to parse", 0); + } + + for (int i = index; i < parts.size(); i++) { + if (payoutComponent == null) { + String part = parts.get(i); + PayoutTarget target = PayoutTarget.match(part); + if (target == null) { + throw new ParseException("Unable to parse payout mode string component " + part + "!", i); + } + payoutComponent = target; + if (parts.size() == 1) { + return payoutComponent; + } + } + + // Stop here, as the last component has already been parsed + if (i + 1 >= parts.size()) { + return payoutComponent; + } + + PayoutDelimiter delimiter = PayoutDelimiter.match(parts.get(++i).charAt(0)); + if (delimiter == null) { + throw new ParseException("Unable to parse payout mode string delimiter " + parts.get(i) + "!", i); + } + + if (delimiter == PayoutDelimiter.ADD) { + PayoutTarget target2 = PayoutTarget.match(parts.get(++i)); + if (target2 == null) { + throw new ParseException("Unable to parse payout mode string component " + parts.get(i) + "!", i); + } + payoutComponent = new PayoutAction(payoutComponent, delimiter, target2); + // The index has to be held back to prevent the parser from skipping the delimiter + i--; + } else if (delimiter == PayoutDelimiter.OR) { + return new PayoutAction(payoutComponent, delimiter, parsePayoutComponent(parts, i + 1)); + } else { + throw new NotImplementedException("That payout delimiter has not been implemented! Alert the developer!"); + } + } + + return payoutComponent; + } + + /** + * Tokenizes a string + * + * @param input

A string.

+ * @return

A list of tokens.

+ */ + private static @NotNull List tokenize(@NotNull String input) { + List tokens = new ArrayList<>(); + StringBuilder currentToken = new StringBuilder(); + for (int index = 0; index < input.length(); index++) { + char character = input.charAt(index); + if (PayoutDelimiter.match(character) != null) { + if (!currentToken.isEmpty()) { + tokens.add(currentToken.toString()); + } + tokens.add(String.valueOf(character)); + currentToken = new StringBuilder(); + } else if (Character.isLetter(character)) { + tokenizeNormalCharacter(currentToken, character, input.length(), index, tokens); + } + + // Unrecognized tokens are ignored + } + return tokens; + } + + /** + * Adds a normal character to the token. Adds the current token to tokens if at the end of the input + * + * @param currentToken

The string builder containing the current token.

+ * @param character

The character found in the input.

+ * @param inputLength

The length of the given input

+ * @param index

The index of the read character.

+ * @param tokens

The list of processed tokens.

+ */ + private static void tokenizeNormalCharacter(@NotNull StringBuilder currentToken, char character, int inputLength, + int index, @NotNull List tokens) { + currentToken.append(character); + if (index == inputLength - 1) { + tokens.add(currentToken.toString()); + } + } + +} diff --git a/src/main/java/net/knarcraft/playerpayouts/config/payout/PayoutComponent.java b/src/main/java/net/knarcraft/playerpayouts/config/payout/PayoutComponent.java new file mode 100644 index 0000000..bb8f1e5 --- /dev/null +++ b/src/main/java/net/knarcraft/playerpayouts/config/payout/PayoutComponent.java @@ -0,0 +1,7 @@ +package net.knarcraft.playerpayouts.config.payout; + +/** + * Interface necessary to treat both payout targets and payout actions as components + */ +public interface PayoutComponent { +} diff --git a/src/main/java/net/knarcraft/playerpayouts/config/payout/PayoutDelimiter.java b/src/main/java/net/knarcraft/playerpayouts/config/payout/PayoutDelimiter.java new file mode 100644 index 0000000..7031133 --- /dev/null +++ b/src/main/java/net/knarcraft/playerpayouts/config/payout/PayoutDelimiter.java @@ -0,0 +1,45 @@ +package net.knarcraft.playerpayouts.config.payout; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public enum PayoutDelimiter { + + /** + * Add a payout component to another + */ + ADD('+'), + + /** + * Choose one if possible, and the other if not + */ + OR(','), + ; + + private final Character character; + + /** + * Instantiates a new payout delimiter + * + * @param character

The character used to specify the delimiter

+ */ + PayoutDelimiter(@NotNull Character character) { + this.character = character; + } + + /** + * Tries to match the payout delimiter specified + * + * @param toMatch

The character to match to a payout delimiter

+ * @return

The matched delimiter, or null if a match was not found

+ */ + public static @Nullable PayoutDelimiter match(@NotNull Character toMatch) { + for (PayoutDelimiter payoutDelimiter : PayoutDelimiter.values()) { + if (payoutDelimiter.character.equals(toMatch)) { + return payoutDelimiter; + } + } + return null; + } + +} diff --git a/src/main/java/net/knarcraft/playerpayouts/config/payout/PayoutTarget.java b/src/main/java/net/knarcraft/playerpayouts/config/payout/PayoutTarget.java new file mode 100644 index 0000000..f30f73b --- /dev/null +++ b/src/main/java/net/knarcraft/playerpayouts/config/payout/PayoutTarget.java @@ -0,0 +1,62 @@ +package net.knarcraft.playerpayouts.config.payout; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * Components used to specify a payout mode + */ +public enum PayoutTarget implements PayoutComponent { + + /** + * The payout set for the specific player + */ + PLAYER(List.of("p", "player")), + + /** + * The payout of all of a player's groups + */ + GROUPS(List.of("g", "group", "groups")), + + /** + * The payout of a player's highest group + */ + HIGHEST_GROUP(List.of("hg", "highestGroup")), + + /** + * The base payout + */ + BASE(List.of("b", "base")), + ; + + private final List stringRepresentations; + + /** + * Instantiates a new payout component + * + * @param stringRepresentations

The possible string representations of the payout component

+ */ + PayoutTarget(List stringRepresentations) { + this.stringRepresentations = stringRepresentations; + } + + /** + * Tries to find a payout component matching the given string + * + * @param toMatch

A string that specifies a payout component

+ * @return

The payout component matching the input, or null if no match was found

+ */ + public static @Nullable PayoutTarget match(@NotNull String toMatch) { + for (PayoutTarget payoutTarget : PayoutTarget.values()) { + for (String representation : payoutTarget.stringRepresentations) { + if (representation.equalsIgnoreCase(toMatch)) { + return payoutTarget; + } + } + } + return null; + } + +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 8a92643..42bf049 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -10,6 +10,15 @@ hoursUntilBonus: 100 bonusMultiplier: 1 # The percentage of their normal payout to pay AFK players afkPercentage: 0 +# The rules for how the base payout is calculated. "," = OR, "+" = AND. "p" or "player" is the override for a specific player. +# "g" or "groups" is the sum of all group overrides for a specific player. "hg" or "HighestGroup" is the highest sum of all +# of a specific player's groups. "b" or "base" is the default base payment. +# +# If you wanted to give players the sum of everything, you'd set it to "p+g+b". +# If you wanted to give players the sum of their personal override and their highest group, but fall back to the base +# pay, you'd set it to: "p+hg,b" +# If the payout rule you set ends up giving 0 as the payment, it will fall back to the default of "p,hg,b" +payoutRules: "player,HighestGroup,base" # Overrides for specific groups. Use /setgrouppayout groupPayouts: [ ] # Overrides for specific players. Use /setplayerpayout diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index e9cbb4c..f37018a 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -11,28 +11,28 @@ softdepend: commands: reload: - permission: timeismoney.reload + permission: playerpayouts.reload description: Reloads the plugin usage: / setgrouppayout: - permission: timeismoney.admin + permission: playerpayouts.admin description: Sets the payout for a permission group usage: / setplayerpayout: - permission: timeismoney.admin + permission: playerpayouts.admin description: Sets the payout for a player usage: / permissions: - timeismoney.*: + playerpayouts.*: description: Allows usage of all commands - default: false + default: op children: - - timeismoney.reload - - timeismoney.admin - timeismoney.reload: + - playerpayouts.reload + - playerpayouts.admin + playerpayouts.reload: description: Allows usage of the /reload command default: false - timeismoney.admin: + playerpayouts.admin: description: Allows usage of configuration commands default: false \ No newline at end of file