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));
+ }
}