All checks were successful
KnarCraft/PlayerPayouts/pipeline/head This commit looks good
422 lines
17 KiB
Java
422 lines
17 KiB
Java
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 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
|
|
*
|
|
* @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;
|
|
|
|
// Load per-group payouts
|
|
ConfigurationSection groupPayoutsSection = fileConfiguration.getConfigurationSection(
|
|
ConfigurationKey.GROUP_PAYOUTS.getPath());
|
|
if (groupPayoutsSection != null) {
|
|
for (String key : groupPayoutsSection.getKeys(false)) {
|
|
groupPayouts.put(key, groupPayoutsSection.getDouble(key));
|
|
}
|
|
}
|
|
|
|
// Load per-player payouts
|
|
ConfigurationSection playerPayoutsSection = fileConfiguration.getConfigurationSection(
|
|
ConfigurationKey.PLAYER_PAYOUTS.getPath());
|
|
if (playerPayoutsSection != null) {
|
|
for (String key : playerPayoutsSection.getKeys(false)) {
|
|
playerPayouts.put(UUID.fromString(key), playerPayoutsSection.getDouble(key));
|
|
}
|
|
}
|
|
|
|
// Load simple configuration values
|
|
this.defaultPayout = fileConfiguration.getDouble(ConfigurationKey.DEFAULT_PAYOUT.getPath(), 10);
|
|
this.hoursUntilBonus = fileConfiguration.getInt(ConfigurationKey.HOURS_UNTIL_BONUS.getPath(), 100);
|
|
this.bonusMultiplier = fileConfiguration.getDouble(ConfigurationKey.BONUS_MULTIPLIER.getPath(), 1);
|
|
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);
|
|
|
|
// Parse the payout rules
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the number of hours a player must have played to receive a payment bonus
|
|
*
|
|
* @return <p>The min. amount of hours required to get a bonus</p>
|
|
*/
|
|
public int getHoursUntilBonus() {
|
|
return hoursUntilBonus;
|
|
}
|
|
|
|
/**
|
|
* A multiplier to apply to the bonus
|
|
*
|
|
* <p>By default, the bonus is total playtime / hours until bonus. This multiplier allows adjusting how high or low
|
|
* the bonus becomes. For example, a bonus multiplier of 0.5 would halve the paid bonus, while a bonus multiplier
|
|
* of 2 would double the paid bonus.</p>
|
|
*
|
|
* @return <p>The bonus multiplier</p>
|
|
*/
|
|
public double getBonusMultiplier() {
|
|
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 getDefaultBasePay(@NotNull Player player) {
|
|
if (playerPayouts.get(player.getUniqueId()) != null) {
|
|
return playerPayouts.get(player.getUniqueId());
|
|
}
|
|
|
|
double groupPayout = 0;
|
|
if (PermissionManager.isInitialized()) {
|
|
groupPayout = getGroupPayout(player, true);
|
|
}
|
|
|
|
if (groupPayout == 0) {
|
|
return defaultPayout;
|
|
} else {
|
|
return groupPayout;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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, 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);
|
|
if (groupPayout != null) {
|
|
maxPay = Math.max(maxPay, groupPayout);
|
|
}
|
|
}
|
|
}
|
|
return maxPay;
|
|
}
|
|
|
|
/**
|
|
* The delay between each time a player is paid in minutes
|
|
*
|
|
* @return <p>The delay between payments</p>
|
|
*/
|
|
public int getPayoutDelay() {
|
|
return payoutDelay;
|
|
}
|
|
|
|
/**
|
|
* The percentage of the payment to pay AFK players
|
|
*
|
|
* @return <p>AFK players' payment percentage</p>
|
|
*/
|
|
public double getAfkPercentage() {
|
|
return afkPercentage;
|
|
}
|
|
|
|
/**
|
|
* Whether to display a message to players when they're paid
|
|
*
|
|
* @return <p>True if a payment message should be displayed</p>
|
|
*/
|
|
public boolean displayPaymentMessage() {
|
|
return displayPaymentMessage;
|
|
}
|
|
|
|
/**
|
|
* Sets the payout given to a specific player
|
|
*
|
|
* @param playerId <p>The id of the player to set payout for</p>
|
|
* @param payout <p>The payout to set for the player</p>
|
|
*/
|
|
public void setPlayerPayout(@NotNull UUID playerId, @Nullable Double payout) {
|
|
if (payout == null || payout < 0) {
|
|
this.playerPayouts.put(playerId, null);
|
|
} else {
|
|
this.playerPayouts.put(playerId, payout);
|
|
}
|
|
this.save();
|
|
}
|
|
|
|
/**
|
|
* Sets the payout given to a specific group
|
|
*
|
|
* @param groupName <p>The name of the group to set payout for</p>
|
|
* @param payout <p>The payout to set for the group</p>
|
|
*/
|
|
public void setGroupPayout(@NotNull String groupName, @Nullable Double payout) {
|
|
if (payout == null || payout < 0) {
|
|
this.groupPayouts.put(groupName, null);
|
|
} else {
|
|
this.groupPayouts.put(groupName, payout);
|
|
}
|
|
this.save();
|
|
}
|
|
|
|
/**
|
|
* Gets all group payout overrides
|
|
*
|
|
* @return <p>All group payout overrides</p>
|
|
*/
|
|
public @NotNull Map<String, Double> getGroupPayouts() {
|
|
return groupPayouts;
|
|
}
|
|
|
|
/**
|
|
* Gets a group payout override
|
|
*
|
|
* @param groupName <p>The group to get the override of</p>
|
|
* @return <p>The overridden payout, or null if missing or cleared</p>
|
|
*/
|
|
public @Nullable Double getGroupPayout(@NotNull String groupName) {
|
|
return groupPayouts.get(groupName);
|
|
}
|
|
|
|
/**
|
|
* Gets all player payout overrides
|
|
*
|
|
* @return <p>All player payout overrides</p>
|
|
*/
|
|
public @NotNull Map<UUID, Double> getPlayerPayouts() {
|
|
return playerPayouts;
|
|
}
|
|
|
|
/**
|
|
* Gets a player payout override
|
|
*
|
|
* @param playerId <p>The id of the player to get the override of</p>
|
|
* @return <p>The overridden payout, or null if missing or cleared</p>
|
|
*/
|
|
public @Nullable Double getPlayerPayout(@NotNull UUID playerId) {
|
|
return playerPayouts.get(playerId);
|
|
}
|
|
|
|
/**
|
|
* Saves this configuration to disk
|
|
*/
|
|
public void save() {
|
|
fileConfiguration.set(ConfigurationKey.PAYOUT_DELAY.getPath(), this.payoutDelay);
|
|
fileConfiguration.setComments(ConfigurationKey.PAYOUT_DELAY.getPath(),
|
|
List.of("The amount of minutes to wait between each payment"));
|
|
|
|
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"));
|
|
|
|
fileConfiguration.set(ConfigurationKey.DEFAULT_PAYOUT.getPath(), this.defaultPayout);
|
|
fileConfiguration.setComments(ConfigurationKey.DEFAULT_PAYOUT.getPath(),
|
|
List.of("The default payout if the player has no overrides"));
|
|
|
|
fileConfiguration.set(ConfigurationKey.DISPLAY_PAYMENT_MESSAGE.getPath(), this.displayPaymentMessage);
|
|
fileConfiguration.setComments(ConfigurationKey.DISPLAY_PAYMENT_MESSAGE.getPath(),
|
|
List.of("Whether to announce to a player that they've just been paid"));
|
|
|
|
fileConfiguration.set(ConfigurationKey.AFK_PERCENTAGE.getPath(), this.afkPercentage);
|
|
fileConfiguration.setComments(ConfigurationKey.AFK_PERCENTAGE.getPath(),
|
|
List.of("The percentage of their normal payout to pay AFK players"));
|
|
|
|
fileConfiguration.set(ConfigurationKey.PAYOUT_DELAY.getPath(), this.payoutDelay);
|
|
fileConfiguration.setComments(ConfigurationKey.PAYOUT_DELAY.getPath(),
|
|
List.of("The amount of minutes to wait between each payment"));
|
|
|
|
fileConfiguration.set(ConfigurationKey.HOURS_UNTIL_BONUS.getPath(), this.hoursUntilBonus);
|
|
fileConfiguration.setComments(ConfigurationKey.HOURS_UNTIL_BONUS.getPath(),
|
|
List.of("The amount of hours until a bonus is given. Set to -1 to disable."));
|
|
|
|
for (Map.Entry<UUID, Double> playerPayout : this.playerPayouts.entrySet()) {
|
|
fileConfiguration.set(ConfigurationKey.PLAYER_PAYOUTS.getPath() + "." + playerPayout.getKey().toString(),
|
|
playerPayout.getValue());
|
|
}
|
|
fileConfiguration.setComments(ConfigurationKey.PLAYER_PAYOUTS.getPath(),
|
|
List.of("Overrides for specific players"));
|
|
|
|
for (Map.Entry<String, Double> groupPayout : this.groupPayouts.entrySet()) {
|
|
fileConfiguration.set(ConfigurationKey.GROUP_PAYOUTS.getPath() + "." + groupPayout.getKey(),
|
|
groupPayout.getValue());
|
|
}
|
|
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();
|
|
|
|
// 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());
|
|
}
|
|
}
|
|
for (Map.Entry<UUID, Double> entry : playerPayouts.entrySet()) {
|
|
if (entry.getValue() == null) {
|
|
playerPayouts.remove(entry.getKey());
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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!");
|
|
}
|
|
}
|
|
|
|
}
|