diff --git a/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/rewards/RewardExecutionContext.java b/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/rewards/RewardExecutionContext.java new file mode 100644 index 0000000000..5b7334e5be --- /dev/null +++ b/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/rewards/RewardExecutionContext.java @@ -0,0 +1,61 @@ +package com.bencodez.advancedcore.api.rewards; + +import java.util.HashMap; + +import com.bencodez.advancedcore.api.user.AdvancedCoreUser; + +/** + * Internal execution state derived from {@link RewardOptions} for one reward + * dispatch operation. + *

+ * RewardOptions remains the public compatibility object; this class centralizes + * execution-specific normalization and naming rules so they are not repeated + * throughout the reward dispatcher. + */ +public final class RewardExecutionContext { + + private final RewardOptions options; + + public RewardExecutionContext(RewardOptions options) { + this.options = options == null ? new RewardOptions() : options; + } + + public RewardExecutionContext initializeOnlineState(AdvancedCoreUser user) { + if (user != null && !options.isOnlineSet()) { + options.setOnline(user.isOnline()); + } + return this; + } + + public String buildRewardName(String path) { + String rewardName = ""; + String prefix = options.getPrefix(); + if (prefix != null && !prefix.isEmpty()) { + rewardName += prefix + "_"; + } + rewardName += path == null ? "" : path.replace(".", "_"); + + String suffix = options.getSuffix(); + if (suffix != null && !suffix.isEmpty()) { + rewardName += "_" + suffix; + } + return rewardName; + } + + public HashMap getPlaceholders() { + return options.getPlaceholders(); + } + + public RewardOptions getOptions() { + return options; + } + + /** + * Preserves the existing direct/sub-direct dispatch condition. Prefix and + * suffix default to empty strings, so only explicit null values disable that + * compatibility path. + */ + public boolean supportsDirectDispatch() { + return options.getPrefix() != null && options.getSuffix() != null; + } +} diff --git a/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/rewards/RewardExecutor.java b/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/rewards/RewardExecutor.java new file mode 100644 index 0000000000..5f225d8aee --- /dev/null +++ b/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/rewards/RewardExecutor.java @@ -0,0 +1,177 @@ +package com.bencodez.advancedcore.api.rewards; + +import java.util.ArrayList; + +import org.bukkit.Bukkit; +import org.bukkit.configuration.Configuration; +import org.bukkit.configuration.ConfigurationSection; + +import com.bencodez.advancedcore.AdvancedCorePlugin; +import com.bencodez.advancedcore.api.misc.MiscUtils; +import com.bencodez.advancedcore.api.user.AdvancedCoreUser; +import com.bencodez.simpleapi.array.ArrayUtils; + +/** + * Executes and constructs rewards while {@link RewardHandler} remains the + * compatibility facade exposed to callers. + */ +public class RewardExecutor { + + private final RewardHandler handler; + private final AdvancedCorePlugin plugin; + + public RewardExecutor(RewardHandler handler, AdvancedCorePlugin plugin) { + this.handler = handler; + this.plugin = plugin; + } + + public Reward getReward(ConfigurationSection data, String path, RewardOptions rewardOptions) { + if (path == null) { + plugin.getLogger().warning("Path is null, failing to give reward"); + return null; + } + if (data == null) { + plugin.getLogger().warning("ConfigurationSection is null, failing to give reward: " + path); + return null; + } + if (!data.isConfigurationSection(path)) { + return null; + } + + RewardExecutionContext context = new RewardExecutionContext(rewardOptions); + return new Reward(context.buildRewardName(path), data.getConfigurationSection(path)); + } + + public void giveChoicesReward(Reward mainReward, AdvancedCoreUser user, String choice) { + RewardBuilder reward = new RewardBuilder(mainReward.getConfig().getConfigData(), + mainReward.getConfig().getChoicesRewardsPath(choice)); + reward.withPrefix(mainReward.getName()); + reward.withPlaceHolder("choice", choice); + reward.send(user); + } + + public void giveReward(AdvancedCoreUser user, ConfigurationSection data, String path, RewardOptions rewardOptions) { + RewardExecutionContext context = new RewardExecutionContext(rewardOptions).initializeOnlineState(user); + RewardOptions options = context.getOptions(); + + if (path == null) { + plugin.getLogger().warning("Path is null, failing to give reward"); + return; + } + if (data == null) { + plugin.getLogger().warning("ConfigurationSection is null, failing to give reward: " + path); + return; + } + if (!plugin.isEnabled()) { + plugin.getLogger().severe("Not giving reward " + path + ", plugin is not enabled"); + return; + } + + if (data.isList(path)) { + ArrayList rewards = new ArrayList<>(data.getStringList(path)); + if (rewards.isEmpty()) { + plugin.debug("Not giving empty list of rewards from " + path + ", Options: " + options); + return; + } + + plugin.debug("Giving list of rewards (" + ArrayUtils.makeStringList(rewards) + ") from " + path + + ", Options: " + options + " to " + user.getPlayerName() + "/" + user.getUUID()); + for (String reward : rewards) { + giveReward(user, reward, options); + } + return; + } + + if (data.isConfigurationSection(path)) { + giveSectionReward(user, data, path, context); + return; + } + + String reward = data.getString(path, ""); + if (!reward.isEmpty()) { + plugin.debug("Giving reward " + reward + " from path " + path + ", Options: " + options + " to " + + user.getPlayerName() + "/" + user.getUUID()); + giveReward(user, reward, options); + } else { + plugin.debug("Not giving reward " + reward + " from path " + path + ", Options: " + options); + } + } + + public void giveReward(AdvancedCoreUser user, Reward reward, RewardOptions rewardOptions) { + RewardExecutionContext context = new RewardExecutionContext(rewardOptions).initializeOnlineState(user); + if (reward == null) { + plugin.debug("Reward == null"); + return; + } + + if (Bukkit.isPrimaryThread()) { + plugin.getBukkitScheduler().runTaskAsynchronously(plugin, + () -> reward.giveReward(user, context.getOptions())); + } else { + reward.giveReward(user, context.getOptions()); + } + } + + public void giveReward(AdvancedCoreUser user, String reward, RewardOptions rewardOptions) { + RewardExecutionContext context = new RewardExecutionContext(rewardOptions).initializeOnlineState(user); + if (reward == null || reward.isEmpty()) { + return; + } + + if (reward.startsWith("/")) { + MiscUtils.getInstance().executeConsoleCommands(user.getPlayerName(), reward, context.getPlaceholders()); + return; + } + giveReward(user, handler.getReward(reward), context.getOptions()); + } + + public void updateReward(Configuration data, String path, RewardOptions rewardOptions) { + if (data == null || path == null || !data.isConfigurationSection(path)) { + return; + } + + RewardExecutionContext context = new RewardExecutionContext(rewardOptions); + Reward reward = new Reward(context.buildRewardName(path), data.getConfigurationSection(path)); + reward.checkRewardFile(); + } + + private void giveSectionReward(AdvancedCoreUser user, ConfigurationSection data, String path, + RewardExecutionContext context) { + RewardOptions options = context.getOptions(); + String rewardName = context.buildRewardName(path); + DirectlyDefinedReward direct = handler.getDirectlyDefined(path); + SubDirectlyDefinedReward sub = handler.getSubDirectlyDefined(rewardName); + + if (context.supportsDirectDispatch() && (direct != null || sub != null)) { + if (direct != null) { + Reward reward = direct.getReward(); + if (reward != null) { + plugin.debug("Giving directlydefined reward " + path + ", Options: " + options + " to " + + user.getPlayerName() + "/" + user.getUUID()); + giveReward(user, reward, options); + } else { + plugin.debug("Failed to give directlydefined reward " + path + ", Options: " + options + + ", Reward == null"); + } + return; + } + + Reward reward = sub.getReward(); + if (reward != null) { + plugin.debug("Giving subdirectlydefined reward " + rewardName + ", Options: " + options + " to " + + user.getPlayerName() + "/" + user.getUUID()); + giveReward(user, reward, options); + } else { + plugin.debug("Failed to give subdirectlydefined reward " + path + ", Options: " + options + + ", Reward == null"); + } + return; + } + + Reward reward = new Reward(rewardName, data.getConfigurationSection(path)); + reward.checkRewardFile(); + plugin.debug("Giving reward " + path + ", Options: " + options + " to " + user.getPlayerName() + "/" + + user.getUUID()); + giveReward(user, reward, options); + } +} diff --git a/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/rewards/RewardHandler.java b/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/rewards/RewardHandler.java index 00dc9ac6a7..137c224a26 100644 --- a/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/rewards/RewardHandler.java +++ b/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/rewards/RewardHandler.java @@ -11,20 +11,17 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import org.bukkit.Bukkit; import org.bukkit.configuration.Configuration; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; import com.bencodez.advancedcore.AdvancedCorePlugin; -import com.bencodez.advancedcore.api.misc.MiscUtils; import com.bencodez.advancedcore.api.rewards.injected.RewardInject; import com.bencodez.advancedcore.api.rewards.injectedrequirement.RequirementInject; import com.bencodez.advancedcore.api.user.AdvancedCoreUser; import com.bencodez.advancedcore.api.user.UserStartup; import com.bencodez.advancedcore.command.gui.RewardEditGUI; -import com.bencodez.simpleapi.array.ArrayUtils; import lombok.Getter; @@ -34,414 +31,270 @@ */ public class RewardHandler { - @Getter - private final RewardRegistry rewardRegistry; - @Getter - private final RewardLoader rewardLoader; - @Getter - private final RewardValidator rewardValidator; - @Getter - private final SubRewardResolver subRewardResolver; - @Getter - private final RewardInjectionRegistry rewardInjectionRegistry; - - AdvancedCorePlugin plugin; - - @Getter - private ScheduledExecutorService delayedTimer = Executors.newSingleThreadScheduledExecutor(); - - public RewardHandler(AdvancedCorePlugin plugin) { - this.plugin = plugin; - rewardRegistry = new RewardRegistry(plugin); - rewardInjectionRegistry = new RewardInjectionRegistry(this, plugin); - rewardValidator = new RewardValidator(this, plugin); - subRewardResolver = new SubRewardResolver(this, plugin); - rewardLoader = new RewardLoader(this, plugin); - } - - public void addDirectlyDefined(DirectlyDefinedReward directlyDefinedReward) { - rewardRegistry.addDirectlyDefined(directlyDefinedReward); - } - - public void addInjectedRequirements(RequirementInject inject) { - rewardInjectionRegistry.addInjectedRequirement(inject); - } - - public void addInjectedReward(RewardInject inject) { - rewardInjectionRegistry.addInjectedReward(inject); - } - - public void addPlaceholder(RewardPlaceholderHandle handle) { - rewardInjectionRegistry.addPlaceholder(handle); - } - - public void addRewardFolder(File file) { - rewardLoader.addRewardFolder(file); - } - - public void addRewardFolder(File file, boolean load, boolean create) { - rewardLoader.addRewardFolder(file, load, create); - } - - public void addSubDirectlyDefined(SubDirectlyDefinedReward subDirectlyDefinedReward) { - rewardRegistry.addSubDirectlyDefined(subDirectlyDefinedReward); - } - - public void addValidPath(String path) { - rewardValidator.addValidPath(path); - } - - public void checkDirectlyDefinedRewardFiles() { - rewardValidator.checkDirectlyDefinedRewardFiles(); - } - - public void checkDirectlyDefined() { - rewardLoader.checkDirectlyDefined(); - } - - public void checkSubRewards() { - subRewardResolver.checkSubRewards(); - } - - public void checkSubRewards(DefinedReward direct) { - subRewardResolver.checkSubRewards(direct); - } - - public File getDefaultFolder() { - return rewardLoader.getDefaultFolder(); - } - - public DirectlyDefinedReward getDirectlyDefined(String path) { - return rewardRegistry.getDirectlyDefined(path); - } - - public CopyOnWriteArrayList getDirectlyDefinedRewards() { - return rewardRegistry.getDirectlyDefinedRewards(); - } - - public CopyOnWriteArrayList getInjectedRequirements() { - return rewardInjectionRegistry.getInjectedRequirements(); - } - - public CopyOnWriteArrayList getInjectedRewards() { - return rewardInjectionRegistry.getInjectedRewards(); - } - - public CopyOnWriteArrayList getPlaceholders() { - return rewardInjectionRegistry.getPlaceholders(); - } - - public Reward getReward(ConfigurationSection data, String path, RewardOptions rewardOptions) { - if (path == null) { - plugin.getLogger().warning("Path is null, failing to give reward"); - return null; - } - if (data == null) { - plugin.getLogger().warning("ConfigurationSection is null, failing to give reward: " + path); - return null; - } - if (data.isConfigurationSection(path)) { - String rewardName = ""; - String prefix = rewardOptions.getPrefix(); - if (prefix != null && !prefix.equals("")) { - rewardName += prefix + "_"; - } - rewardName += path.replace(".", "_"); - - String suffix = rewardOptions.getSuffix(); - if (suffix != null && !suffix.equals("")) { - rewardName += "_" + suffix; - } - ConfigurationSection section = data.getConfigurationSection(path); - return new Reward(rewardName, section); - } - return null; - } - - public Reward getReward(String reward) { - return rewardRegistry.getReward(reward); - } - - public Reward getRewardDirectlyDefined(String reward) { - return rewardLoader.getRewardDirectlyDefined(reward); - } - - public ArrayList getRewardFiles(File folder) { - return rewardLoader.getRewardFiles(folder); - } - - public ArrayList getRewardNames(File file) { - return rewardLoader.getRewardNames(file); - } - - public List getRewards() { - return rewardRegistry.getRewards(); - } - - public SubDirectlyDefinedReward getSubDirectlyDefined(String path) { - return rewardRegistry.getSubDirectlyDefined(path); - } - - public CopyOnWriteArrayList getSubDirectlyDefinedRewards() { - return rewardRegistry.getSubDirectlyDefinedRewards(); - } - - public Set getValidPaths() { - return rewardValidator.getValidPaths(); - } - - public void setValidPaths(Set validPaths) { - rewardValidator.setValidPaths(validPaths); - } - - public void giveChoicesReward(Reward mainReward, AdvancedCoreUser user, String choice) { - RewardBuilder reward = new RewardBuilder(mainReward.getConfig().getConfigData(), - mainReward.getConfig().getChoicesRewardsPath(choice)); - reward.withPrefix(mainReward.getName()); - reward.withPlaceHolder("choice", choice); - reward.send(user); - } - - @SuppressWarnings("unchecked") - public void giveReward(AdvancedCoreUser user, ConfigurationSection data, String path, RewardOptions rewardOptions) { - if (!rewardOptions.isOnlineSet()) { - rewardOptions.setOnline(user.isOnline()); - } - if (path == null) { - plugin.getLogger().warning("Path is null, failing to give reward"); - return; - } - if (data == null) { - plugin.getLogger().warning("ConfigurationSection is null, failing to give reward: " + path); - return; - } - if (plugin == null || !plugin.isEnabled()) { - plugin.getLogger().severe("Not giving reward " + path + ", plugin is not enabled"); - return; - } - if (data.isList(path)) { - ArrayList rewards = (ArrayList) data.getList(path, new ArrayList<>()); - if (rewards.isEmpty()) { - plugin.debug( - "Not giving empty list of rewards from " + path + ", Options: " + rewardOptions.toString()); - } else { - plugin.debug("Giving list of rewards (" + ArrayUtils.makeStringList(rewards) + ") from " + path - + ", Options: " + rewardOptions.toString() + " to " + user.getPlayerName() + "/" - + user.getUUID()); - for (String reward : rewards) { - giveReward(user, reward, rewardOptions); - } - } - } else if (data.isConfigurationSection(path)) { - String rewardName = ""; - String prefix = rewardOptions.getPrefix(); - if (prefix != null && !prefix.equals("")) { - rewardName += prefix + "_"; - } - rewardName += path.replace(".", "_"); - - String suffix = rewardOptions.getSuffix(); - if (suffix != null && !suffix.equals("")) { - rewardName += "_" + suffix; - } - DirectlyDefinedReward direct = getDirectlyDefined(path); - SubDirectlyDefinedReward sub = getSubDirectlyDefined(rewardName); - if (suffix != null && prefix != null && (direct != null || sub != null)) { - if (direct != null) { - Reward reward = direct.getReward(); - if (reward != null) { - plugin.debug("Giving directlydefined reward " + path + ", Options: " + rewardOptions.toString() - + " to " + user.getPlayerName() + "/" + user.getUUID()); - giveReward(user, reward, rewardOptions); - } else { - plugin.debug("Failed to give directlydefined reward " + path + ", Options: " - + rewardOptions.toString() + ", Reward == null"); - } - } else { - Reward reward = sub.getReward(); - if (reward != null) { - plugin.debug("Giving subdirectlydefined reward " + rewardName + ", Options: " - + rewardOptions.toString() + " to " + user.getPlayerName() + "/" + user.getUUID()); - giveReward(user, reward, rewardOptions); - } else { - plugin.debug("Failed to give subdirectlydefined reward " + path + ", Options: " - + rewardOptions.toString() + ", Reward == null"); - } - } - } else { - ConfigurationSection section = data.getConfigurationSection(path); - Reward reward = new Reward(rewardName, section); - reward.checkRewardFile(); - plugin.debug("Giving reward " + path + ", Options: " + rewardOptions.toString() + " to " - + user.getPlayerName() + "/" + user.getUUID()); - giveReward(user, reward, rewardOptions); - } - } else { - String reward = data.getString(path, ""); - if (!reward.isEmpty()) { - plugin.debug("Giving reward " + reward + " from path " + path + ", Options: " + rewardOptions.toString() - + " to " + user.getPlayerName() + "/" + user.getUUID()); - giveReward(user, reward, rewardOptions); - } else { - plugin.debug("Not giving reward " + reward + " from path " + path + ", Options: " - + rewardOptions.toString()); - } - } - } - - public void giveReward(AdvancedCoreUser user, Reward reward, RewardOptions rewardOptions) { - if (reward != null) { - if (Bukkit.isPrimaryThread()) { - plugin.getBukkitScheduler().runTaskAsynchronously(plugin, new Runnable() { - @Override - public void run() { - reward.giveReward(user, rewardOptions); - } - }); - } else { - reward.giveReward(user, rewardOptions); - } - } else { - plugin.debug("Reward == null"); - } - } - - public void giveReward(AdvancedCoreUser user, String reward, RewardOptions rewardOptions) { - if (!reward.equals("")) { - if (reward.startsWith("/")) { - MiscUtils.getInstance().executeConsoleCommands(user.getPlayerName(), reward, - rewardOptions.getPlaceholders()); - return; - } - giveReward(user, getReward(reward), rewardOptions); - } - } - - public boolean hasDirectRewardHandle(String reward) { - return rewardRegistry.hasDirectRewardHandle(reward); - } - - public boolean hasRewards(FileConfiguration data, String path) { - return rewardValidator.hasRewards(data, path); - } - - public void loadInjectedRequirements() { - rewardInjectionRegistry.loadInjectedRequirements(); - } - - public void loadInjectedRewards() { - rewardInjectionRegistry.loadInjectedRewards(); - } - - public void loadRewards() { - rewardLoader.loadRewards(); - } - - public void openSubReward(Player player, String path, RewardEditData reward) { - if (!reward.getData().contains(path)) { - reward.createSection(path); - } - RewardEditGUI.getInstance().openRewardGUI(player, new RewardEditData(new DirectlyDefinedReward(path) { - @Override - public void createSection(String path) { - reward.createSection(path); - } - - @Override - public ConfigurationSection getFileData() { - return reward.getData(); - } - - @Override - public void save() { - reward.save(); - } - - @Override - public void setData(String path, Object value) { - reward.setValue(path, value); - } - }, reward), reward.getName() + "." + path); - } - - public boolean rewardExist(String reward) { - return rewardRegistry.rewardExist(reward); - } - - public void setDefaultFolder(File defaultFolder) { - rewardLoader.setDefaultFolder(defaultFolder); - } - - public void setupExample() { - rewardLoader.setupExample(); - } - - public void shutdown() { - delayedTimer.shutdown(); - try { - delayedTimer.awaitTermination(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - } - delayedTimer.shutdownNow(); - } - - public void sortInjectedRequirements() { - rewardInjectionRegistry.sortInjectedRequirements(); - } - - public void sortInjectedRewards() { - rewardInjectionRegistry.sortInjectedRewards(); - } - - public void startup() { - plugin.addUserStartup(new UserStartup() { - @Override - public void onFinish() { - } - - @Override - public void onStart() { - plugin.debug("Checking timed/delayed rewards"); - } - - @Override - public void onStartUp(AdvancedCoreUser user) { - try { - HashMap timed = user.getTimedRewards(); - for (Entry entry : timed.entrySet()) { - user.loadTimedDelayedTimer(entry.getValue().longValue()); - } - } catch (Exception ex) { - plugin.debug("Failed to update delayed/timed for: " + user.getUUID()); - plugin.debug(ex); - } - } - }); - } - - public void updateReward(Configuration data, String path, RewardOptions rewardOptions) { - if (rewardOptions == null) { - rewardOptions = new RewardOptions(); - } - if (data.isConfigurationSection(path)) { - String rewardName = ""; - String prefix = rewardOptions.getPrefix(); - if (prefix != null && !prefix.equals("")) { - rewardName += prefix + "_"; - } - rewardName += path.replace(".", "_"); - String suffix = rewardOptions.getSuffix(); - if (suffix != null && !suffix.equals("")) { - rewardName += "_" + suffix; - } - ConfigurationSection section = data.getConfigurationSection(path); - Reward reward = new Reward(rewardName, section); - reward.checkRewardFile(); - } - } - - public void updateReward(Reward reward) { - rewardRegistry.updateReward(reward); - } + @Getter + private final RewardRegistry rewardRegistry; + @Getter + private final RewardLoader rewardLoader; + @Getter + private final RewardValidator rewardValidator; + @Getter + private final SubRewardResolver subRewardResolver; + @Getter + private final RewardInjectionRegistry rewardInjectionRegistry; + @Getter + private final RewardExecutor rewardExecutor; + + AdvancedCorePlugin plugin; + + @Getter + private ScheduledExecutorService delayedTimer = Executors.newSingleThreadScheduledExecutor(); + + public RewardHandler(AdvancedCorePlugin plugin) { + this.plugin = plugin; + rewardRegistry = new RewardRegistry(plugin); + rewardInjectionRegistry = new RewardInjectionRegistry(this, plugin); + rewardValidator = new RewardValidator(this, plugin); + subRewardResolver = new SubRewardResolver(this, plugin); + rewardLoader = new RewardLoader(this, plugin); + rewardExecutor = new RewardExecutor(this, plugin); + } + + public void addDirectlyDefined(DirectlyDefinedReward directlyDefinedReward) { + rewardRegistry.addDirectlyDefined(directlyDefinedReward); + } + + public void addInjectedRequirements(RequirementInject inject) { + rewardInjectionRegistry.addInjectedRequirement(inject); + } + + public void addInjectedReward(RewardInject inject) { + rewardInjectionRegistry.addInjectedReward(inject); + } + + public void addPlaceholder(RewardPlaceholderHandle handle) { + rewardInjectionRegistry.addPlaceholder(handle); + } + + public void addRewardFolder(File file) { + rewardLoader.addRewardFolder(file); + } + + public void addRewardFolder(File file, boolean load, boolean create) { + rewardLoader.addRewardFolder(file, load, create); + } + + public void addSubDirectlyDefined(SubDirectlyDefinedReward subDirectlyDefinedReward) { + rewardRegistry.addSubDirectlyDefined(subDirectlyDefinedReward); + } + + public void addValidPath(String path) { + rewardValidator.addValidPath(path); + } + + public void checkDirectlyDefinedRewardFiles() { + rewardValidator.checkDirectlyDefinedRewardFiles(); + } + + public void checkDirectlyDefined() { + rewardLoader.checkDirectlyDefined(); + } + + public void checkSubRewards() { + subRewardResolver.checkSubRewards(); + } + + public void checkSubRewards(DefinedReward direct) { + subRewardResolver.checkSubRewards(direct); + } + + public File getDefaultFolder() { + return rewardLoader.getDefaultFolder(); + } + + public DirectlyDefinedReward getDirectlyDefined(String path) { + return rewardRegistry.getDirectlyDefined(path); + } + + public CopyOnWriteArrayList getDirectlyDefinedRewards() { + return rewardRegistry.getDirectlyDefinedRewards(); + } + + public CopyOnWriteArrayList getInjectedRequirements() { + return rewardInjectionRegistry.getInjectedRequirements(); + } + + public CopyOnWriteArrayList getInjectedRewards() { + return rewardInjectionRegistry.getInjectedRewards(); + } + + public CopyOnWriteArrayList getPlaceholders() { + return rewardInjectionRegistry.getPlaceholders(); + } + + public Reward getReward(ConfigurationSection data, String path, RewardOptions rewardOptions) { + return rewardExecutor.getReward(data, path, rewardOptions); + } + + public Reward getReward(String reward) { + return rewardRegistry.getReward(reward); + } + + public Reward getRewardDirectlyDefined(String reward) { + return rewardLoader.getRewardDirectlyDefined(reward); + } + + public ArrayList getRewardFiles(File folder) { + return rewardLoader.getRewardFiles(folder); + } + + public ArrayList getRewardNames(File file) { + return rewardLoader.getRewardNames(file); + } + + public List getRewards() { + return rewardRegistry.getRewards(); + } + + public SubDirectlyDefinedReward getSubDirectlyDefined(String path) { + return rewardRegistry.getSubDirectlyDefined(path); + } + + public CopyOnWriteArrayList getSubDirectlyDefinedRewards() { + return rewardRegistry.getSubDirectlyDefinedRewards(); + } + + public Set getValidPaths() { + return rewardValidator.getValidPaths(); + } + + public void setValidPaths(Set validPaths) { + rewardValidator.setValidPaths(validPaths); + } + + public void giveChoicesReward(Reward mainReward, AdvancedCoreUser user, String choice) { + rewardExecutor.giveChoicesReward(mainReward, user, choice); + } + + public void giveReward(AdvancedCoreUser user, ConfigurationSection data, String path, RewardOptions rewardOptions) { + rewardExecutor.giveReward(user, data, path, rewardOptions); + } + + public void giveReward(AdvancedCoreUser user, Reward reward, RewardOptions rewardOptions) { + rewardExecutor.giveReward(user, reward, rewardOptions); + } + + public void giveReward(AdvancedCoreUser user, String reward, RewardOptions rewardOptions) { + rewardExecutor.giveReward(user, reward, rewardOptions); + } + + public boolean hasDirectRewardHandle(String reward) { + return rewardRegistry.hasDirectRewardHandle(reward); + } + + public boolean hasRewards(FileConfiguration data, String path) { + return rewardValidator.hasRewards(data, path); + } + + public void loadInjectedRequirements() { + rewardInjectionRegistry.loadInjectedRequirements(); + } + + public void loadInjectedRewards() { + rewardInjectionRegistry.loadInjectedRewards(); + } + + public void loadRewards() { + rewardLoader.loadRewards(); + } + + public void openSubReward(Player player, String path, RewardEditData reward) { + if (!reward.getData().contains(path)) { + reward.createSection(path); + } + RewardEditGUI.getInstance().openRewardGUI(player, new RewardEditData(new DirectlyDefinedReward(path) { + @Override + public void createSection(String path) { + reward.createSection(path); + } + + @Override + public ConfigurationSection getFileData() { + return reward.getData(); + } + + @Override + public void save() { + reward.save(); + } + + @Override + public void setData(String path, Object value) { + reward.setValue(path, value); + } + }, reward), reward.getName() + "." + path); + } + + public boolean rewardExist(String reward) { + return rewardRegistry.rewardExist(reward); + } + + public void setDefaultFolder(File defaultFolder) { + rewardLoader.setDefaultFolder(defaultFolder); + } + + public void setupExample() { + rewardLoader.setupExample(); + } + + public void shutdown() { + delayedTimer.shutdown(); + try { + delayedTimer.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + delayedTimer.shutdownNow(); + } + + public void sortInjectedRequirements() { + rewardInjectionRegistry.sortInjectedRequirements(); + } + + public void sortInjectedRewards() { + rewardInjectionRegistry.sortInjectedRewards(); + } + + public void startup() { + plugin.addUserStartup(new UserStartup() { + @Override + public void onFinish() { + } + + @Override + public void onStart() { + plugin.debug("Checking timed/delayed rewards"); + } + + @Override + public void onStartUp(AdvancedCoreUser user) { + try { + HashMap timed = user.getTimedRewards(); + for (Entry entry : timed.entrySet()) { + user.loadTimedDelayedTimer(entry.getValue().longValue()); + } + } catch (Exception ex) { + plugin.debug("Failed to update delayed/timed for: " + user.getUUID()); + plugin.debug(ex); + } + } + }); + } + + public void updateReward(Configuration data, String path, RewardOptions rewardOptions) { + rewardExecutor.updateReward(data, path, rewardOptions); + } + + public void updateReward(Reward reward) { + rewardRegistry.updateReward(reward); + } } diff --git a/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/rewards/RewardRegistry.java b/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/rewards/RewardRegistry.java index 010d5f74c0..fa360ea950 100644 --- a/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/rewards/RewardRegistry.java +++ b/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/rewards/RewardRegistry.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.concurrent.CopyOnWriteArrayList; import com.bencodez.advancedcore.AdvancedCorePlugin; @@ -15,152 +16,165 @@ */ public class RewardRegistry { - private final AdvancedCorePlugin plugin; - private final CopyOnWriteArrayList directlyDefinedRewards = new CopyOnWriteArrayList<>(); - private CopyOnWriteArrayList subDirectlyDefinedRewards = new CopyOnWriteArrayList<>(); - private List rewards; - - public RewardRegistry(AdvancedCorePlugin plugin) { - this.plugin = plugin; - resetRewards(); - } - - public void addDirectlyDefined(DirectlyDefinedReward directlyDefinedReward) { - if (getDirectlyDefined(directlyDefinedReward.getPath()) != null) { - plugin.extraDebug( - "DirectlyDefinedReward with path already exists, skipping: " + directlyDefinedReward.getPath()); - return; - } - plugin.extraDebug("Adding directlydefined reward handle: " + directlyDefinedReward.getPath() - + ", isdirectlydefined: " + directlyDefinedReward.isDirectlyDefined()); - directlyDefinedRewards.add(directlyDefinedReward); - } - - public void addSubDirectlyDefined(SubDirectlyDefinedReward subDirectlyDefinedReward) { - plugin.extraDebug("Adding subdirectlydefined reward handle: " + subDirectlyDefinedReward.getFullPath() - + ", isdirectlydefined: " + subDirectlyDefinedReward.isDirectlyDefined()); - subDirectlyDefinedRewards.add(subDirectlyDefinedReward); - } - - public DirectlyDefinedReward getDirectlyDefined(String path) { - for (DirectlyDefinedReward direct : directlyDefinedRewards) { - if (direct.getPath().equalsIgnoreCase(path)) { - return direct; - } - } - return null; - } - - public CopyOnWriteArrayList getDirectlyDefinedRewards() { - return directlyDefinedRewards; - } - - public Reward getReward(String reward) { - if (reward == null) { - reward = ""; - } - reward = reward.replace(" ", "_"); - - if (reward.equals("")) { - plugin.getLogger().warning("Tried to get any empty reward file name, renaming to EmptyName"); - reward = "EmptyName"; - } - - if (reward.equalsIgnoreCase("examplebasic") || reward.equalsIgnoreCase("exampleadvanced")) { - plugin.getLogger().warning("Using example rewards as a reward, be carefull"); - } - - for (DirectlyDefinedReward direct : directlyDefinedRewards) { - if (direct.getPath().replace(".", "_").equals(reward)) { - plugin.debug("Using directlydefined reward for: " + reward); - return direct.getReward(); - } - } - - for (SubDirectlyDefinedReward direct : subDirectlyDefinedRewards) { - if (matchesSubDirectlyDefined(direct, reward)) { - plugin.debug("Using subdirectlydefined reward for: " + reward); - return direct.getReward(); - } - } - - for (Reward rewardFile : getRewards()) { - if (rewardFile.getName().equalsIgnoreCase(reward)) { - return rewardFile; - } - } - - return new Reward(reward); - } - - public List getRewards() { - if (rewards == null) { - resetRewards(); - } - return rewards; - } - - public SubDirectlyDefinedReward getSubDirectlyDefined(String path) { - for (SubDirectlyDefinedReward direct : subDirectlyDefinedRewards) { - if (matchesSubDirectlyDefined(direct, path)) { - return direct; - } - } - return null; - } - - public CopyOnWriteArrayList getSubDirectlyDefinedRewards() { - return subDirectlyDefinedRewards; - } - - public boolean hasDirectRewardHandle(String reward) { - for (DirectlyDefinedReward direct : directlyDefinedRewards) { - if (direct.getPath().replace(".", "_").equals(reward)) { - return true; - } - } - for (SubDirectlyDefinedReward direct : subDirectlyDefinedRewards) { - if (matchesSubDirectlyDefined(direct, reward)) { - return true; - } - } - return false; - } - - public boolean rewardExist(String reward) { - if (reward.equals("")) { - return false; - } - for (Reward rewardName : getRewards()) { - if (rewardName.getName().equalsIgnoreCase(reward)) { - return true; - } - } - return false; - } - - public void resetRewards() { - rewards = Collections.synchronizedList(new ArrayList()); - } - - public void resetSubDirectlyDefinedRewards() { - subDirectlyDefinedRewards = new CopyOnWriteArrayList<>(); - } - - public void updateReward(Reward reward) { - reward.validate(); - for (int i = getRewards().size() - 1; i >= 0; i--) { - if (getRewards().get(i).getFile().getPath().equals(reward.getFile().getPath())) { - getRewards().set(i, reward); - return; - } - } - getRewards().add(reward); - } - - private boolean matchesSubDirectlyDefined(SubDirectlyDefinedReward direct, String reward) { - return direct.getFullPath().equalsIgnoreCase(reward) - || direct.getFullPath().replace(".", "_").equalsIgnoreCase(reward) - || direct.getFullPath().equalsIgnoreCase(reward.replaceAll("_", ".")); - } + private final AdvancedCorePlugin plugin; + private final CopyOnWriteArrayList directlyDefinedRewards = new CopyOnWriteArrayList<>(); + private CopyOnWriteArrayList subDirectlyDefinedRewards = new CopyOnWriteArrayList<>(); + private List rewards; + + public RewardRegistry(AdvancedCorePlugin plugin) { + this.plugin = plugin; + resetRewards(); + } + + public void addDirectlyDefined(DirectlyDefinedReward directlyDefinedReward) { + if (getDirectlyDefined(directlyDefinedReward.getPath()) != null) { + plugin.extraDebug( + "DirectlyDefinedReward with path already exists, skipping: " + directlyDefinedReward.getPath()); + return; + } + plugin.extraDebug("Adding directlydefined reward handle: " + directlyDefinedReward.getPath() + + ", isdirectlydefined: " + directlyDefinedReward.isDirectlyDefined()); + directlyDefinedRewards.add(directlyDefinedReward); + } + + public void addSubDirectlyDefined(SubDirectlyDefinedReward subDirectlyDefinedReward) { + if (getSubDirectlyDefined(subDirectlyDefinedReward.getFullPath()) != null) { + plugin.extraDebug("SubDirectlyDefinedReward with path already exists, skipping: " + + subDirectlyDefinedReward.getFullPath()); + return; + } + plugin.extraDebug("Adding subdirectlydefined reward handle: " + subDirectlyDefinedReward.getFullPath() + + ", isdirectlydefined: " + subDirectlyDefinedReward.isDirectlyDefined()); + subDirectlyDefinedRewards.add(subDirectlyDefinedReward); + } + + public DirectlyDefinedReward getDirectlyDefined(String path) { + for (DirectlyDefinedReward direct : directlyDefinedRewards) { + if (matchesDirectPath(direct.getPath(), path)) { + return direct; + } + } + return null; + } + + public CopyOnWriteArrayList getDirectlyDefinedRewards() { + return directlyDefinedRewards; + } + + public Reward getReward(String reward) { + reward = normalizeLookupName(reward); + + if (reward.isEmpty()) { + plugin.getLogger().warning("Tried to get any empty reward file name, renaming to EmptyName"); + reward = "EmptyName"; + } + + if (reward.equalsIgnoreCase("examplebasic") || reward.equalsIgnoreCase("exampleadvanced")) { + plugin.getLogger().warning("Using example rewards as a reward, be carefull"); + } + + for (DirectlyDefinedReward direct : directlyDefinedRewards) { + if (matchesDirectPath(direct.getPath(), reward)) { + plugin.debug("Using directlydefined reward for: " + reward); + return direct.getReward(); + } + } + + for (SubDirectlyDefinedReward direct : subDirectlyDefinedRewards) { + if (matchesSubDirectlyDefined(direct, reward)) { + plugin.debug("Using subdirectlydefined reward for: " + reward); + return direct.getReward(); + } + } + + for (Reward rewardFile : getRewards()) { + if (rewardFile.getName().equalsIgnoreCase(reward)) { + return rewardFile; + } + } + + return new Reward(reward); + } + + public List getRewards() { + if (rewards == null) { + resetRewards(); + } + return rewards; + } + + public SubDirectlyDefinedReward getSubDirectlyDefined(String path) { + for (SubDirectlyDefinedReward direct : subDirectlyDefinedRewards) { + if (matchesSubDirectlyDefined(direct, path)) { + return direct; + } + } + return null; + } + + public CopyOnWriteArrayList getSubDirectlyDefinedRewards() { + return subDirectlyDefinedRewards; + } + + public boolean hasDirectRewardHandle(String reward) { + for (DirectlyDefinedReward direct : directlyDefinedRewards) { + if (matchesDirectPath(direct.getPath(), reward)) { + return true; + } + } + for (SubDirectlyDefinedReward direct : subDirectlyDefinedRewards) { + if (matchesSubDirectlyDefined(direct, reward)) { + return true; + } + } + return false; + } + + public static String normalizeLookupName(String reward) { + return reward == null ? "" : reward.replace(" ", "_"); + } + + public static String normalizeDirectPath(String path) { + return normalizeLookupName(path).replace('.', '_').toLowerCase(Locale.ROOT); + } + + public boolean rewardExist(String reward) { + reward = normalizeLookupName(reward); + if (reward.isEmpty()) { + return false; + } + for (Reward rewardName : getRewards()) { + if (rewardName.getName().equalsIgnoreCase(reward)) { + return true; + } + } + return false; + } + + public void resetRewards() { + rewards = Collections.synchronizedList(new ArrayList()); + } + + public void resetSubDirectlyDefinedRewards() { + subDirectlyDefinedRewards = new CopyOnWriteArrayList<>(); + } + + public void updateReward(Reward reward) { + reward.validate(); + for (int i = getRewards().size() - 1; i >= 0; i--) { + if (getRewards().get(i).getFile().getPath().equals(reward.getFile().getPath())) { + getRewards().set(i, reward); + return; + } + } + getRewards().add(reward); + } + + private boolean matchesDirectPath(String registeredPath, String lookupPath) { + return normalizeDirectPath(registeredPath).equals(normalizeDirectPath(lookupPath)); + } + + private boolean matchesSubDirectlyDefined(SubDirectlyDefinedReward direct, String reward) { + return matchesDirectPath(direct.getFullPath(), reward); + } } diff --git a/AdvancedCore/src/test/java/com/bencodez/advancedcore/tests/rewards/RewardExecutorTest.java b/AdvancedCore/src/test/java/com/bencodez/advancedcore/tests/rewards/RewardExecutorTest.java new file mode 100644 index 0000000000..52926d2b3c --- /dev/null +++ b/AdvancedCore/src/test/java/com/bencodez/advancedcore/tests/rewards/RewardExecutorTest.java @@ -0,0 +1,279 @@ +package com.bencodez.advancedcore.tests.rewards; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockConstruction; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import java.util.logging.Logger; + +import org.bukkit.Bukkit; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.MockedConstruction; +import org.mockito.MockedStatic; + +import com.bencodez.advancedcore.AdvancedCorePlugin; +import com.bencodez.advancedcore.api.misc.MiscUtils; +import com.bencodez.advancedcore.api.rewards.DirectlyDefinedReward; +import com.bencodez.advancedcore.api.rewards.Reward; +import com.bencodez.advancedcore.api.rewards.RewardBuilder; +import com.bencodez.advancedcore.api.rewards.RewardExecutionContext; +import com.bencodez.advancedcore.api.rewards.RewardExecutor; +import com.bencodez.advancedcore.api.rewards.RewardFileData; +import com.bencodez.advancedcore.api.rewards.RewardHandler; +import com.bencodez.advancedcore.api.rewards.RewardOptions; +import com.bencodez.advancedcore.api.rewards.SubDirectlyDefinedReward; +import com.bencodez.advancedcore.api.user.AdvancedCoreUser; +import com.bencodez.simpleapi.scheduler.BukkitScheduler; + +public class RewardExecutorTest { + + private AdvancedCorePlugin plugin; + private RewardHandler handler; + private AdvancedCoreUser user; + private RewardExecutor executor; + + @BeforeEach + public void setUp() { + plugin = mock(AdvancedCorePlugin.class); + handler = mock(RewardHandler.class); + user = mock(AdvancedCoreUser.class); + executor = new RewardExecutor(handler, plugin); + + when(plugin.getLogger()).thenReturn(mock(Logger.class)); + when(plugin.isEnabled()).thenReturn(true); + when(user.getPlayerName()).thenReturn("Ben"); + when(user.getUUID()).thenReturn("uuid"); + when(user.isOnline()).thenReturn(true); + } + + @Test + public void executionContextBuildsRewardNamesAndInitializesOnlineState() { + RewardOptions options = new RewardOptions().setPrefix("Parent").setSuffix("Child"); + RewardExecutionContext context = new RewardExecutionContext(options); + when(user.isOnline()).thenReturn(false); + + context.initializeOnlineState(user); + + assertSame(options, context.getOptions()); + assertTrue(options.isOnlineSet()); + assertFalse(options.isOnline()); + assertEquals("Parent_Nested_Reward_Child", context.buildRewardName("Nested.Reward")); + } + + @Test + public void nullOptionsProduceAUsableExecutionContext() { + RewardExecutionContext context = new RewardExecutionContext(null).initializeOnlineState(user); + + assertNotNull(context.getOptions()); + assertTrue(context.getOptions().isOnlineSet()); + assertEquals("Reward", context.buildRewardName("Reward")); + } + + @Test + public void getRewardConstructsInlineRewardUsingPrefixAndSuffix() { + YamlConfiguration data = new YamlConfiguration(); + ConfigurationSection section = data.createSection("Nested.Reward"); + RewardOptions options = new RewardOptions().setPrefix("Parent").setSuffix("Child"); + AtomicReference> arguments = new AtomicReference<>(); + + try (MockedConstruction rewards = mockConstruction(Reward.class, + (mock, context) -> arguments.set(context.arguments()))) { + Reward result = executor.getReward(data, "Nested.Reward", options); + + assertSame(rewards.constructed().get(0), result); + assertEquals("Parent_Nested_Reward_Child", arguments.get().get(0)); + assertSame(section, arguments.get().get(1)); + } + } + + @Test + public void listRewardDispatchesEveryNamedReward() { + YamlConfiguration data = new YamlConfiguration(); + data.set("Rewards", new ArrayList<>(List.of("First", "Second"))); + Reward first = mock(Reward.class); + Reward second = mock(Reward.class); + RewardOptions options = new RewardOptions(); + when(handler.getReward("First")).thenReturn(first); + when(handler.getReward("Second")).thenReturn(second); + + try (MockedStatic bukkit = mockStatic(Bukkit.class)) { + bukkit.when(Bukkit::isPrimaryThread).thenReturn(false); + executor.giveReward(user, data, "Rewards", options); + } + + verify(first).giveReward(user, options); + verify(second).giveReward(user, options); + assertTrue(options.isOnlineSet()); + } + + @Test + public void stringRewardDispatchesNamedReward() { + YamlConfiguration data = new YamlConfiguration(); + data.set("Reward", "Daily"); + Reward daily = mock(Reward.class); + when(handler.getReward("Daily")).thenReturn(daily); + + try (MockedStatic bukkit = mockStatic(Bukkit.class)) { + bukkit.when(Bukkit::isPrimaryThread).thenReturn(false); + executor.giveReward(user, data, "Reward", null); + } + + verify(daily).giveReward(eq(user), any(RewardOptions.class)); + } + + @Test + public void directSectionUsesRegisteredDirectReward() { + YamlConfiguration data = new YamlConfiguration(); + data.createSection("Direct.Reward"); + DirectlyDefinedReward direct = mock(DirectlyDefinedReward.class); + Reward directReward = mock(Reward.class); + RewardOptions options = new RewardOptions(); + when(handler.getDirectlyDefined("Direct.Reward")).thenReturn(direct); + when(direct.getReward()).thenReturn(directReward); + + try (MockedStatic bukkit = mockStatic(Bukkit.class)) { + bukkit.when(Bukkit::isPrimaryThread).thenReturn(false); + executor.giveReward(user, data, "Direct.Reward", options); + } + + verify(directReward).giveReward(user, options); + } + + @Test + public void subDirectSectionUsesConstructedPrefixNameForLookup() { + YamlConfiguration data = new YamlConfiguration(); + data.createSection("Rewards"); + SubDirectlyDefinedReward sub = mock(SubDirectlyDefinedReward.class); + Reward subReward = mock(Reward.class); + RewardOptions options = new RewardOptions().setPrefix("Parent"); + when(handler.getSubDirectlyDefined("Parent_Rewards")).thenReturn(sub); + when(sub.getReward()).thenReturn(subReward); + + try (MockedStatic bukkit = mockStatic(Bukkit.class)) { + bukkit.when(Bukkit::isPrimaryThread).thenReturn(false); + executor.giveReward(user, data, "Rewards", options); + } + + verify(subReward).giveReward(user, options); + } + + @Test + public void inlineSectionConstructsChecksAndExecutesReward() { + YamlConfiguration data = new YamlConfiguration(); + data.createSection("Inline"); + RewardOptions options = new RewardOptions(); + + try (MockedConstruction rewards = mockConstruction(Reward.class); + MockedStatic bukkit = mockStatic(Bukkit.class)) { + bukkit.when(Bukkit::isPrimaryThread).thenReturn(false); + executor.giveReward(user, data, "Inline", options); + + Reward reward = rewards.constructed().get(0); + verify(reward).checkRewardFile(); + verify(reward).giveReward(user, options); + } + } + + @Test + public void commandStyleRewardExecutesConsoleCommand() { + MiscUtils misc = mock(MiscUtils.class); + RewardOptions options = new RewardOptions().addPlaceholder("player", "Ben"); + + try (MockedStatic miscStatic = mockStatic(MiscUtils.class)) { + miscStatic.when(MiscUtils::getInstance).thenReturn(misc); + executor.giveReward(user, "/say hi", options); + } + + verify(misc).executeConsoleCommands("Ben", "/say hi", options.getPlaceholders()); + } + + @Test + public void mainThreadRewardExecutionHandsOffAsynchronously() { + Reward reward = mock(Reward.class); + RewardOptions options = new RewardOptions(); + BukkitScheduler scheduler = mock(BukkitScheduler.class); + when(plugin.getBukkitScheduler()).thenReturn(scheduler); + ArgumentCaptor task = ArgumentCaptor.forClass(Runnable.class); + + try (MockedStatic bukkit = mockStatic(Bukkit.class)) { + bukkit.when(Bukkit::isPrimaryThread).thenReturn(true); + executor.giveReward(user, reward, options); + } + + verify(scheduler).runTaskAsynchronously(eq(plugin), task.capture()); + verify(reward, never()).giveReward(user, options); + task.getValue().run(); + verify(reward).giveReward(user, options); + } + + @Test + public void asyncRewardExecutionRunsImmediately() { + Reward reward = mock(Reward.class); + RewardOptions options = new RewardOptions(); + + try (MockedStatic bukkit = mockStatic(Bukkit.class)) { + bukkit.when(Bukkit::isPrimaryThread).thenReturn(false); + executor.giveReward(user, reward, options); + } + + verify(reward).giveReward(user, options); + } + + @Test + public void choicesDispatchThroughRewardBuilder() { + Reward mainReward = mock(Reward.class); + RewardFileData config = mock(RewardFileData.class); + ConfigurationSection data = mock(ConfigurationSection.class); + when(mainReward.getConfig()).thenReturn(config); + when(mainReward.getName()).thenReturn("Source"); + when(config.getConfigData()).thenReturn(data); + when(config.getChoicesRewardsPath("A")).thenReturn("Choices.A.Rewards"); + + try (MockedConstruction builders = mockConstruction(RewardBuilder.class, (builder, context) -> { + when(builder.withPrefix(anyString())).thenReturn(builder); + when(builder.withPlaceHolder(anyString(), anyString())).thenReturn(builder); + })) { + executor.giveChoicesReward(mainReward, user, "A"); + + RewardBuilder builder = builders.constructed().get(0); + verify(builder).withPrefix("Source"); + verify(builder).withPlaceHolder("choice", "A"); + verify(builder).send(user); + } + } + + @Test + public void updateRewardConstructsAndChecksInlineReward() { + YamlConfiguration data = new YamlConfiguration(); + data.createSection("Nested"); + RewardOptions options = new RewardOptions().setPrefix("Parent"); + AtomicReference> arguments = new AtomicReference<>(); + + try (MockedConstruction rewards = mockConstruction(Reward.class, + (mock, context) -> arguments.set(context.arguments()))) { + executor.updateReward(data, "Nested", options); + + Reward reward = rewards.constructed().get(0); + assertEquals("Parent_Nested", arguments.get().get(0)); + verify(reward).checkRewardFile(); + } + } +} diff --git a/AdvancedCore/src/test/java/com/bencodez/advancedcore/tests/rewards/RewardRegistryTest.java b/AdvancedCore/src/test/java/com/bencodez/advancedcore/tests/rewards/RewardRegistryTest.java index 8449b84293..7ef09b4d4b 100644 --- a/AdvancedCore/src/test/java/com/bencodez/advancedcore/tests/rewards/RewardRegistryTest.java +++ b/AdvancedCore/src/test/java/com/bencodez/advancedcore/tests/rewards/RewardRegistryTest.java @@ -1,5 +1,6 @@ package com.bencodez.advancedcore.tests.rewards; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertSame; @@ -23,97 +24,114 @@ public class RewardRegistryTest { - private RewardRegistry registry; - - @BeforeEach - public void setUp() { - AdvancedCorePlugin plugin = mock(AdvancedCorePlugin.class); - when(plugin.getLogger()).thenReturn(mock(Logger.class)); - registry = new RewardRegistry(plugin); - } - - @Test - public void directlyDefinedLookupIsCaseInsensitiveAndRejectsDuplicatePaths() { - DirectlyDefinedReward first = mock(DirectlyDefinedReward.class); - DirectlyDefinedReward duplicate = mock(DirectlyDefinedReward.class); - when(first.getPath()).thenReturn("Test.Path"); - when(duplicate.getPath()).thenReturn("test.path"); - - registry.addDirectlyDefined(first); - registry.addDirectlyDefined(duplicate); - - assertSame(first, registry.getDirectlyDefined("TEST.PATH")); - assertTrue(registry.getDirectlyDefinedRewards().size() == 1); - } - - @Test - public void subDirectlyDefinedLookupSupportsFileStyleUnderscores() { - SubDirectlyDefinedReward sub = mock(SubDirectlyDefinedReward.class); - when(sub.getFullPath()).thenReturn("Test_Rewards_Name.Rewards"); - - registry.addSubDirectlyDefined(sub); - - assertSame(sub, registry.getSubDirectlyDefined("Test_Rewards_Name_Rewards")); - assertTrue(registry.hasDirectRewardHandle("Test_Rewards_Name_Rewards")); - } - - @Test - public void loadedRewardLookupNormalizesSpacesAndIgnoresCase() { - Reward reward = mock(Reward.class); - when(reward.getName()).thenReturn("My_Reward"); - registry.getRewards().add(reward); - - assertSame(reward, registry.getReward("my reward")); - } - - @Test - public void directlyDefinedRewardLookupPreservesExistingPathBehavior() { - DirectlyDefinedReward direct = mock(DirectlyDefinedReward.class); - Reward reward = mock(Reward.class); - when(direct.getPath()).thenReturn("Direct.Reward"); - when(direct.getReward()).thenReturn(reward); - registry.addDirectlyDefined(direct); - - assertSame(reward, registry.getReward("Direct_Reward")); - } - - @Test - public void rewardExistIsCaseInsensitiveAndRejectsEmptyNames() { - Reward reward = mock(Reward.class); - when(reward.getName()).thenReturn("DailyReward"); - registry.getRewards().add(reward); - - assertTrue(registry.rewardExist("dailyreward")); - assertFalse(registry.rewardExist("")); - } - - @Test - public void resetRewardsReplacesAndClearsTheLoadedRewardList() { - List original = registry.getRewards(); - original.add(mock(Reward.class)); - - registry.resetRewards(); - - assertNotSame(original, registry.getRewards()); - assertTrue(registry.getRewards().isEmpty()); - } - - @Test - public void updateRewardReplacesMatchingFileAndValidatesReplacement() { - Reward oldReward = mock(Reward.class); - Reward replacement = mock(Reward.class); - File oldFile = mock(File.class); - File replacementFile = mock(File.class); - when(oldReward.getFile()).thenReturn(oldFile); - when(replacement.getFile()).thenReturn(replacementFile); - when(oldFile.getPath()).thenReturn("Rewards/Test.yml"); - when(replacementFile.getPath()).thenReturn("Rewards/Test.yml"); - registry.getRewards().add(oldReward); - - registry.updateReward(replacement); - - verify(replacement).validate(); - assertTrue(registry.getRewards().size() == 1); - assertSame(replacement, registry.getRewards().get(0)); - } + private RewardRegistry registry; + + @BeforeEach + public void setUp() { + AdvancedCorePlugin plugin = mock(AdvancedCorePlugin.class); + when(plugin.getLogger()).thenReturn(mock(Logger.class)); + registry = new RewardRegistry(plugin); + } + + @Test + public void directlyDefinedLookupNormalizesCaseDotsUnderscoresAndDuplicatePaths() { + DirectlyDefinedReward first = mock(DirectlyDefinedReward.class); + DirectlyDefinedReward duplicate = mock(DirectlyDefinedReward.class); + when(first.getPath()).thenReturn("Test.Path"); + when(duplicate.getPath()).thenReturn("test_path"); + + registry.addDirectlyDefined(first); + registry.addDirectlyDefined(duplicate); + + assertSame(first, registry.getDirectlyDefined("TEST.PATH")); + assertSame(first, registry.getDirectlyDefined("test_path")); + assertTrue(registry.hasDirectRewardHandle("TEST_PATH")); + assertEquals(1, registry.getDirectlyDefinedRewards().size()); + } + + @Test + public void subDirectlyDefinedLookupNormalizesSeparatorsAndRejectsDuplicates() { + SubDirectlyDefinedReward first = mock(SubDirectlyDefinedReward.class); + SubDirectlyDefinedReward duplicate = mock(SubDirectlyDefinedReward.class); + when(first.getFullPath()).thenReturn("Test_Rewards_Name.Rewards"); + when(duplicate.getFullPath()).thenReturn("test.rewards.name.rewards"); + + registry.addSubDirectlyDefined(first); + registry.addSubDirectlyDefined(duplicate); + + assertSame(first, registry.getSubDirectlyDefined("Test_Rewards_Name_Rewards")); + assertSame(first, registry.getSubDirectlyDefined("TEST.REWARDS.NAME.REWARDS")); + assertTrue(registry.hasDirectRewardHandle("test_rewards_name_rewards")); + assertEquals(1, registry.getSubDirectlyDefinedRewards().size()); + } + + @Test + public void loadedRewardLookupNormalizesSpacesAndIgnoresCase() { + Reward reward = mock(Reward.class); + when(reward.getName()).thenReturn("My_Reward"); + registry.getRewards().add(reward); + + assertSame(reward, registry.getReward("my reward")); + } + + @Test + public void directlyDefinedRewardLookupUsesSameNormalizedPathRules() { + DirectlyDefinedReward direct = mock(DirectlyDefinedReward.class); + Reward reward = mock(Reward.class); + when(direct.getPath()).thenReturn("Direct.Reward"); + when(direct.getReward()).thenReturn(reward); + registry.addDirectlyDefined(direct); + + assertSame(reward, registry.getReward("Direct_Reward")); + assertSame(reward, registry.getReward("direct.reward")); + assertSame(reward, registry.getReward("DIRECT REWARD")); + } + + @Test + public void rewardExistUsesNormalizedNamesAndRejectsEmptyNames() { + Reward reward = mock(Reward.class); + when(reward.getName()).thenReturn("Daily_Reward"); + registry.getRewards().add(reward); + + assertTrue(registry.rewardExist("daily reward")); + assertTrue(registry.rewardExist("DAILY_REWARD")); + assertFalse(registry.rewardExist("")); + } + + @Test + public void normalizationIsLocaleIndependentAndNullSafe() { + assertEquals("", RewardRegistry.normalizeLookupName(null)); + assertEquals("my_reward", RewardRegistry.normalizeDirectPath("My.Reward")); + assertEquals("my_reward", RewardRegistry.normalizeDirectPath("My Reward")); + } + + @Test + public void resetRewardsReplacesAndClearsTheLoadedRewardList() { + List original = registry.getRewards(); + original.add(mock(Reward.class)); + + registry.resetRewards(); + + assertNotSame(original, registry.getRewards()); + assertTrue(registry.getRewards().isEmpty()); + } + + @Test + public void updateRewardReplacesMatchingFileAndValidatesReplacement() { + Reward oldReward = mock(Reward.class); + Reward replacement = mock(Reward.class); + File oldFile = mock(File.class); + File replacementFile = mock(File.class); + when(oldReward.getFile()).thenReturn(oldFile); + when(replacement.getFile()).thenReturn(replacementFile); + when(oldFile.getPath()).thenReturn("Rewards/Test.yml"); + when(replacementFile.getPath()).thenReturn("Rewards/Test.yml"); + registry.getRewards().add(oldReward); + + registry.updateReward(replacement); + + verify(replacement).validate(); + assertEquals(1, registry.getRewards().size()); + assertSame(replacement, registry.getRewards().get(0)); + } }