Adds a highly configurable option for deciding the base payout
This commit is contained in:
parent
db922f7351
commit
0b601d9bb7
31
README.md
31
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) | <group> <payout> | Sets the payout for a specific group |
|
||||
| [/setplayerpayout](#setplayerpayout) | <player> <payout> | 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 |
|
||||
|----------------------|----------------------------------------|
|
||||
| playerpayouts.* | Grants all permissions |
|
||||
| playerpayouts.reload | Allows usage of the reload command |
|
||||
| playerpayouts.admin | Allows usage of configuration commands |
|
@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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 <p>The group to set payout for</p>
|
||||
* @param payout <p>The payout to set</p>
|
||||
*/
|
||||
private void setPayout(@NotNull String group, @Nullable Double payout) {
|
||||
configuration.setGroupPayout(group, payout);
|
||||
configuration.save();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 <p>The player to set payout for</p>
|
||||
* @param payout <p>The payout to set</p>
|
||||
*/
|
||||
private void setPayout(@NotNull UUID playerId, @Nullable Double payout) {
|
||||
configuration.setPlayerPayout(playerId, payout);
|
||||
configuration.save();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<String, Double> groupPayouts;
|
||||
private final Map<UUID, Double> 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<String, Double> groupPayouts;
|
||||
private Map<UUID, Double> 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 <p>The file configuration to read values from</p>
|
||||
*/
|
||||
public Configuration(@NotNull FileConfiguration fileConfiguration) {
|
||||
load(fileConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the configuration specified in the given file configuration
|
||||
*
|
||||
* @param fileConfiguration <p>The file configuration to load</p>
|
||||
*/
|
||||
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,23 +112,38 @@ public class Configuration {
|
||||
return bonusMultiplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the base pay for the given player
|
||||
*
|
||||
* @param player <p>The player to get the base pay for</p>
|
||||
* @return <p>The base pay for the player</p>
|
||||
*/
|
||||
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 <p>The player to get the base payout for</p>
|
||||
* @return <p>The player's base pay</p>
|
||||
*/
|
||||
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;
|
||||
@ -108,10 +154,44 @@ public class Configuration {
|
||||
* Gets the max payout of the given player's permission groups
|
||||
*
|
||||
* @param player <p>The player to get the group payout for</p>
|
||||
* @param highest <p>Whether to just get the highest value, instead of the sum</p>
|
||||
* @return <p>The group payout, or -1 if no groups has a set payout</p>
|
||||
*/
|
||||
private double getGroupPayout(@NotNull Player player) {
|
||||
double maxPay = -1;
|
||||
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 <p>The player to get the group payout for</p>
|
||||
* @return <p>The group payout, or -1 if no groups has a set payout</p>
|
||||
*/
|
||||
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 <p>The player to get the group payout for</p>
|
||||
* @return <p>The group payout, or -1 if no groups has a set payout</p>
|
||||
*/
|
||||
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<String, Double> 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 <p>The payout component to calculate from</p>
|
||||
* @param player <p>The player to calculate payment for</p>
|
||||
* @return <p></p>
|
||||
*/
|
||||
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!");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -0,0 +1,15 @@
|
||||
package net.knarcraft.playerpayouts.config.payout;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Instantiates a new payout action
|
||||
*
|
||||
* @param component1 <p>The component "to the left of" the delimiter</p>
|
||||
* @param delimiter <p>The delimiter between the two components</p>
|
||||
* @param component2 <p>The component "to the right of" the delimiter</p>
|
||||
*/
|
||||
public record PayoutAction(@NotNull PayoutComponent component1, @NotNull PayoutDelimiter delimiter,
|
||||
@NotNull PayoutComponent component2) implements PayoutComponent {
|
||||
|
||||
}
|
@ -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 <p>The string to match</p>
|
||||
* @return <p>A payout component describing how to handle payouts</p>
|
||||
* @throws ParseException <p>If unable to parse the input string</p>
|
||||
*/
|
||||
public static PayoutComponent matchPayoutComponent(@NotNull String toMatch) throws ParseException {
|
||||
List<String> parts = tokenize(toMatch);
|
||||
return parsePayoutComponent(parts, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a payout component from the given input
|
||||
*
|
||||
* @param parts <p>The list of components to parse</p>
|
||||
* @param index <p>The index of the list to start at</p>
|
||||
* @return <p>The parsed payout component</p>
|
||||
* @throws ParseException <p>If unable to parse the input</p>
|
||||
*/
|
||||
private static @NotNull PayoutComponent parsePayoutComponent(@NotNull List<String> 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 <p>A string.</p>
|
||||
* @return <p>A list of tokens.</p>
|
||||
*/
|
||||
private static @NotNull List<String> tokenize(@NotNull String input) {
|
||||
List<String> 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 <p>The string builder containing the current token.</p>
|
||||
* @param character <p>The character found in the input.</p>
|
||||
* @param inputLength <p>The length of the given input</p>
|
||||
* @param index <p>The index of the read character.</p>
|
||||
* @param tokens <p>The list of processed tokens.</p>
|
||||
*/
|
||||
private static void tokenizeNormalCharacter(@NotNull StringBuilder currentToken, char character, int inputLength,
|
||||
int index, @NotNull List<String> tokens) {
|
||||
currentToken.append(character);
|
||||
if (index == inputLength - 1) {
|
||||
tokens.add(currentToken.toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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 {
|
||||
}
|
@ -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 <p>The character used to specify the delimiter</p>
|
||||
*/
|
||||
PayoutDelimiter(@NotNull Character character) {
|
||||
this.character = character;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to match the payout delimiter specified
|
||||
*
|
||||
* @param toMatch <p>The character to match to a payout delimiter</p>
|
||||
* @return <p>The matched delimiter, or null if a match was not found</p>
|
||||
*/
|
||||
public static @Nullable PayoutDelimiter match(@NotNull Character toMatch) {
|
||||
for (PayoutDelimiter payoutDelimiter : PayoutDelimiter.values()) {
|
||||
if (payoutDelimiter.character.equals(toMatch)) {
|
||||
return payoutDelimiter;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -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<String> stringRepresentations;
|
||||
|
||||
/**
|
||||
* Instantiates a new payout component
|
||||
*
|
||||
* @param stringRepresentations <p>The possible string representations of the payout component</p>
|
||||
*/
|
||||
PayoutTarget(List<String> stringRepresentations) {
|
||||
this.stringRepresentations = stringRepresentations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to find a payout component matching the given string
|
||||
*
|
||||
* @param toMatch <p>A string that specifies a payout component</p>
|
||||
* @return <p>The payout component matching the input, or null if no match was found</p>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
|
@ -11,28 +11,28 @@ softdepend:
|
||||
|
||||
commands:
|
||||
reload:
|
||||
permission: timeismoney.reload
|
||||
permission: playerpayouts.reload
|
||||
description: Reloads the plugin
|
||||
usage: /<command>
|
||||
setgrouppayout:
|
||||
permission: timeismoney.admin
|
||||
permission: playerpayouts.admin
|
||||
description: Sets the payout for a permission group
|
||||
usage: /<command> <group name> <payout>
|
||||
setplayerpayout:
|
||||
permission: timeismoney.admin
|
||||
permission: playerpayouts.admin
|
||||
description: Sets the payout for a player
|
||||
usage: /<command> <player name/uuid> <payout>
|
||||
|
||||
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
|
Loading…
Reference in New Issue
Block a user