diff --git a/.gitignore b/.gitignore index 999b588..bd61f89 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,47 @@ +# Compiled class file +*.class -# IntelliJ project files -.idea/ -.gradle/ -build/ -*.iml +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +# eclipse +bin +*.launch +.settings +.metadata +.classpath +.project + +# idea out gen +*.ipr +*.iws +*.iml +.idea +# gradle +build +.gradle +# other +eclipse +run diff --git a/build.gradle b/build.gradle index 2cd2838..1504ae0 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'eclipse' sourceCompatibility = 1.8 targetCompatibility = 1.8 -version = '1.4.0' +version = '1.5.0' jar { manifest { diff --git a/src/main/java/io/github/hsyyid/payday/PayDay.java b/src/main/java/io/github/hsyyid/payday/PayDay.java index 0f1b937..01f22aa 100644 --- a/src/main/java/io/github/hsyyid/payday/PayDay.java +++ b/src/main/java/io/github/hsyyid/payday/PayDay.java @@ -1,7 +1,9 @@ package io.github.hsyyid.payday; import com.google.inject.Inject; +import io.github.hsyyid.payday.commands.PayDayCommand; import io.github.hsyyid.payday.utils.Utils; +import io.github.nucleuspowered.nucleus.api.NucleusAPI; import io.github.nucleuspowered.nucleus.api.service.NucleusAFKService; import ninja.leaping.configurate.ConfigurationNode; import ninja.leaping.configurate.commented.CommentedConfigurationNode; @@ -13,10 +15,10 @@ import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.cause.Cause; import org.spongepowered.api.event.cause.EventContext; +import org.spongepowered.api.event.game.GameReloadEvent; import org.spongepowered.api.event.game.state.GameInitializationEvent; import org.spongepowered.api.event.game.state.GamePostInitializationEvent; import org.spongepowered.api.event.network.ClientConnectionEvent; -import org.spongepowered.api.event.service.ChangeServiceProviderEvent; import org.spongepowered.api.plugin.Dependency; import org.spongepowered.api.plugin.Plugin; import org.spongepowered.api.plugin.PluginContainer; @@ -24,141 +26,149 @@ import org.spongepowered.api.service.economy.EconomyService; import org.spongepowered.api.service.economy.account.UniqueAccount; -import java.io.File; -import java.io.IOException; import java.math.BigDecimal; +import java.util.List; import java.util.Map.Entry; import java.util.Optional; +import java.util.UUID; -@Plugin(id = "payday", name = "PayDay", version = "1.4.0", description = "Pay your players as they play.", dependencies = {@Dependency( +@Plugin(id = "payday", name = "PayDay", version = "1.5.0", description = "Pay your players as they play.", dependencies = {@Dependency( id = "nucleus", optional = true)}) public class PayDay { public static ConfigurationNode config; - public static ConfigurationLoader configurationManager; - public static EconomyService economyService; + private static EconomyService economyService; private static PayDay instance; private Task task; private boolean functional = false; - private Optional afkService = Optional.empty(); + private static boolean afkServicePresent = false; + private static NucleusAFKService afkService; @Inject private Logger logger; @Inject private PluginContainer container; - public Logger getLogger() { - return logger; - } - - @Inject @DefaultConfig(sharedRoot = true) private File dConfig; - @Inject @DefaultConfig(sharedRoot = true) private ConfigurationLoader confManager; @Listener public void onGameInit(GameInitializationEvent event) { instance = this; - getLogger().info("PayDay loading..."); + logger.info("PayDay loading..."); - try { - if (!dConfig.exists()) { - dConfig.createNewFile(); - config = confManager.load(); - confManager.save(config); - } + Utils.loadConfig(); - configurationManager = confManager; - config = confManager.load(); - } catch (IOException exception) { - getLogger().error("The default configuration could not be loaded or created!"); - } + Sponge.getCommandManager().register(this, PayDayCommand.getCommandSpec(), "payday"); - // Setup other config options - Utils.getJoinPay(); - Utils.enableAfkPay(); + createTask(); + logger.info("-----------------------------"); + logger.info("PayDay was made by HassanS6000!"); + logger.info("Patched to APIv5 by Kostronor from the Minecolonies team!"); + logger.info("Further updated by Flibio!"); + logger.info("Improved by Brycey92!"); + logger.info("Please post all errors on the Sponge Thread or on GitHub!"); + logger.info("Have fun, and enjoy! :D"); + logger.info("-----------------------------"); + logger.info("PayDay loaded!"); + } + + private void createTask() { Task.Builder taskBuilder = Sponge.getScheduler().createTaskBuilder(); task = taskBuilder.execute(task -> { + // Reset who's been paid, for all payment amounts + for(List array: Utils.paidPlayersMap.values()){ + array.clear(); + } + for (Player player : Sponge.getServer().getOnlinePlayers()) { // Check if the player is afk - if (!Utils.enableAfkPay() && afkService.isPresent() && afkService.get().isAFK(player)) { - continue; - } - for (Entry entry : Utils.getPaymentAmounts().entrySet()) { - if (entry.getKey().equals("*") || player.hasPermission(entry.getKey())) { - BigDecimal pay = entry.getValue(); - player.sendMessage(Utils.getSalaryMessage(pay)); - UniqueAccount uniqueAccount = economyService.getOrCreateAccount(player.getUniqueId()).get(); - uniqueAccount.deposit(economyService.getDefaultCurrency(), pay, Cause.of(EventContext.empty(), container)); + if (Utils.enableAfkPay() || ! (afkServicePresent && afkService.isAFK(player))) { + for (Entry entry : Utils.getPaymentAmounts().entrySet()) { + String key = entry.getKey(); + + if ((key.equals("*") || player.hasPermission(key)) && !Utils.paidPlayersMap.get(key).contains(player.getUniqueId())) { + BigDecimal pay = entry.getValue(); + player.sendMessage(Utils.getSalaryMessage(pay)); + UniqueAccount uniqueAccount = economyService.getOrCreateAccount(player.getUniqueId()).get(); + uniqueAccount.deposit(economyService.getDefaultCurrency(), pay, Cause.of(EventContext.empty(), container)); + Utils.paidPlayersMap.get(key).add(player.getUniqueId()); + } } } } }).interval(Utils.getTimeAmount(), Utils.getTimeUnit()).name("PayDay - Pay").submit(this); - - getLogger().info("-----------------------------"); - getLogger().info("PayDay was made by HassanS6000!"); - getLogger().info("Patched to APIv5 by Kostronor from the Minecolonies team!"); - getLogger().info("Further updated by Flibio!"); - getLogger().info("Please post all errors on the Sponge Thread or on GitHub!"); - getLogger().info("Have fun, and enjoy! :D"); - getLogger().info("-----------------------------"); - getLogger().info("PayDay loaded!"); - } - - @Listener - public void onChangeServiceProvider(ChangeServiceProviderEvent event) { - if (Sponge.getPluginManager().getPlugin("nucleus").isPresent()) { - if (event.getService().equals(NucleusAFKService.class)) { - Object raw = event.getNewProviderRegistration().getProvider(); - if (raw instanceof NucleusAFKService) { - afkService = Optional.of((NucleusAFKService) raw); - } - } - } } @Listener public void onGamePostInit(GamePostInitializationEvent event) { Optional econService = Sponge.getServiceManager().provide(EconomyService.class); - if (econService.isPresent()) { economyService = econService.get(); functional = true; - - // Setup messages - getLogger().info("Initializing messages config!"); - Utils.getFirstJoinMessage(BigDecimal.ONE); - Utils.getSalaryMessage(BigDecimal.ONE); - } else { - getLogger().error("Error! There is no Economy plugin found on this server, PayDay will not work correctly!"); + } + else { + logger.error("Error! There is no Economy plugin found on this server, PayDay will not work!"); task.cancel(); functional = false; + return; + } + + Optional afkServiceOptional = NucleusAPI.getAFKService(); + if (afkServiceOptional.isPresent()) { + afkService = afkServiceOptional.get(); + afkServicePresent = true; + } + else { + Utils.warnIfMissingAfkService(); + afkServicePresent = false; } } @Listener - public void onPlayerJoin(ClientConnectionEvent.Join event) { - if (!Utils.getJoinPay() || !functional) { - return; + public void onReload(GameReloadEvent event) { + reload(); + } + + public static void reload() { + Utils.loadConfig(); + + instance.task.cancel(); + instance.createTask(); + + if(!afkServicePresent) { + Utils.warnIfMissingAfkService(); } - Player player = event.getTargetEntity(); - - for (Entry entry : Utils.getPaymentAmounts().entrySet()) { - if (entry.getKey().equals("*") || player.hasPermission(entry.getKey())) { - BigDecimal pay = entry.getValue(); - player.sendMessage(Utils.getFirstJoinMessage(pay)); - UniqueAccount uniqueAccount = economyService.getOrCreateAccount(player.getUniqueId()).get(); - uniqueAccount.deposit(economyService.getDefaultCurrency(), pay, Cause.of(EventContext.empty(), container)); + instance.logger.info("Reloaded config!"); + } + + @Listener + public void onPlayerJoin(ClientConnectionEvent.Join event) { + if (functional && Utils.getJoinPay()) { + Player player = event.getTargetEntity(); + + for (Entry entry : Utils.getPaymentAmounts().entrySet()) { + String key = entry.getKey(); + + if ((key.equals("*") || player.hasPermission(key)) && !Utils.paidPlayersMap.get(key).contains(player.getUniqueId())) { + BigDecimal pay = entry.getValue(); + player.sendMessage(Utils.getFirstJoinMessage(pay)); + UniqueAccount uniqueAccount = economyService.getOrCreateAccount(player.getUniqueId()).get(); + uniqueAccount.deposit(economyService.getDefaultCurrency(), pay, Cause.of(EventContext.empty(), container)); + Utils.paidPlayersMap.get(key).add(player.getUniqueId()); + } } } } - public static PayDay getInstance() { - return instance; - } + public static PayDay getInstance() { return instance; } - public static ConfigurationLoader getConfigManager() { - return configurationManager; - } + public static ConfigurationLoader getConfigManager() { return instance.confManager; } + + public static Logger getLogger() { return instance.logger; } + + public static EconomyService getEconomyService() { return economyService; } + + public static NucleusAFKService getAfkService() { return afkService; } } diff --git a/src/main/java/io/github/hsyyid/payday/commands/PayDayCommand.java b/src/main/java/io/github/hsyyid/payday/commands/PayDayCommand.java new file mode 100644 index 0000000..ea9c98e --- /dev/null +++ b/src/main/java/io/github/hsyyid/payday/commands/PayDayCommand.java @@ -0,0 +1,28 @@ +package io.github.hsyyid.payday.commands; + +import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.command.args.CommandContext; +import org.spongepowered.api.command.spec.CommandExecutor; +import org.spongepowered.api.command.spec.CommandSpec; +import org.spongepowered.api.text.Text; + +public class PayDayCommand implements CommandExecutor { + public static CommandSpec getCommandSpec() { + return CommandSpec.builder() + .description(Text.of("PayDay commands")) + .permission("payday.base") + .executor(new PayDayCommand()) + .child(ReloadCommand.getCommandSpec(), "reload") + .build(); + } + + @Override + public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { + src.sendMessage(Text.of("PayDay commands:")); + src.sendMessage(Text.of("/payday reload")); + src.sendMessage(Text.of(" - " + ReloadCommand.description)); + return CommandResult.empty(); + } +} diff --git a/src/main/java/io/github/hsyyid/payday/commands/ReloadCommand.java b/src/main/java/io/github/hsyyid/payday/commands/ReloadCommand.java new file mode 100644 index 0000000..11ddc8f --- /dev/null +++ b/src/main/java/io/github/hsyyid/payday/commands/ReloadCommand.java @@ -0,0 +1,31 @@ +package io.github.hsyyid.payday.commands; + +import io.github.hsyyid.payday.PayDay; +import io.github.hsyyid.payday.utils.Utils; +import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.command.args.CommandContext; +import org.spongepowered.api.command.spec.CommandExecutor; +import org.spongepowered.api.command.spec.CommandSpec; +import org.spongepowered.api.text.Text; + +public class ReloadCommand implements CommandExecutor { + public static final String description = "Reloads the PayDay config"; + + public static CommandSpec getCommandSpec() { + return CommandSpec.builder() + .description(Text.of(description)) + .permission("payday.reload") + .executor(new ReloadCommand()) + .build(); + } + + @Override + public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { + PayDay.reload(); + Utils.warnIfMissingAfkService(src); + src.sendMessage(Text.of("Reloaded config!")); + return CommandResult.success(); + } +} diff --git a/src/main/java/io/github/hsyyid/payday/utils/Utils.java b/src/main/java/io/github/hsyyid/payday/utils/Utils.java index b94efb7..67654a1 100644 --- a/src/main/java/io/github/hsyyid/payday/utils/Utils.java +++ b/src/main/java/io/github/hsyyid/payday/utils/Utils.java @@ -4,170 +4,268 @@ import ninja.leaping.configurate.ConfigurationNode; import ninja.leaping.configurate.commented.CommentedConfigurationNode; import ninja.leaping.configurate.loader.ConfigurationLoader; +import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.service.economy.EconomyService; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.serializer.TextSerializers; +import javax.annotation.Nullable; import java.io.IOException; import java.math.BigDecimal; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import java.util.concurrent.TimeUnit; public class Utils { + private static TimeUnit timeUnit; + private static int timeAmount; + private static boolean joinPay; + private static boolean enableAfkPay; + private static Map paymentAmounts; + private static String firstJoinMessage; + private static String salaryMessage; + public static Map> paidPlayersMap; + + public static void loadConfig() { + ConfigurationLoader confManager = PayDay.getConfigManager(); + + try { + PayDay.config = confManager.load(); + } catch (IOException exception) { + PayDay.getLogger().error("Error! The configuration could not be loaded! Resetting configuration.", exception); + PayDay.config = confManager.createEmptyNode(); + } + + loadTimeUnit(); + loadTimeAmount(); + loadJoinPay(); + loadEnableAfkPay(); + loadPaymentAmounts(); + loadFirstJoinMessage(); + loadSalaryMessage(); + + try { + confManager.save(PayDay.config); + } catch (IOException exception) { + PayDay.getLogger().warn("Error! The configuration could not be saved!", exception); + } + } + + private static void loadTimeUnit() { + ConfigurationNode valueNode = PayDay.config.getNode("timeunit"); + + String defaultValue = "hours"; + + String value = loadConfigurationNode(valueNode, defaultValue).get(); + + switch (value.toLowerCase()) { + case "days": + case "day": + timeUnit = TimeUnit.DAYS; + break; + case "hours": + case "hour": + timeUnit = TimeUnit.HOURS; + break; + case "minutes": + case "minute": + timeUnit = TimeUnit.MINUTES; + break; + case "seconds": + case "second": + timeUnit = TimeUnit.SECONDS; + break; + default: + PayDay.getLogger().error("Error! timeunit not recognized: \"" + value + "\". Expected \"days\", \"hours\", \"minutes\", or \"seconds\". Defaulting to \"" + defaultValue + "\"."); + timeUnit = TimeUnit.HOURS; + } + } + public static TimeUnit getTimeUnit() { - ConfigurationNode valueNode = PayDay.config.getNode((Object[]) ("timeunit").split("\\.")); - - if (valueNode.getValue() != null) { - String value = valueNode.getString(); - - if (value.toLowerCase().equals("days")) { - return TimeUnit.DAYS; - } else if (value.toLowerCase().equals("hours")) { - return TimeUnit.HOURS; - } else if (value.toLowerCase().equals("minutes")) { - return TimeUnit.MINUTES; - } else if (value.toLowerCase().equals("seconds")) { - return TimeUnit.SECONDS; - } else if (value.toLowerCase().equals("microseconds")) { - return TimeUnit.MICROSECONDS; - } else if (value.toLowerCase().equals("milliseconds")) { - return TimeUnit.MILLISECONDS; - } else if (value.toLowerCase().equals("nanoseconds")) { - return TimeUnit.NANOSECONDS; - } else { - System.out.println("Error! TimeUnit not recognized: " + value); - return TimeUnit.HOURS; + return timeUnit; + } + + private static void loadTimeAmount() { + ConfigurationNode valueNode = PayDay.config.getNode("timeamount"); + + int defaultValue = 1; + + // Convert the setting to an int if it's currently a String + String valueStr = valueNode.getString(); + if(valueStr != null && valueStr.matches("(0|[1-9]\\d*)")) { + try { + timeAmount = Integer.parseInt(valueStr); + valueNode.setValue(timeAmount); + return; + } + catch(NumberFormatException exception) { + PayDay.getLogger().error("Error! timeamount not recognized: \"" + valueStr + "\". Expected a positive integer. Defaulting to " + defaultValue + ".", exception); } - } else { - Utils.setConfig("timeunit", "Hours"); - return TimeUnit.HOURS; } + + timeAmount = loadConfigurationNode(valueNode, defaultValue).get(); } public static int getTimeAmount() { - ConfigurationNode valueNode = PayDay.config.getNode((Object[]) ("timeamount").split("\\.")); + return timeAmount; + } - try { - String value = valueNode.getString(); - return Integer.parseInt(value); - } catch (RuntimeException e) { - Utils.setConfig("timeamount", "1"); - return 1; + private static void loadJoinPay() { + ConfigurationNode valueNode = PayDay.config.getNode("payonjoin"); + + String defaultValue = "true"; + + String value = loadConfigurationNode(valueNode, defaultValue).get(); + if(!value.equals("true") && !value.equals("false")) { + PayDay.getLogger().error("Error! payonjoin not recognized: \"" + value + "\". Expected \"true\" or \"false\". Defaulting to \"" + defaultValue + "\"."); + joinPay = Boolean.parseBoolean(defaultValue); + } + else { + // Returns false if !value.equals("true") + joinPay = Boolean.parseBoolean(value); } } public static boolean getJoinPay() { - ConfigurationNode valueNode = PayDay.config.getNode((Object[]) ("payonjoin").split("\\.")); + return joinPay; + } - try { - String value = valueNode.getString(); - if (value == null) { - Utils.setConfig("payonjoin", Boolean.toString(true)); - return true; - } else { - return Boolean.parseBoolean(value); - } - } catch (RuntimeException e) { - Utils.setConfig("payonjoin", Boolean.toString(true)); - return true; + private static void loadEnableAfkPay() { + ConfigurationNode valueNode = PayDay.config.getNode("enableafkpay"); + + String defaultValue = "true"; + + String value = loadConfigurationNode(valueNode, defaultValue).get(); + if(!value.equals("true") && !value.equals("false")) { + PayDay.getLogger().error("Error! payonjoin not recognized: \"" + value + "\". Expected \"true\" or \"false\". Defaulting to \"" + defaultValue + "\"."); + enableAfkPay = Boolean.parseBoolean(defaultValue); + } + else { + // Returns false if !value.equals("true") + enableAfkPay = Boolean.parseBoolean(value); } } public static boolean enableAfkPay() { - ConfigurationNode valueNode = PayDay.config.getNode((Object[]) ("enableafkpay").split("\\.")); - - try { - String value = valueNode.getString(); - if (value == null) { - Utils.setConfig("enableafkpay", Boolean.toString(true)); - return true; - } else { - return Boolean.parseBoolean(value); - } - } catch (RuntimeException e) { - Utils.setConfig("enableafkpay", Boolean.toString(true)); - return true; - } + return enableAfkPay; } - public static Map getPaymentAmounts() { - Map payments = new HashMap<>(); - Map children = PayDay.config.getNode("payamounts").getChildrenMap(); + private static void loadPaymentAmounts() { + paymentAmounts = new HashMap<>(); + paidPlayersMap = new HashMap<>(); + + ConfigurationNode node = PayDay.config.getNode("payamounts"); + Map children = node.getChildrenMap(); for (ConfigurationNode child : children.values()) { if (!child.getNode("permission").isVirtual() && !child.getNode("amount").isVirtual()) { - payments.put(child.getNode("permission").getString(), BigDecimal.valueOf(child.getNode("amount").getDouble())); + String permission = child.getNode("permission").getString(); + paymentAmounts.put(permission, BigDecimal.valueOf(child.getNode("amount").getDouble())); + paidPlayersMap.put(permission, new ArrayList<>()); } } + } - return payments; + public static Map getPaymentAmounts() { + return paymentAmounts; } - public static Text getFirstJoinMessage(BigDecimal amount) { - ConfigurationNode valueNode = PayDay.config.getNode((Object[]) ("joinmessage").split("\\.")); + private static void loadFirstJoinMessage() { + ConfigurationNode valueNode = PayDay.config.getNode("joinmessage"); - String defaultMessage = "&6[PayDay]: &7Welcome to the server! Here is {amount} {label}! Enjoy!"; + firstJoinMessage = loadConfigurationNode(valueNode, "&6[PayDay]: &7Welcome to the server! Here is {amount} {label}! Enjoy!").get(); + } - EconomyService economyService = PayDay.economyService; - String label = economyService.getDefaultCurrency().getDisplayName().toPlain(); - if (amount.compareTo(BigDecimal.ONE) != 0) { - label = economyService.getDefaultCurrency().getPluralDisplayName().toPlain(); - } + public static Text getFirstJoinMessage(BigDecimal amount) { + String label = getCurrencyLabel(amount); - try { - String value = valueNode.getString(); - if (value == null) { - Utils.setConfig("joinmessage", defaultMessage); - } else { - return TextSerializers.FORMATTING_CODE.deserialize(value.replaceAll("\\{amount\\}", amount.toString()).replaceAll("\\{label\\}", - label)); - } - } catch (RuntimeException e) { - Utils.setConfig("joinmessage", defaultMessage); - } + return TextSerializers.FORMATTING_CODE.deserialize(firstJoinMessage.replaceAll("\\{amount}", amount.toString()) + .replaceAll("\\{label}",label)); + } + + private static void loadSalaryMessage() { + ConfigurationNode valueNode = PayDay.config.getNode("salarymessage"); - return TextSerializers.FORMATTING_CODE.deserialize(defaultMessage.replaceAll("\\{amount\\}", amount.toString()).replaceAll("\\{label\\}", - label)); + salaryMessage = loadConfigurationNode(valueNode, "&6[PayDay]: &7It's PayDay! Here is your salary of {amount} {label}! Enjoy!").get(); } public static Text getSalaryMessage(BigDecimal amount) { - ConfigurationNode valueNode = PayDay.config.getNode((Object[]) ("salarymessage").split("\\.")); + String label = getCurrencyLabel(amount); + + return TextSerializers.FORMATTING_CODE.deserialize(salaryMessage.replaceAll("\\{amount}", amount.toString()) + .replaceAll("\\{label}", label)); + } - String defaultMessage = "&6[PayDay]: &7It's PayDay! Here is your salary of {amount} {label}! Enjoy!"; + private static String getCurrencyLabel(BigDecimal amount) { + EconomyService economyService = PayDay.getEconomyService(); - EconomyService economyService = PayDay.economyService; - String label = economyService.getDefaultCurrency().getDisplayName().toPlain(); if (amount.compareTo(BigDecimal.ONE) != 0) { - label = economyService.getDefaultCurrency().getPluralDisplayName().toPlain(); + return economyService.getDefaultCurrency().getDisplayName().toPlain(); } + else { + return economyService.getDefaultCurrency().getPluralDisplayName().toPlain(); + } + } - try { - String value = valueNode.getString(); - if (value == null) { - Utils.setConfig("salarymessage", defaultMessage); - } else { - return TextSerializers.FORMATTING_CODE.deserialize(value.replaceAll("\\{amount\\}", amount.toString()).replaceAll("\\{label\\}", - label)); + private static Optional loadConfigurationNode(ConfigurationNode node, @Nullable T defaultValue) { + return loadConfigurationNode(node, null, defaultValue); + } + + // Loads a ConfigurationNode's comment and value, making changes as necessary + // defaultValue can be null if the node only contains other nodes. in this case, null will be returned as well. + // comment can be null if the node is not a CommentedConfigurationNode or doesn't need its comment set. + @SuppressWarnings("unchecked") + private static Optional loadConfigurationNode(ConfigurationNode node, @Nullable String comment, @Nullable T defaultValue) { + T nodeValue = null; + + if(comment != null && node instanceof CommentedConfigurationNode) { + CommentedConfigurationNode cNode = (CommentedConfigurationNode) node; + // If the node doesn't exist, or its comment is unset or incorrect, set the comment + if (node.isVirtual() || !cNode.getComment().isPresent() || !cNode.getComment().get().equals(comment)) { + cNode.setComment(comment); + } + } + + if(defaultValue != null) { + // Get the current value, or null if it's unset + Object nodeValueObj = node.getValue(); + + // If the value has never been set, set it silently + if (node.isVirtual() || nodeValueObj == null) { + node.setValue(defaultValue); + nodeValue = defaultValue; + } + else { + // Ensure the type of the node's value is the same as defaultValue's type + if (defaultValue.getClass().isInstance(nodeValueObj)) { + nodeValue = (T) nodeValueObj; + } + else { + PayDay.getLogger().warn("Configuration value " + node.getKey() + " of type " + nodeValueObj.getClass().getName() + " was found when it should have been " + defaultValue.getClass().getName()); + } } - } catch (RuntimeException e) { - Utils.setConfig("salarymessage", defaultMessage); + } - return TextSerializers.FORMATTING_CODE.deserialize(defaultMessage.replaceAll("\\{amount\\}", amount.toString()).replaceAll("\\{label\\}", - label)); + return Optional.ofNullable(nodeValue); } - public static void setConfig(String key, String value) { - ConfigurationLoader configManager = PayDay.getConfigManager(); - PayDay.config.getNode(key).setValue(value); + public static void warnIfMissingAfkService() { + Utils.warnIfMissingAfkService(null); + } - try { - configManager.save(PayDay.config); - configManager.load(); - } catch (IOException e) { - System.out.println("Failed to save " + key + "!"); + public static void warnIfMissingAfkService(@Nullable CommandSource src) { + if(PayDay.getAfkService() == null && enableAfkPay()) { + String warning1 = "Error! AFK payments are disabled in the config, but Nucleus' AFK service wasn't found!"; + String warning2 = "PayDay will be unable to determine whether players are AFK."; + + if (src == null) { + PayDay.getLogger().error(warning1); + PayDay.getLogger().error(warning2); + } else { + src.sendMessage(Text.of(warning1)); + src.sendMessage(Text.of(warning2)); + } } } }