From 027b79639bdeb31f95ae84c08019f9d8f8bd9bc5 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sat, 22 Jul 2023 10:14:35 -0700 Subject: [PATCH 01/13] command on level up wip --- .../commands/levelup/LevelUpCommand.java | 10 + .../commands/levelup/LevelUpCommandImpl.java | 69 ++++++ .../levelup/LevelUpCommandManager.java | 43 ++++ .../config/CommandOnLevelUpConfig.java | 17 ++ .../experience/McMMOPlayerLevelUpEvent.java | 1 + .../gmail/nossr50/listeners/SelfListener.java | 18 +- src/main/java/com/gmail/nossr50/mcMMO.java | 22 +- src/main/resources/commandonlevelup.yml | 23 ++ .../nossr50/MMOTestEnvironmentBasic.java | 230 ++++++++++++++++++ .../commands/levelup/LevelUpCommandTest.java | 62 +++++ 10 files changed, 483 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java create mode 100644 src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java create mode 100644 src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java create mode 100644 src/main/java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java create mode 100644 src/main/resources/commandonlevelup.yml create mode 100644 src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java create mode 100644 src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java new file mode 100644 index 0000000000..89cb4e1bb8 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java @@ -0,0 +1,10 @@ +package com.gmail.nossr50.commands.levelup; + +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; + +import java.util.Set; + +public interface LevelUpCommand { + void apply(McMMOPlayer player, PrimarySkillType primarySkillType, Set levelsGained); +} diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java new file mode 100644 index 0000000000..11bdae089a --- /dev/null +++ b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java @@ -0,0 +1,69 @@ +package com.gmail.nossr50.commands.levelup; + +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.LogUtils; +import org.bukkit.Bukkit; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; +import java.util.Set; +import java.util.function.Predicate; + +public class LevelUpCommandImpl implements LevelUpCommand { + private final @NotNull Predicate shouldApply; + private final boolean logInfo; + private final @NotNull String commandStr; + + private final @NotNull Set skills; + + public LevelUpCommandImpl(@NotNull Predicate shouldApply, @NotNull String commandStr, @NotNull Set skills, boolean logInfo) { + this.shouldApply = shouldApply; + this.commandStr = commandStr; + this.skills = skills; + this.logInfo = logInfo; + } + + @Override + public void apply(McMMOPlayer player, PrimarySkillType primarySkillType, Set levelsGained) { + if(!skills.contains(primarySkillType)) { + return; + } + + for (int i : levelsGained) { + if (shouldApply.test(i)) { + // execute command via server console in Bukkit + if(logInfo) { + mcMMO.p.getLogger().info("Executing command: " + commandStr); + } else { + LogUtils.debug(mcMMO.p.getLogger(), "Executing command: " + commandStr); + } + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), commandStr); + } + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + LevelUpCommandImpl that = (LevelUpCommandImpl) o; + return logInfo == that.logInfo && Objects.equals(shouldApply, that.shouldApply) && Objects.equals(commandStr, that.commandStr) && Objects.equals(skills, that.skills); + } + + @Override + public int hashCode() { + return Objects.hash(shouldApply, logInfo, commandStr, skills); + } + + @Override + public String toString() { + return "LevelUpCommandImpl{" + + "shouldApply=" + shouldApply + + ", logInfo=" + logInfo + + ", commandStr='" + commandStr + '\'' + + ", skills=" + skills + + '}'; + } +} diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java new file mode 100644 index 0000000000..212cf90e79 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java @@ -0,0 +1,43 @@ +package com.gmail.nossr50.commands.levelup; + +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.mcMMO; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Set; + +public class LevelUpCommandManager { + private final @NotNull Set commands; + private final @NotNull mcMMO plugin; + + public LevelUpCommandManager(@NotNull mcMMO plugin) { + this.plugin = plugin; + this.commands = new HashSet<>(); + } + + public void registerCommand(@NotNull LevelUpCommand command) { + commands.add(command); + mcMMO.p.getLogger().info("Registered command on level up: " + command); + } + + public void apply(@NotNull McMMOPlayer mmoPlayer, @NotNull PrimarySkillType primarySkillType, Set levelsGained) { + if (!mmoPlayer.getPlayer().isOnline()) { + return; + } + + for (LevelUpCommand command : commands) { + command.apply(mmoPlayer, primarySkillType, levelsGained); + } + } + + public void clear() { + mcMMO.p.getLogger().info("Clearing registered commands on level up"); + commands.clear(); + } + + public boolean isEmpty() { + return commands.isEmpty(); + } +} diff --git a/src/main/java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java b/src/main/java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java new file mode 100644 index 0000000000..6b9498b01a --- /dev/null +++ b/src/main/java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java @@ -0,0 +1,17 @@ +package com.gmail.nossr50.config; + +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +public class CommandOnLevelUpConfig extends BukkitConfig { + + public CommandOnLevelUpConfig(@NotNull File dataFolder) { + super("commandonlevelup", dataFolder); + } + + @Override + protected void loadKeys() { + + } +} diff --git a/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelUpEvent.java b/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelUpEvent.java index 20badcf7cf..2ec305b4d3 100644 --- a/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelUpEvent.java +++ b/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelUpEvent.java @@ -1,6 +1,7 @@ package com.gmail.nossr50.events.experience; import com.gmail.nossr50.datatypes.experience.XPGainReason; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; diff --git a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java index 0fe8eec9fe..0e2d063f66 100644 --- a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java @@ -20,6 +20,11 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + public class SelfListener implements Listener { //Used in task scheduling and other things private final mcMMO plugin; @@ -31,10 +36,10 @@ public SelfListener(mcMMO plugin) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerLevelUp(McMMOPlayerLevelUpEvent event) { - Player player = event.getPlayer(); - PrimarySkillType skill = event.getSkill(); + final Player player = event.getPlayer(); + final PrimarySkillType skill = event.getSkill(); - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); //TODO: Handle proper validation at the event level if(mcMMOPlayer == null || !mcMMOPlayer.getProfile().isLoaded()) @@ -55,6 +60,13 @@ public void onPlayerLevelUp(McMMOPlayerLevelUpEvent event) { if(mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) ScoreboardManager.handleLevelUp(player, skill); } + + final Set levelsAchieved = new LinkedHashSet<>(); + for(int i = 0; i < event.getLevelsGained(); i++) + { + levelsAchieved.add(event.getSkillLevel()); + } + plugin.getLevelUpCommandManager().apply(mcMMOPlayer, skill, levelsAchieved); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index ebf4b6e732..54d8e0d254 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -2,6 +2,7 @@ import com.gmail.nossr50.chat.ChatManager; import com.gmail.nossr50.commands.CommandManager; +import com.gmail.nossr50.commands.levelup.LevelUpCommandManager; import com.gmail.nossr50.config.*; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.config.mods.ArmorConfigManager; @@ -88,6 +89,7 @@ public class mcMMO extends JavaPlugin { private static DatabaseManager databaseManager; private static FormulaManager formulaManager; private static UpgradeManager upgradeManager; + private static LevelUpCommandManager levelUpCommandManager; private static MaterialMapStore materialMapStore; private static PlayerLevelUtils playerLevelUtils; private static SmeltingTracker smeltingTracker; @@ -137,15 +139,8 @@ public class mcMMO extends JavaPlugin { private GeneralConfig generalConfig; private AdvancedConfig advancedConfig; -// private RepairConfig repairConfig; -// private SalvageConfig salvageConfig; -// private PersistentDataConfig persistentDataConfig; -// private ChatConfig chatConfig; -// private CoreSkillsConfig coreSkillsConfig; -// private RankConfig rankConfig; -// private TreasureConfig treasureConfig; -// private FishingTreasureConfig fishingTreasureConfig; -// private SoundConfig soundConfig; + + private CommandOnLevelUpConfig commandOnLevelUpConfig; public mcMMO() { p = this; @@ -173,6 +168,7 @@ public void onEnable() { //Init configs advancedConfig = new AdvancedConfig(getDataFolder()); + commandOnLevelUpConfig = new CommandOnLevelUpConfig(getDataFolder()); //Store this value so other plugins can check it isRetroModeEnabled = generalConfig.getIsRetroMode(); @@ -770,4 +766,12 @@ public long getPurgeTime() { public @NotNull AdvancedConfig getAdvancedConfig() { return advancedConfig; } + + public @NotNull CommandOnLevelUpConfig getCommandOnLevelUpConfig() { + return commandOnLevelUpConfig; + } + + public @NotNull LevelUpCommandManager getLevelUpCommandManager() { + return levelUpCommandManager; + } } diff --git a/src/main/resources/commandonlevelup.yml b/src/main/resources/commandonlevelup.yml new file mode 100644 index 0000000000..cfb95699b6 --- /dev/null +++ b/src/main/resources/commandonlevelup.yml @@ -0,0 +1,23 @@ +level_up_commands: + unique_id_here: + enabled: false + condition: + skills: + - 'Swords' + - 'Axes' + levels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + commands: + - "say %player% reached level %level%!" + - "say Isn't that nice?" + run_command_as: 'CONSOLE' + log_level: 'INFO' + other_unique_id_here: + enabled: false + condition: + complex_condition: + source: 'player.getLevel() % 2 == 0' + commands: + - "say %player% reached an even level!" + - "say Isn't that fun?" + run_command_as: 'CONSOLE' + log_level: 'DEBUG' diff --git a/src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java b/src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java new file mode 100644 index 0000000000..f0b061924b --- /dev/null +++ b/src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java @@ -0,0 +1,230 @@ +package com.gmail.nossr50; + +import com.gmail.nossr50.commands.levelup.LevelUpCommandManager; +import com.gmail.nossr50.config.*; +import com.gmail.nossr50.config.experience.ExperienceConfig; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.datatypes.player.PlayerProfile; +import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.listeners.SelfListener; +import com.gmail.nossr50.util.*; +import com.gmail.nossr50.util.blockmeta.ChunkManager; +import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.skills.RankUtils; +import com.gmail.nossr50.util.skills.SkillTools; +import org.bukkit.Bukkit; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.plugin.PluginManager; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import java.util.UUID; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public abstract class MMOTestEnvironmentBasic { + private final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(MMOTestEnvironmentBasic.class.getName()); + protected MockedStatic mockedMcMMO; + protected MockedStatic mockedBukkit; + protected MockedStatic mockedChatConfig; + protected MockedStatic experienceConfig; + protected MockedStatic mockedPermissions; + protected MockedStatic mockedRankUtils; + protected MockedStatic mockedUserManager; + protected MockedStatic mockedMisc; + protected MockedStatic mockedSkillTools; + protected MockedStatic mockedEventUtils; + protected SelfListener selfListener; + protected TransientEntityTracker transientEntityTracker; + protected AdvancedConfig advancedConfig; + protected CommandOnLevelUpConfig commandOnLevelUpConfig; + protected LevelUpCommandManager levelUpCommandManager; + protected GeneralConfig generalConfig; + protected RankConfig rankConfig; + protected SkillTools skillTools; + protected Server server; + protected PluginManager pluginManager; + protected World world; + + /* Mocks */ + protected Player player; + + protected UUID playerUUID = UUID.randomUUID(); + protected ItemStack itemInMainHand; + + protected PlayerInventory playerInventory; + protected PlayerProfile playerProfile; + protected McMMOPlayer mmoPlayer; + protected String playerName = "testPlayer"; + + protected ChunkManager chunkManager; + + protected ConsoleCommandSender consoleCommandSender; + + protected void mockBaseEnvironment() { + mockedMcMMO = Mockito.mockStatic(mcMMO.class); + mcMMO.p = mock(mcMMO.class); + when(mcMMO.p.getLogger()).thenReturn(logger); + + // place store + chunkManager = mock(ChunkManager.class); + when(mcMMO.getPlaceStore()).thenReturn(chunkManager); + + // shut off mod manager for woodcutting + when(mcMMO.getModManager()).thenReturn(mock(ModManager.class)); + when(mcMMO.getModManager().isCustomLog(any())).thenReturn(false); + + // chat config + mockedChatConfig = Mockito.mockStatic(ChatConfig.class); + when(ChatConfig.getInstance()).thenReturn(mock(ChatConfig.class)); + + // general config + mockGeneralConfig(); + + // rank config + mockRankConfig(); + + // wire advanced config + mockAdvancedConfig(); + + // wire command level up config + mockLevelUpCommand(); + + // wire experience config + mockExperienceConfig(); + + // wire skill tools + this.skillTools = new SkillTools(mcMMO.p); + when(mcMMO.p.getSkillTools()).thenReturn(skillTools); + + this.transientEntityTracker = new TransientEntityTracker(); + when(mcMMO.getTransientEntityTracker()).thenReturn(transientEntityTracker); + + mockPermissions(); + + mockedRankUtils = Mockito.mockStatic(RankUtils.class); + + // wire server + this.server = mock(Server.class); + when(mcMMO.p.getServer()).thenReturn(server); + + // wire plugin manager + this.pluginManager = mock(PluginManager.class); + when(server.getPluginManager()).thenReturn(pluginManager); + + // wire world + this.world = mock(World.class); + + // wire Misc + this.mockedMisc = Mockito.mockStatic(Misc.class); + // Mockito.when(Misc.getBlockCenter(any())).thenReturn(new Location(world, 0, 0, 0)); + + // setup player and player related mocks after everything else + this.player = mock(Player.class); + when(player.getUniqueId()).thenReturn(playerUUID); + + // wire inventory + this.playerInventory = mock(PlayerInventory.class); + when(player.getInventory()).thenReturn(playerInventory); + + // PlayerProfile and McMMOPlayer are partially mocked + playerProfile = Mockito.spy(new PlayerProfile("testPlayer", player.getUniqueId(), 0)); + when(playerProfile.isLoaded()).thenReturn(true); + mmoPlayer = Mockito.spy(new McMMOPlayer(player, playerProfile)); + + // wire user manager + this.mockedUserManager = Mockito.mockStatic(UserManager.class); + when(UserManager.getPlayer(player)).thenReturn(mmoPlayer); + + // Self listener + selfListener = Mockito.spy(new SelfListener(mcMMO.p)); + + // Player online status + when(player.isOnline()).thenReturn(true); + + // Console command sender + consoleCommandSender = mock(ConsoleCommandSender.class); + when(consoleCommandSender.getName()).thenReturn("CONSOLE"); + mockedBukkit = Mockito.mockStatic(Bukkit.class); + when(Bukkit.getConsoleSender()).thenReturn(consoleCommandSender); + } + + private void mockPermissions() { + mockedPermissions = Mockito.mockStatic(Permissions.class); + when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); + // Mockito.when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn(true); + when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); + // Mockito.when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn(true); + } + + private void mockRankConfig() { + rankConfig = mock(RankConfig.class); + } + + private void mockAdvancedConfig() { + this.advancedConfig = mock(AdvancedConfig.class); + when(mcMMO.p.getAdvancedConfig()).thenReturn(advancedConfig); + } + + private void mockLevelUpCommand() { + this.commandOnLevelUpConfig = mock(CommandOnLevelUpConfig.class); + when(mcMMO.p.getCommandOnLevelUpConfig()).thenReturn(commandOnLevelUpConfig); + + this.levelUpCommandManager = Mockito.spy(new LevelUpCommandManager(mcMMO.p)); + when(mcMMO.p.getLevelUpCommandManager()).thenReturn(levelUpCommandManager); + } + + private void mockGeneralConfig() { + generalConfig = mock(GeneralConfig.class); + when(generalConfig.getLocale()).thenReturn("en_US"); + when(mcMMO.p.getGeneralConfig()).thenReturn(generalConfig); + } + + private void mockExperienceConfig() { + experienceConfig = Mockito.mockStatic(ExperienceConfig.class); + + when(ExperienceConfig.getInstance()).thenReturn(mock(ExperienceConfig.class)); + + // Combat + when(ExperienceConfig.getInstance().getCombatXP(EntityType.COW)).thenReturn(1D); + } + + protected void cleanupBaseEnvironment() { + // Clean up resources here if needed. + if (mockedMcMMO != null) { + mockedMcMMO.close(); + } + if (mockedBukkit != null) { + mockedBukkit.close(); + } + if (experienceConfig != null) { + experienceConfig.close(); + } + if (mockedChatConfig != null) { + mockedChatConfig.close(); + } + if (mockedPermissions != null) { + mockedPermissions.close(); + } + if (mockedRankUtils != null) { + mockedRankUtils.close(); + } + if (mockedUserManager != null) { + mockedUserManager.close(); + } + if (mockedMisc != null) { + mockedMisc.close(); + } + if (mockedEventUtils != null) { + mockedEventUtils.close(); + } + } +} diff --git a/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java b/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java new file mode 100644 index 0000000000..66b872183f --- /dev/null +++ b/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java @@ -0,0 +1,62 @@ +package com.gmail.nossr50.commands.levelup; + +import com.gmail.nossr50.MMOTestEnvironmentBasic; +import com.gmail.nossr50.datatypes.experience.XPGainReason; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.datatypes.player.PlayerProfile; +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.events.experience.McMMOPlayerLevelUpEvent; +import com.gmail.nossr50.listeners.SelfListener; +import com.gmail.nossr50.mcMMO; +import org.bukkit.entity.Player; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import java.util.Set; +import java.util.UUID; +import java.util.function.Predicate; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +class LevelUpCommandTest extends MMOTestEnvironmentBasic { + + @BeforeEach + void setUp() { + mockBaseEnvironment(); + } + + @AfterEach + void tearDown() { + cleanupBaseEnvironment(); + } + + @Test + void levelInMiningShouldRunCommand() { + // validate command manager has zero registered commands + assert mcMMO.p.getLevelUpCommandManager().isEmpty(); + final PrimarySkillType skillType = PrimarySkillType.MINING; + final Predicate predicate = (i) -> true; + final LevelUpCommand levelUpCommand = spy(new LevelUpCommandImpl( + predicate, + "say hello", + Set.of(skillType), + true)); + mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); + + // GIVEN level up command that should always execute for Mining is registered with command manager + + int levelsGained = 5; + // WHEN player gains 5 levels in mining + McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(player, PrimarySkillType.MINING, levelsGained, XPGainReason.PVE); + selfListener.onPlayerLevelUp(event); + + // THEN the command should be run + // check the mockito spy for level up command manager for executing the command + Mockito.verify(levelUpCommandManager).apply(any(), any(), any()); + Mockito.verify(levelUpCommand).apply(any(), any(), any()); + } +} \ No newline at end of file From eb8c5bf0e9e0927d8991c24dbf89ea5ad2a7fc1c Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sat, 22 Jul 2023 10:34:27 -0700 Subject: [PATCH 02/13] more unit tests --- .../commands/levelup/LevelUpCommand.java | 17 ++++- .../commands/levelup/LevelUpCommandImpl.java | 8 ++- .../levelup/LevelUpCommandManager.java | 2 +- .../gmail/nossr50/listeners/SelfListener.java | 4 +- .../commands/levelup/LevelUpCommandTest.java | 70 +++++++++++++++---- 5 files changed, 82 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java index 89cb4e1bb8..e8ca656bd4 100644 --- a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java @@ -5,6 +5,21 @@ import java.util.Set; +/** + * Represents a command to be executed on a level up + */ public interface LevelUpCommand { - void apply(McMMOPlayer player, PrimarySkillType primarySkillType, Set levelsGained); + /** + * Process the command + * + * @param player the player + * @param primarySkillType the skill type + * @param levelsGained the levels gained + */ + void process(McMMOPlayer player, PrimarySkillType primarySkillType, Set levelsGained); + + /** + * Execute the command + */ + void executeCommand(); } diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java index 11bdae089a..f0b132a0e0 100644 --- a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java +++ b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java @@ -26,7 +26,7 @@ public LevelUpCommandImpl(@NotNull Predicate shouldApply, @NotNull Stri } @Override - public void apply(McMMOPlayer player, PrimarySkillType primarySkillType, Set levelsGained) { + public void process(McMMOPlayer player, PrimarySkillType primarySkillType, Set levelsGained) { if(!skills.contains(primarySkillType)) { return; } @@ -39,11 +39,15 @@ public void apply(McMMOPlayer player, PrimarySkillType primarySkillType, Set levelsAchieved = new LinkedHashSet<>(); - for(int i = 0; i < event.getLevelsGained(); i++) + for(int i = 1; i <= event.getLevelsGained(); i++) { - levelsAchieved.add(event.getSkillLevel()); + levelsAchieved.add(event.getSkillLevel() + i); } plugin.getLevelUpCommandManager().apply(mcMMOPlayer, skill, levelsAchieved); } diff --git a/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java b/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java index 66b872183f..6430ce4359 100644 --- a/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java +++ b/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java @@ -2,21 +2,15 @@ import com.gmail.nossr50.MMOTestEnvironmentBasic; import com.gmail.nossr50.datatypes.experience.XPGainReason; -import com.gmail.nossr50.datatypes.player.McMMOPlayer; -import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.events.experience.McMMOPlayerLevelUpEvent; -import com.gmail.nossr50.listeners.SelfListener; import com.gmail.nossr50.mcMMO; -import org.bukkit.entity.Player; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; import org.mockito.Mockito; import java.util.Set; -import java.util.UUID; import java.util.function.Predicate; import static org.mockito.ArgumentMatchers.any; @@ -35,8 +29,8 @@ void tearDown() { } @Test - void levelInMiningShouldRunCommand() { - // validate command manager has zero registered commands + void levelInMiningShouldRunCommandFiveTimes() { + // GIVEN level up command for Mining should always execute for Mining level up assert mcMMO.p.getLevelUpCommandManager().isEmpty(); final PrimarySkillType skillType = PrimarySkillType.MINING; final Predicate predicate = (i) -> true; @@ -47,16 +41,66 @@ void levelInMiningShouldRunCommand() { true)); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); - // GIVEN level up command that should always execute for Mining is registered with command manager + int levelsGained = 5; + // WHEN player gains 5 levels in mining + McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(player, PrimarySkillType.MINING, levelsGained, XPGainReason.PVE); + selfListener.onPlayerLevelUp(event); + + // THEN the command should be checked for execution + verify(levelUpCommandManager).apply(any(), any(), any()); + verify(levelUpCommand).process(any(), any(), any()); + // THEN the command should have executed + verify(levelUpCommand, times(levelsGained)).executeCommand(); + } + + @Test + void levelInMiningShouldRunCommandAtLeastOnce() { + // GIVEN level up command for Mining should always execute for Mining level up + assert mcMMO.p.getLevelUpCommandManager().isEmpty(); + final PrimarySkillType skillType = PrimarySkillType.MINING; + final Predicate predicate = (i) -> true; + final LevelUpCommand levelUpCommand = spy(new LevelUpCommandImpl( + predicate, + "say hello", + Set.of(skillType), + true)); + mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); + + int levelsGained = 1; + // WHEN player gains 5 levels in mining + McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(player, PrimarySkillType.MINING, levelsGained, XPGainReason.PVE); + selfListener.onPlayerLevelUp(event); + + // THEN the command should be checked for execution + verify(levelUpCommandManager).apply(any(), any(), any()); + verify(levelUpCommand).process(any(), any(), any()); + // THEN the command should have executed + verify(levelUpCommand).executeCommand(); + } + + @Test + void levelInMiningShouldNotRunCommand() { + // GIVEN level up command for Woodcutting should not execute for Mining level up + assert mcMMO.p.getLevelUpCommandManager().isEmpty(); + final PrimarySkillType skillType = PrimarySkillType.WOODCUTTING; + final Predicate predicate = (i) -> true; + final LevelUpCommand levelUpCommand = spy(new LevelUpCommandImpl( + predicate, + "say hello", + Set.of(skillType), + true)); + mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); + int levelsGained = 5; // WHEN player gains 5 levels in mining McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(player, PrimarySkillType.MINING, levelsGained, XPGainReason.PVE); selfListener.onPlayerLevelUp(event); - // THEN the command should be run - // check the mockito spy for level up command manager for executing the command - Mockito.verify(levelUpCommandManager).apply(any(), any(), any()); - Mockito.verify(levelUpCommand).apply(any(), any(), any()); + // THEN the command should be checked for execution + verify(levelUpCommandManager).apply(any(), any(), any()); + verify(levelUpCommand).process(any(), any(), any()); + // THEN the command should not be run + verify(levelUpCommand, never()).executeCommand(); } } \ No newline at end of file From 8ee282beec37e038581aba9477524f65583783b5 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 30 Jul 2023 16:23:41 -0700 Subject: [PATCH 03/13] Add builder, switch to BiPredicate for impl --- .../commands/levelup/LevelUpCommand.java | 57 +++++++++++++++++++ .../commands/levelup/LevelUpCommandImpl.java | 24 +++----- .../levelup/LevelUpCommandManager.java | 49 +++++++++++++++- .../config/CommandOnLevelUpConfig.java | 9 +++ .../experience/McMMOPlayerLevelUpEvent.java | 1 - .../gmail/nossr50/listeners/SelfListener.java | 2 - .../commands/levelup/LevelUpCommandTest.java | 51 ++++++++++------- .../config/CommandOnLevelUpConfigTest.java | 5 ++ src/test/resources/commandonlevelup.yml | 23 ++++++++ 9 files changed, 177 insertions(+), 44 deletions(-) create mode 100644 src/test/java/com/gmail/nossr50/config/CommandOnLevelUpConfigTest.java create mode 100644 src/test/resources/commandonlevelup.yml diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java index e8ca656bd4..c99d4d05b8 100644 --- a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java @@ -4,6 +4,9 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import java.util.Set; +import java.util.function.BiPredicate; + +import static java.util.Objects.requireNonNull; /** * Represents a command to be executed on a level up @@ -22,4 +25,58 @@ public interface LevelUpCommand { * Execute the command */ void executeCommand(); + + class LevelUpCommandBuilder { + private Set skillFilter = null; + private Set levels = null; + private String commandStr = null; + private BiPredicate predicate = null; + private boolean logInfo; + + public LevelUpCommandBuilder() { + this.logInfo = false; + } + + public LevelUpCommandBuilder withPredicate(BiPredicate predicate) { + this.predicate = predicate; + return this; + } + + public LevelUpCommandBuilder withLogInfo(boolean logInfo) { + this.logInfo = logInfo; + return this; + } + + public LevelUpCommandBuilder commandString(String commandStr) { + this.commandStr = commandStr; + return this; + } + + public LevelUpCommandBuilder withLevels(Set levels) { + this.levels = levels; + return this; + } + + public LevelUpCommandBuilder withSkillFilter(Set skillFilter) { + this.skillFilter = skillFilter; + return this; + } + + public LevelUpCommand build() { + requireNonNull(commandStr, "commandStr is null"); + if (predicate == null) { + requireNonNull(levels, "levels is null"); + + return new LevelUpCommandImpl((skill, level) -> { + if (skillFilter == null) { + return levels.contains(level); + } else { + return skillFilter.contains(skill) && levels.contains(level); + } + }, commandStr, logInfo); + } + + return new LevelUpCommandImpl(predicate, commandStr, logInfo); + } + } } diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java index f0b132a0e0..e48f5a1561 100644 --- a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java +++ b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java @@ -9,30 +9,23 @@ import java.util.Objects; import java.util.Set; -import java.util.function.Predicate; +import java.util.function.BiPredicate; public class LevelUpCommandImpl implements LevelUpCommand { - private final @NotNull Predicate shouldApply; + private final BiPredicate predicate; private final boolean logInfo; private final @NotNull String commandStr; - private final @NotNull Set skills; - - public LevelUpCommandImpl(@NotNull Predicate shouldApply, @NotNull String commandStr, @NotNull Set skills, boolean logInfo) { - this.shouldApply = shouldApply; + public LevelUpCommandImpl(@NotNull BiPredicate predicate, @NotNull String commandStr, boolean logInfo) { this.commandStr = commandStr; - this.skills = skills; + this.predicate = predicate; this.logInfo = logInfo; } @Override public void process(McMMOPlayer player, PrimarySkillType primarySkillType, Set levelsGained) { - if(!skills.contains(primarySkillType)) { - return; - } - for (int i : levelsGained) { - if (shouldApply.test(i)) { + if (predicate.test(primarySkillType, i)) { // execute command via server console in Bukkit if(logInfo) { mcMMO.p.getLogger().info("Executing command: " + commandStr); @@ -53,21 +46,20 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; LevelUpCommandImpl that = (LevelUpCommandImpl) o; - return logInfo == that.logInfo && Objects.equals(shouldApply, that.shouldApply) && Objects.equals(commandStr, that.commandStr) && Objects.equals(skills, that.skills); + return logInfo == that.logInfo && Objects.equals(predicate, that.predicate) && Objects.equals(commandStr, that.commandStr); } @Override public int hashCode() { - return Objects.hash(shouldApply, logInfo, commandStr, skills); + return Objects.hash(predicate, logInfo, commandStr); } @Override public String toString() { return "LevelUpCommandImpl{" + - "shouldApply=" + shouldApply + + "predicate=" + predicate + ", logInfo=" + logInfo + ", commandStr='" + commandStr + '\'' + - ", skills=" + skills + '}'; } } diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java index aaecc3fc35..72a6e9633f 100644 --- a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java +++ b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java @@ -6,8 +6,12 @@ import org.jetbrains.annotations.NotNull; import java.util.HashSet; +import java.util.Objects; import java.util.Set; +/** + * Manages commands to be executed on level up + */ public class LevelUpCommandManager { private final @NotNull Set commands; private final @NotNull mcMMO plugin; @@ -17,11 +21,23 @@ public LevelUpCommandManager(@NotNull mcMMO plugin) { this.commands = new HashSet<>(); } - public void registerCommand(@NotNull LevelUpCommand command) { - commands.add(command); - mcMMO.p.getLogger().info("Registered command on level up: " + command); + /** + * Register a level up command to be executed on level up + * + * @param levelUpCommand the levelUpCommand + */ + public void registerCommand(@NotNull LevelUpCommand levelUpCommand) { + commands.add(levelUpCommand); + mcMMO.p.getLogger().info("Registered levelUpCommand on level up: " + levelUpCommand); } + /** + * Apply the level up commands to the player + * + * @param mmoPlayer the player + * @param primarySkillType the skill type + * @param levelsGained the levels gained + */ public void apply(@NotNull McMMOPlayer mmoPlayer, @NotNull PrimarySkillType primarySkillType, Set levelsGained) { if (!mmoPlayer.getPlayer().isOnline()) { return; @@ -32,12 +48,39 @@ public void apply(@NotNull McMMOPlayer mmoPlayer, @NotNull PrimarySkillType prim } } + /** + * Clear all registered commands + */ public void clear() { mcMMO.p.getLogger().info("Clearing registered commands on level up"); commands.clear(); } + /** + * @return true if there are no registered commands + */ public boolean isEmpty() { return commands.isEmpty(); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + LevelUpCommandManager that = (LevelUpCommandManager) o; + return Objects.equals(commands, that.commands) && Objects.equals(plugin, that.plugin); + } + + @Override + public int hashCode() { + return Objects.hash(commands, plugin); + } + + @Override + public String toString() { + return "LevelUpCommandManager{" + + "commands=" + commands + + ", plugin=" + plugin + + '}'; + } } diff --git a/src/main/java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java b/src/main/java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java index 6b9498b01a..e3c7a9dfad 100644 --- a/src/main/java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java +++ b/src/main/java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java @@ -1,17 +1,26 @@ package com.gmail.nossr50.config; +import com.gmail.nossr50.commands.levelup.LevelUpCommand; +import org.bukkit.configuration.ConfigurationSection; import org.jetbrains.annotations.NotNull; import java.io.File; public class CommandOnLevelUpConfig extends BukkitConfig { + public static final String LEVEL_UP_COMMANDS = "level_up_commands"; + public CommandOnLevelUpConfig(@NotNull File dataFolder) { super("commandonlevelup", dataFolder); } @Override protected void loadKeys() { + final ConfigurationSection configurationSection = config.getConfigurationSection(LEVEL_UP_COMMANDS); + } + private LevelUpCommand buildCommand() { + LevelUpCommand.LevelUpCommandBuilder builder = new LevelUpCommand.LevelUpCommandBuilder(); + return builder.build(); } } diff --git a/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelUpEvent.java b/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelUpEvent.java index 2ec305b4d3..20badcf7cf 100644 --- a/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelUpEvent.java +++ b/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelUpEvent.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.events.experience; import com.gmail.nossr50.datatypes.experience.XPGainReason; -import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; diff --git a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java index 75089bb965..26640a99fa 100644 --- a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java @@ -20,9 +20,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import java.util.HashSet; import java.util.LinkedHashSet; -import java.util.List; import java.util.Set; public class SelfListener implements Listener { diff --git a/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java b/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java index 6430ce4359..da72715ddd 100644 --- a/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java +++ b/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java @@ -11,7 +11,7 @@ import org.mockito.Mockito; import java.util.Set; -import java.util.function.Predicate; +import java.util.function.BiPredicate; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -32,13 +32,9 @@ void tearDown() { void levelInMiningShouldRunCommandFiveTimes() { // GIVEN level up command for Mining should always execute for Mining level up assert mcMMO.p.getLevelUpCommandManager().isEmpty(); - final PrimarySkillType skillType = PrimarySkillType.MINING; - final Predicate predicate = (i) -> true; - final LevelUpCommand levelUpCommand = spy(new LevelUpCommandImpl( - predicate, - "say hello", - Set.of(skillType), - true)); + final String commandStr = "say hello"; + final LevelUpCommand levelUpCommand + = buildLevelUpCommand(commandStr, (skill, ignored) -> skill == PrimarySkillType.MINING); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); int levelsGained = 5; @@ -57,13 +53,9 @@ void levelInMiningShouldRunCommandFiveTimes() { void levelInMiningShouldRunCommandAtLeastOnce() { // GIVEN level up command for Mining should always execute for Mining level up assert mcMMO.p.getLevelUpCommandManager().isEmpty(); - final PrimarySkillType skillType = PrimarySkillType.MINING; - final Predicate predicate = (i) -> true; - final LevelUpCommand levelUpCommand = spy(new LevelUpCommandImpl( - predicate, - "say hello", - Set.of(skillType), - true)); + final String commandStr = "say hello"; + final LevelUpCommand levelUpCommand + = buildLevelUpCommand(commandStr, (skill, ignored) -> skill == PrimarySkillType.MINING); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); int levelsGained = 1; @@ -82,13 +74,9 @@ void levelInMiningShouldRunCommandAtLeastOnce() { void levelInMiningShouldNotRunCommand() { // GIVEN level up command for Woodcutting should not execute for Mining level up assert mcMMO.p.getLevelUpCommandManager().isEmpty(); - final PrimarySkillType skillType = PrimarySkillType.WOODCUTTING; - final Predicate predicate = (i) -> true; - final LevelUpCommand levelUpCommand = spy(new LevelUpCommandImpl( - predicate, - "say hello", - Set.of(skillType), - true)); + final String commandStr = "say hello"; + final LevelUpCommand levelUpCommand + = buildLevelUpCommand(commandStr, (skill, ignored) -> skill == PrimarySkillType.WOODCUTTING); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); @@ -103,4 +91,23 @@ void levelInMiningShouldNotRunCommand() { // THEN the command should not be run verify(levelUpCommand, never()).executeCommand(); } + + private LevelUpCommand buildLevelUpCommand(String commandStr, Set levels, Set skillFilter) { + LevelUpCommand.LevelUpCommandBuilder builder = new LevelUpCommand.LevelUpCommandBuilder(); + builder.commandString(commandStr); + builder.withLevels(levels); + if (skillFilter != null) { + builder.withSkillFilter(skillFilter); + } + builder.withLogInfo(true); + return Mockito.spy(builder.build()); + } + + private LevelUpCommand buildLevelUpCommand(String commandStr, BiPredicate predicate) { + LevelUpCommand.LevelUpCommandBuilder builder = new LevelUpCommand.LevelUpCommandBuilder(); + builder.commandString(commandStr); + builder.withPredicate(predicate); + builder.withLogInfo(true); + return Mockito.spy(builder.build()); + } } \ No newline at end of file diff --git a/src/test/java/com/gmail/nossr50/config/CommandOnLevelUpConfigTest.java b/src/test/java/com/gmail/nossr50/config/CommandOnLevelUpConfigTest.java new file mode 100644 index 0000000000..379a2f98f1 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/config/CommandOnLevelUpConfigTest.java @@ -0,0 +1,5 @@ +package com.gmail.nossr50.config; + +class CommandOnLevelUpConfigTest { + +} \ No newline at end of file diff --git a/src/test/resources/commandonlevelup.yml b/src/test/resources/commandonlevelup.yml new file mode 100644 index 0000000000..cfb95699b6 --- /dev/null +++ b/src/test/resources/commandonlevelup.yml @@ -0,0 +1,23 @@ +level_up_commands: + unique_id_here: + enabled: false + condition: + skills: + - 'Swords' + - 'Axes' + levels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + commands: + - "say %player% reached level %level%!" + - "say Isn't that nice?" + run_command_as: 'CONSOLE' + log_level: 'INFO' + other_unique_id_here: + enabled: false + condition: + complex_condition: + source: 'player.getLevel() % 2 == 0' + commands: + - "say %player% reached an even level!" + - "say Isn't that fun?" + run_command_as: 'CONSOLE' + log_level: 'DEBUG' From 656beb34ef0652ad5eb00f0f092f4185f717a92e Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 30 Jul 2023 16:25:58 -0700 Subject: [PATCH 04/13] Builder style --- .../nossr50/commands/levelup/LevelUpCommandTest.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java b/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java index da72715ddd..9dccaee264 100644 --- a/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java +++ b/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java @@ -94,8 +94,9 @@ void levelInMiningShouldNotRunCommand() { private LevelUpCommand buildLevelUpCommand(String commandStr, Set levels, Set skillFilter) { LevelUpCommand.LevelUpCommandBuilder builder = new LevelUpCommand.LevelUpCommandBuilder(); - builder.commandString(commandStr); - builder.withLevels(levels); + builder.commandString(commandStr) + .withLevels(levels) + .withLogInfo(true); if (skillFilter != null) { builder.withSkillFilter(skillFilter); } @@ -105,9 +106,9 @@ private LevelUpCommand buildLevelUpCommand(String commandStr, Set level private LevelUpCommand buildLevelUpCommand(String commandStr, BiPredicate predicate) { LevelUpCommand.LevelUpCommandBuilder builder = new LevelUpCommand.LevelUpCommandBuilder(); - builder.commandString(commandStr); - builder.withPredicate(predicate); - builder.withLogInfo(true); + builder.commandString(commandStr) + .withPredicate(predicate) + .withLogInfo(true); return Mockito.spy(builder.build()); } } \ No newline at end of file From 753834e1fc8169439ab760e8049555298ca1154c Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 20 Aug 2023 13:42:55 -0700 Subject: [PATCH 05/13] Read and register commands from config --- .../commands/levelup/LevelUpCommand.java | 38 ++++-- .../commands/levelup/LevelUpCommandImpl.java | 21 +++- .../config/CommandOnLevelUpConfig.java | 111 +++++++++++++++++- .../datatypes/skills/PrimarySkillType.java | 13 +- .../gmail/nossr50/util/skills/SkillTools.java | 30 ++++- 5 files changed, 193 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java index c99d4d05b8..a91834f7ff 100644 --- a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java @@ -2,7 +2,10 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import org.jetbrains.annotations.NotNull; +import java.util.Collection; +import java.util.LinkedList; import java.util.Set; import java.util.function.BiPredicate; @@ -29,7 +32,7 @@ public interface LevelUpCommand { class LevelUpCommandBuilder { private Set skillFilter = null; private Set levels = null; - private String commandStr = null; + private LinkedList commands = null; private BiPredicate predicate = null; private boolean logInfo; @@ -47,23 +50,40 @@ public LevelUpCommandBuilder withLogInfo(boolean logInfo) { return this; } - public LevelUpCommandBuilder commandString(String commandStr) { - this.commandStr = commandStr; + public LevelUpCommandBuilder command(@NotNull String command) { + this.commands = new LinkedList<>(); + this.commands.add(command); return this; } - public LevelUpCommandBuilder withLevels(Set levels) { - this.levels = levels; + public LevelUpCommandBuilder commands(@NotNull Collection command) { + this.commands = new LinkedList<>(command); return this; } - public LevelUpCommandBuilder withSkillFilter(Set skillFilter) { + public LevelUpCommandBuilder withLevels(@NotNull Collection levels) { + requireNonNull(levels, "levels is null!"); + this.levels = Set.copyOf(levels); + return this; + } + + public LevelUpCommandBuilder withSkillFilter(@NotNull Set skillFilter) { + requireNonNull(skillFilter, "skillFilter is null!"); + if (skillFilter.isEmpty()) { + throw new IllegalArgumentException("skillFilter is empty"); + } this.skillFilter = skillFilter; return this; } + public LevelUpCommandBuilder withSkillFilter(@NotNull PrimarySkillType skill) { + requireNonNull(skill, "skill is null!"); + this.skillFilter = Set.of(skill); + return this; + } + public LevelUpCommand build() { - requireNonNull(commandStr, "commandStr is null"); + requireNonNull(commands, "commandStr is null"); if (predicate == null) { requireNonNull(levels, "levels is null"); @@ -73,10 +93,10 @@ public LevelUpCommand build() { } else { return skillFilter.contains(skill) && levels.contains(level); } - }, commandStr, logInfo); + }, commands, logInfo); } - return new LevelUpCommandImpl(predicate, commandStr, logInfo); + return new LevelUpCommandImpl(predicate, commands, logInfo); } } } diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java index e48f5a1561..2d2aad5598 100644 --- a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java +++ b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java @@ -7,6 +7,8 @@ import org.bukkit.Bukkit; import org.jetbrains.annotations.NotNull; +import java.util.Collection; +import java.util.LinkedList; import java.util.Objects; import java.util.Set; import java.util.function.BiPredicate; @@ -14,11 +16,18 @@ public class LevelUpCommandImpl implements LevelUpCommand { private final BiPredicate predicate; private final boolean logInfo; - private final @NotNull String commandStr; + private final @NotNull LinkedList commandStr; public LevelUpCommandImpl(@NotNull BiPredicate predicate, @NotNull String commandStr, boolean logInfo) { - this.commandStr = commandStr; this.predicate = predicate; + this.commandStr = new LinkedList<>(); + this.commandStr.add(commandStr); + this.logInfo = logInfo; + } + + public LevelUpCommandImpl(@NotNull BiPredicate predicate, @NotNull LinkedList commandStr, boolean logInfo) { + this.predicate = predicate; + this.commandStr = commandStr; this.logInfo = logInfo; } @@ -38,7 +47,13 @@ public void process(McMMOPlayer player, PrimarySkillType primarySkillType, Set(Set.of(skillName)))); + } + } + } else { + ConfigurationSection skillsSection = condition.getConfigurationSection(SKILLS_SECTION); + if (skillsSection != null) { + Set skillNames = skillsSection.getKeys(false); + Set skillsFromFilter = getSkillsFromFilter(skillNames); + if (skillsFromFilter.isEmpty()) { + LogUtils.debug(mcMMO.p.getLogger(), "No valid skills found for command named " + + commandSection.getName() + "for condition section named " + skillsSection.getName()); + } else { + builder.withSkillFilter(skillsFromFilter); + } + } + } + } + + // for now only simple condition is supported + if (!condition.contains(LEVELS_SECTION)) { + mcMMO.p.getLogger().severe("No condition.levels section found for command named " + commandSection.getName()); + return null; + } + + Collection levels = condition.getIntegerList(LEVELS_SECTION); + if (levels.isEmpty()) { + mcMMO.p.getLogger().severe("No valid levels found in condition.levels for command named " + + commandSection.getName()); + return null; + } + builder.withLevels(levels); + + // commands + if (commandSection.isString(COMMANDS)) { + String command = commandSection.getString(COMMANDS); + if (command != null) { + builder.command(command); + } + } else { + List commands = commandSection.getStringList(COMMANDS); + if (commands.isEmpty()) { + mcMMO.p.getLogger().severe("No commands defined for command named " + + commandSection.getName()); + return null; + } else { + builder.commands(commands); + } + } + return builder.build(); } + + private Set getSkillsFromFilter(Set skillFilter) { + return mcMMO.p.getSkillTools().matchSkills(skillFilter); + } } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java index 5b513c2805..9fa39bd5d6 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java @@ -9,7 +9,9 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.Set; public enum PrimarySkillType { ACROBATICS, @@ -140,7 +142,6 @@ public double getXpModifier() { /** * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead - * @return the max level of this skill * @see SkillTools#matchSkill(java.lang.String) * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead */ @@ -149,6 +150,16 @@ public static PrimarySkillType getSkill(String skillName) { return mcMMO.p.getSkillTools().matchSkill(skillName); } + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @see SkillTools#matchSkill(java.lang.String) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public static Set getSkills(Collection skillNames) { + return mcMMO.p.getSkillTools().matchSkills(skillNames); + } + /** * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead * @return the max level of this skill diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java index 416926fe46..240bd68619 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java @@ -17,6 +17,7 @@ import org.bukkit.entity.Player; import org.bukkit.entity.Tameable; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.VisibleForTesting; import java.util.*; @@ -236,14 +237,15 @@ public SkillTools(@NotNull mcMMO pluginRef) { /** * Matches a string of a skill to a skill - * This is NOT case sensitive + * This is NOT case-sensitive * First it checks the locale file and tries to match by the localized name of the skill * Then if nothing is found it checks against the hard coded "name" of the skill, which is just its name in English * * @param skillName target skill name * @return the matching PrimarySkillType if one is found, otherwise null */ - public PrimarySkillType matchSkill(String skillName) { + @Nullable + public PrimarySkillType matchSkill(@NotNull String skillName) { if (!pluginRef.getGeneralConfig().getLocale().equalsIgnoreCase("en_US")) { for (PrimarySkillType type : PrimarySkillType.values()) { if (skillName.equalsIgnoreCase(LocaleLoader.getString(StringUtils.getCapitalized(type.name()) + ".SkillName"))) { @@ -258,11 +260,29 @@ public PrimarySkillType matchSkill(String skillName) { } } - if (!skillName.equalsIgnoreCase("all")) { - pluginRef.getLogger().warning("Invalid mcMMO skill (" + skillName + ")"); //TODO: Localize + return null; + } + + /** + * Matches an array of strings of skills to skills + * This is NOT case-sensitive + * First it checks the locale file and tries to match by the localized name of the skill + * Then if nothing is found it checks against the hard coded "name" of the skill, which is just its name in English + * + * @param skills target skill names + * @return the matching PrimarySkillType if one is found, otherwise null + */ + @NotNull + public Set matchSkills(@NotNull Collection skills) { + Set matchingSkills = new HashSet<>(); + for (String skillName : skills) { + PrimarySkillType primarySkillType = matchSkill(skillName); + if(primarySkillType != null) { + matchingSkills.add(primarySkillType); + } } - return null; + return matchingSkills; } /** From 02cacb9e946411431502e4eb50f6a93fb6811d74 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 20 Aug 2023 14:28:53 -0700 Subject: [PATCH 06/13] Add some string injection for commands --- .../commands/levelup/LevelUpCommand.java | 5 +- .../commands/levelup/LevelUpCommandImpl.java | 54 +++++++++++++------ .../config/CommandOnLevelUpConfig.java | 4 +- src/main/java/com/gmail/nossr50/mcMMO.java | 1 + ...mmandonlevelup.yml => levelupcommands.yml} | 9 ++-- .../commands/levelup/LevelUpCommandTest.java | 11 ++-- 6 files changed, 55 insertions(+), 29 deletions(-) rename src/main/resources/{commandonlevelup.yml => levelupcommands.yml} (73%) diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java index a91834f7ff..02876bfa18 100644 --- a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java @@ -26,8 +26,11 @@ public interface LevelUpCommand { /** * Execute the command + * @param player the player + * @param primarySkillType the skill + * @param level the level of the skill */ - void executeCommand(); + void executeCommand(McMMOPlayer player, PrimarySkillType primarySkillType, int level); class LevelUpCommandBuilder { private Set skillFilter = null; diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java index 2d2aad5598..935abed0a8 100644 --- a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java +++ b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java @@ -7,7 +7,6 @@ import org.bukkit.Bukkit; import org.jetbrains.annotations.NotNull; -import java.util.Collection; import java.util.LinkedList; import java.util.Objects; import java.util.Set; @@ -16,18 +15,18 @@ public class LevelUpCommandImpl implements LevelUpCommand { private final BiPredicate predicate; private final boolean logInfo; - private final @NotNull LinkedList commandStr; + private final @NotNull LinkedList commands; - public LevelUpCommandImpl(@NotNull BiPredicate predicate, @NotNull String commandStr, boolean logInfo) { + public LevelUpCommandImpl(@NotNull BiPredicate predicate, @NotNull String command, boolean logInfo) { this.predicate = predicate; - this.commandStr = new LinkedList<>(); - this.commandStr.add(commandStr); + this.commands = new LinkedList<>(); + this.commands.add(command); this.logInfo = logInfo; } - public LevelUpCommandImpl(@NotNull BiPredicate predicate, @NotNull LinkedList commandStr, boolean logInfo) { + public LevelUpCommandImpl(@NotNull BiPredicate predicate, @NotNull LinkedList commands, boolean logInfo) { this.predicate = predicate; - this.commandStr = commandStr; + this.commands = commands; this.logInfo = logInfo; } @@ -37,36 +36,57 @@ public void process(McMMOPlayer player, PrimarySkillType primarySkillType, Set levels, Set skillFilter) { LevelUpCommand.LevelUpCommandBuilder builder = new LevelUpCommand.LevelUpCommandBuilder(); - builder.commandString(commandStr) + builder.command(commandStr) .withLevels(levels) .withLogInfo(true); if (skillFilter != null) { @@ -106,7 +107,7 @@ private LevelUpCommand buildLevelUpCommand(String commandStr, Set level private LevelUpCommand buildLevelUpCommand(String commandStr, BiPredicate predicate) { LevelUpCommand.LevelUpCommandBuilder builder = new LevelUpCommand.LevelUpCommandBuilder(); - builder.commandString(commandStr) + builder.command(commandStr) .withPredicate(predicate) .withLogInfo(true); return Mockito.spy(builder.build()); From c1a4cc2c97f50285e1ebc284ab6b65b15e146e7b Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 20 Aug 2023 14:56:13 -0700 Subject: [PATCH 07/13] Add power_level_milestones entry to default config --- src/main/resources/levelupcommands.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/resources/levelupcommands.yml b/src/main/resources/levelupcommands.yml index 9acbe3c2e5..eeb390013a 100644 --- a/src/main/resources/levelupcommands.yml +++ b/src/main/resources/levelupcommands.yml @@ -20,3 +20,13 @@ level_up_commands: - "say Isn't that fun?" run_command_as: 'CONSOLE' log_level: 'DEBUG' + power_level_milestones: + enabled: true + condition: + power_level: true + levels: [ 10, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 2000, 3000, 4000, 5000, 10000, 20000 ] + commands: + - "say %player% has reached a power level milestone!" + - "say %player% is now at power level %level%!" + run_command_as: 'CONSOLE' + log_level: 'DEBUG' From 2d8bdbded8ef300dec158ad6c332e1f18a8bcbba Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 27 Aug 2023 14:39:59 -0700 Subject: [PATCH 08/13] More unit tests --- .../nossr50/MMOTestEnvironmentBasic.java | 25 +++- .../commands/levelup/LevelUpCommandTest.java | 116 +++++++++++++----- 2 files changed, 106 insertions(+), 35 deletions(-) diff --git a/src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java b/src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java index f0b061924b..831b20f175 100644 --- a/src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java +++ b/src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java @@ -6,6 +6,7 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.events.experience.McMMOPlayerLevelUpEvent; import com.gmail.nossr50.listeners.SelfListener; import com.gmail.nossr50.util.*; import com.gmail.nossr50.util.blockmeta.ChunkManager; @@ -21,6 +22,8 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.plugin.PluginManager; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.mockito.MockedStatic; import org.mockito.Mockito; @@ -50,7 +53,7 @@ public abstract class MMOTestEnvironmentBasic { protected GeneralConfig generalConfig; protected RankConfig rankConfig; protected SkillTools skillTools; - protected Server server; + protected Server mockedServer; protected PluginManager pluginManager; protected World world; @@ -69,6 +72,16 @@ public abstract class MMOTestEnvironmentBasic { protected ConsoleCommandSender consoleCommandSender; + @BeforeEach + void setUp() { + mockBaseEnvironment(); + } + + @AfterEach + void tearDown() { + cleanupBaseEnvironment(); + } + protected void mockBaseEnvironment() { mockedMcMMO = Mockito.mockStatic(mcMMO.class); mcMMO.p = mock(mcMMO.class); @@ -113,12 +126,16 @@ protected void mockBaseEnvironment() { mockedRankUtils = Mockito.mockStatic(RankUtils.class); // wire server - this.server = mock(Server.class); - when(mcMMO.p.getServer()).thenReturn(server); + this.mockedServer = mock(Server.class); + when(mcMMO.p.getServer()).thenReturn(mockedServer); // wire plugin manager this.pluginManager = mock(PluginManager.class); - when(server.getPluginManager()).thenReturn(pluginManager); + when(mockedServer.getPluginManager()).thenReturn(pluginManager); + Mockito.doAnswer(invocation -> { + selfListener.onPlayerLevelUp(invocation.getArgument(0)); + return null; + }).when(pluginManager).callEvent(any(McMMOPlayerLevelUpEvent.class)); // wire world this.world = mock(World.class); diff --git a/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java b/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java index 957f19ffb0..cc2dad328b 100644 --- a/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java +++ b/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java @@ -6,41 +6,101 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.events.experience.McMMOPlayerLevelUpEvent; import com.gmail.nossr50.mcMMO; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; +import com.gmail.nossr50.util.EventUtils; +import org.bukkit.Bukkit; import org.junit.jupiter.api.Test; import org.mockito.Mockito; import java.util.Set; import java.util.function.BiPredicate; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; class LevelUpCommandTest extends MMOTestEnvironmentBasic { + private final PrimarySkillType skill = PrimarySkillType.MINING; + private final PrimarySkillType otherSkill = PrimarySkillType.WOODCUTTING; - @BeforeEach - void setUp() { - mockBaseEnvironment(); - } + @Test + void levelUpShouldRunCommandFiveTimes() { + // GIVEN level up command for Mining should always execute for Mining level up + assert mcMMO.p.getLevelUpCommandManager().isEmpty(); + final String commandStr = "say hello"; + final LevelUpCommand levelUpCommand + = buildLevelUpCommand(commandStr, (s, ignored) -> s == skill); + mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); + + // WHEN player gains 5 levels in mining via command + assertEquals(0, mmoPlayer.getSkillLevel(skill)); + int levelsGained = 5; + EventUtils.tryLevelChangeEvent( + player, + skill, + levelsGained, + mmoPlayer.getProfile().getSkillXpLevelRaw(skill), + true, + XPGainReason.COMMAND); - @AfterEach - void tearDown() { - cleanupBaseEnvironment(); + // THEN the command should be checked for execution + verify(levelUpCommandManager).apply(any(), any(), any()); + verify(levelUpCommand).process(any(), any(), any()); + // THEN the command should have executed + verify(levelUpCommand, times(levelsGained)).executeCommand(any(McMMOPlayer.class), any(PrimarySkillType.class), anyInt()); + mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), any()), atLeast(5)); } @Test - void levelInMiningShouldRunCommandFiveTimes() { + void levelUpShouldRunCommandFiveTimesWithPlaceholders() { // GIVEN level up command for Mining should always execute for Mining level up assert mcMMO.p.getLevelUpCommandManager().isEmpty(); - final String commandStr = "say hello"; + String playerName = "Momshroom"; + when (player.getName()).thenReturn(playerName); + assertEquals(player.getName(), playerName); + + final String commandStr = "say hello %player%"; + final String expectedStr = "say hello " + playerName; final LevelUpCommand levelUpCommand - = buildLevelUpCommand(commandStr, (skill, ignored) -> skill == PrimarySkillType.MINING); + = buildLevelUpCommand(commandStr, (s, ignored) -> s == skill); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); + int levelsGained = 5; + // WHEN player gains 5 levels in mining + McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(player, skill, levelsGained, XPGainReason.PVE); + selfListener.onPlayerLevelUp(event); + + // THEN the command should be checked for execution + verify(levelUpCommandManager).apply(any(), any(), any()); + verify(levelUpCommand).process(any(), any(), any()); + // THEN the command should have executed + verify(levelUpCommand, times(levelsGained)).executeCommand(any(McMMOPlayer.class), any(PrimarySkillType.class), anyInt()); + // verify that Bukkit.dispatchCommand got executed at least 5 times with the correct injectedCommand + mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), eq(expectedStr)), atLeast(5)); + } + + @Test + void levelUpShouldRunCommandFiveTimesWithPlaceholdersForLevel() { + // GIVEN level up command for Mining should always execute for Mining level up + assert mcMMO.p.getLevelUpCommandManager().isEmpty(); + String playerName = "Momshroom"; + when (player.getName()).thenReturn(playerName); + assertEquals(player.getName(), playerName); + + final String commandStr = "say hello %player%, you have reached level %level%"; + final String expectedStr1 = "say hello " + playerName + ", you have reached level 1"; + final String expectedStr2 = "say hello " + playerName + ", you have reached level 2"; + final String expectedStr3 = "say hello " + playerName + ", you have reached level 3"; + final String expectedStr4 = "say hello " + playerName + ", you have reached level 4"; + final String expectedStr5 = "say hello " + playerName + ", you have reached level 5"; + + final LevelUpCommand levelUpCommand + = buildLevelUpCommand(commandStr, (s, ignored) -> s == skill); + mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); int levelsGained = 5; + // WHEN player gains 5 levels in mining - McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(player, PrimarySkillType.MINING, levelsGained, XPGainReason.PVE); + McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(player, skill, levelsGained, XPGainReason.PVE); selfListener.onPlayerLevelUp(event); // THEN the command should be checked for execution @@ -48,20 +108,26 @@ void levelInMiningShouldRunCommandFiveTimes() { verify(levelUpCommand).process(any(), any(), any()); // THEN the command should have executed verify(levelUpCommand, times(levelsGained)).executeCommand(any(McMMOPlayer.class), any(PrimarySkillType.class), anyInt()); + // verify that Bukkit.dispatchCommand got executed at least 5 times with the correct injectedCommand + mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), eq(expectedStr1))); + mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), eq(expectedStr2))); + mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), eq(expectedStr3))); + mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), eq(expectedStr4))); + mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), eq(expectedStr5))); } @Test - void levelInMiningShouldRunCommandAtLeastOnce() { + void levelUpShouldRunCommandAtLeastOnce() { // GIVEN level up command for Mining should always execute for Mining level up assert mcMMO.p.getLevelUpCommandManager().isEmpty(); final String commandStr = "say hello"; final LevelUpCommand levelUpCommand - = buildLevelUpCommand(commandStr, (skill, ignored) -> skill == PrimarySkillType.MINING); + = buildLevelUpCommand(commandStr, (s, ignored) -> s == skill); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); int levelsGained = 1; // WHEN player gains 5 levels in mining - McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(player, PrimarySkillType.MINING, levelsGained, XPGainReason.PVE); + McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(player, skill, levelsGained, XPGainReason.PVE); selfListener.onPlayerLevelUp(event); // THEN the command should be checked for execution @@ -72,18 +138,18 @@ void levelInMiningShouldRunCommandAtLeastOnce() { } @Test - void levelInMiningShouldNotRunCommand() { + void levelUpShouldNotRunCommand() { // GIVEN level up command for Woodcutting should not execute for Mining level up assert mcMMO.p.getLevelUpCommandManager().isEmpty(); final String commandStr = "say hello"; final LevelUpCommand levelUpCommand - = buildLevelUpCommand(commandStr, (skill, ignored) -> skill == PrimarySkillType.WOODCUTTING); + = buildLevelUpCommand(commandStr, (s, ignored) -> s == otherSkill); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); int levelsGained = 5; // WHEN player gains 5 levels in mining - McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(player, PrimarySkillType.MINING, levelsGained, XPGainReason.PVE); + McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(player, skill, levelsGained, XPGainReason.PVE); selfListener.onPlayerLevelUp(event); // THEN the command should be checked for execution @@ -93,18 +159,6 @@ void levelInMiningShouldNotRunCommand() { verify(levelUpCommand, never()).executeCommand(any(McMMOPlayer.class), any(PrimarySkillType.class), anyInt()); } - private LevelUpCommand buildLevelUpCommand(String commandStr, Set levels, Set skillFilter) { - LevelUpCommand.LevelUpCommandBuilder builder = new LevelUpCommand.LevelUpCommandBuilder(); - builder.command(commandStr) - .withLevels(levels) - .withLogInfo(true); - if (skillFilter != null) { - builder.withSkillFilter(skillFilter); - } - builder.withLogInfo(true); - return Mockito.spy(builder.build()); - } - private LevelUpCommand buildLevelUpCommand(String commandStr, BiPredicate predicate) { LevelUpCommand.LevelUpCommandBuilder builder = new LevelUpCommand.LevelUpCommandBuilder(); builder.command(commandStr) From edab455581e17c0b86bebeac6a78b68062f2a481 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 27 Aug 2023 16:19:46 -0700 Subject: [PATCH 09/13] Fix bug with levels up commands reporting incorrect level --- .../com/gmail/nossr50/api/ExperienceAPI.java | 4 +- .../experience/ConvertExperienceCommand.java | 2 +- .../config/experience/ExperienceConfig.java | 8 +- .../gmail/nossr50/datatypes/party/Party.java | 2 +- .../nossr50/datatypes/player/McMMOPlayer.java | 2 +- .../datatypes/player/PlayerProfile.java | 2 +- .../gmail/nossr50/listeners/SelfListener.java | 6 +- src/main/java/com/gmail/nossr50/mcMMO.java | 4 +- .../database/FormulaConversionTask.java | 6 +- .../com/gmail/nossr50/util/EventUtils.java | 1 - .../util/experience/FormulaManager.java | 29 +++---- .../util/player/NotificationManager.java | 2 +- .../nossr50/MMOTestEnvironmentBasic.java | 43 +++++++++- .../commands/levelup/LevelUpCommandTest.java | 82 +++++++++++++++++-- 14 files changed, 150 insertions(+), 43 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java index f18cd18ca1..0f1d8eeedc 100644 --- a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java +++ b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java @@ -1123,7 +1123,7 @@ public static void removeXPOffline(UUID uuid, String skillType, int xp) { * @throws InvalidFormulaTypeException if the given formulaType is not valid */ public static int getXpNeededToLevel(int level) { - return mcMMO.getFormulaManager().getXPtoNextLevel(level, ExperienceConfig.getInstance().getFormulaType()); + return mcMMO.p.getFormulaManager().getXPtoNextLevel(level, ExperienceConfig.getInstance().getFormulaType()); } /** @@ -1137,7 +1137,7 @@ public static int getXpNeededToLevel(int level) { * @throws InvalidFormulaTypeException if the given formulaType is not valid */ public static int getXpNeededToLevel(int level, String formulaType) { - return mcMMO.getFormulaManager().getXPtoNextLevel(level, getFormulaType(formulaType)); + return mcMMO.p.getFormulaManager().getXPtoNextLevel(level, getFormulaType(formulaType)); } /** diff --git a/src/main/java/com/gmail/nossr50/commands/experience/ConvertExperienceCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/ConvertExperienceCommand.java index e15063ebff..cf5fce21c3 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/ConvertExperienceCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/ConvertExperienceCommand.java @@ -18,7 +18,7 @@ public class ConvertExperienceCommand implements CommandExecutor { @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { if (args.length == 2) { - FormulaType previousType = mcMMO.getFormulaManager().getPreviousFormulaType(); + FormulaType previousType = mcMMO.p.getFormulaManager().getPreviousFormulaType(); FormulaType newType = FormulaType.getFormulaType(args[1].toUpperCase(Locale.ENGLISH)); if (newType == FormulaType.UNKNOWN) { diff --git a/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java b/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java index 929fdcefe3..cb350ad814 100644 --- a/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java +++ b/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java @@ -199,7 +199,7 @@ public boolean isTreeFellerXPReduced() { /* Curve settings */ public FormulaType getFormulaType() { - return FormulaType.getFormulaType(config.getString("Experience_Formula.Curve")); + return FormulaType.getFormulaType(config.getString("Experience_Formula.Curve", "LINEAR")); } public boolean getCumulativeCurveEnabled() { @@ -208,11 +208,13 @@ public boolean getCumulativeCurveEnabled() { /* Curve values */ public double getMultiplier(FormulaType type) { - return config.getDouble("Experience_Formula." + StringUtils.getCapitalized(type.toString()) + "_Values.multiplier"); + double def = type == FormulaType.LINEAR ? 20D : 0.1D; + return config.getDouble("Experience_Formula." + StringUtils.getCapitalized(type.toString()) + "_Values.multiplier", def); } public int getBase(FormulaType type) { - return config.getInt("Experience_Formula." + StringUtils.getCapitalized(type.toString()) + "_Values.base"); + int def = type == FormulaType.LINEAR ? 1020 : 2000; + return config.getInt("Experience_Formula." + StringUtils.getCapitalized(type.toString()) + "_Values.base", def); } public double getExponent(FormulaType type) { diff --git a/src/main/java/com/gmail/nossr50/datatypes/party/Party.java b/src/main/java/com/gmail/nossr50/datatypes/party/Party.java index ccf1c991ca..af5aa7b748 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/party/Party.java +++ b/src/main/java/com/gmail/nossr50/datatypes/party/Party.java @@ -203,7 +203,7 @@ protected float levelUp() { public int getXpToLevel() { FormulaType formulaType = ExperienceConfig.getInstance().getFormulaType(); - return (mcMMO.getFormulaManager().getXPtoNextLevel(level, formulaType)) * (getOnlineMembers().size() + mcMMO.p.getGeneralConfig().getPartyXpCurveMultiplier()); + return (mcMMO.p.getFormulaManager().getXPtoNextLevel(level, formulaType)) * (getOnlineMembers().size() + mcMMO.p.getGeneralConfig().getPartyXpCurveMultiplier()); } public String getXpToLevelPercentage() { diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index a22dd34913..69245f0806 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -663,7 +663,7 @@ public void applyXpGain(PrimarySkillType primarySkillType, float xp, XPGainReaso } final McMMOPlayerPreXpGainEvent mcMMOPlayerPreXpGainEvent = new McMMOPlayerPreXpGainEvent(player, primarySkillType, xp, xpGainReason); - Bukkit.getPluginManager().callEvent(mcMMOPlayerPreXpGainEvent); + mcMMO.p.getServer().getPluginManager().callEvent(mcMMOPlayerPreXpGainEvent); xp = mcMMOPlayerPreXpGainEvent.getXpGained(); if (SkillTools.isChildSkill(primarySkillType)) { diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java index 976ee3434c..432e96e651 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java @@ -428,7 +428,7 @@ public int getXpToLevel(PrimarySkillType primarySkillType) { int level = (ExperienceConfig.getInstance().getCumulativeCurveEnabled()) ? UserManager.getPlayer(playerName).getPowerLevel() : skills.get(primarySkillType); FormulaType formulaType = ExperienceConfig.getInstance().getFormulaType(); - return mcMMO.getFormulaManager().getXPtoNextLevel(level, formulaType); + return mcMMO.p.getFormulaManager().getXPtoNextLevel(level, formulaType); } private int getChildSkillLevel(PrimarySkillType primarySkillType) { diff --git a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java index 26640a99fa..e72c82194d 100644 --- a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java @@ -60,9 +60,9 @@ public void onPlayerLevelUp(McMMOPlayerLevelUpEvent event) { } final Set levelsAchieved = new LinkedHashSet<>(); - for(int i = 1; i <= event.getLevelsGained(); i++) - { - levelsAchieved.add(event.getSkillLevel() + i); + int startingLevel = event.getSkillLevel() - event.getLevelsGained(); + for (int i = 0; i < event.getLevelsGained(); i++) { + levelsAchieved.add(startingLevel + (i + 1)); } plugin.getLevelUpCommandManager().apply(mcMMOPlayer, skill, levelsAchieved); } diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index d421a68707..04f93e96c0 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -87,7 +87,7 @@ public class mcMMO extends JavaPlugin { private static SalvageableManager salvageableManager; private static ModManager modManager; private static DatabaseManager databaseManager; - private static FormulaManager formulaManager; + private FormulaManager formulaManager; private static UpgradeManager upgradeManager; private static LevelUpCommandManager levelUpCommandManager; private static MaterialMapStore materialMapStore; @@ -428,7 +428,7 @@ public void toggleXpEventEnabled() { xpEventEnabled = !xpEventEnabled; } - public static FormulaManager getFormulaManager() { + public FormulaManager getFormulaManager() { return formulaManager; } diff --git a/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java b/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java index 331c90f921..2fe1d180a6 100644 --- a/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java @@ -52,7 +52,7 @@ public void run() { convertedUsers++; Misc.printProgress(convertedUsers, DatabaseManager.progressInterval, startMillis); } - mcMMO.getFormulaManager().setPreviousFormulaType(formulaType); + mcMMO.p.getFormulaManager().setPreviousFormulaType(formulaType); sender.sendMessage(LocaleLoader.getString("Commands.mcconvert.Experience.Finish", formulaType.toString())); } @@ -63,13 +63,13 @@ private void editValues(PlayerProfile profile) { for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { int oldLevel = profile.getSkillLevel(primarySkillType); int oldXPLevel = profile.getSkillXpLevel(primarySkillType); - int totalOldXP = mcMMO.getFormulaManager().calculateTotalExperience(oldLevel, oldXPLevel); + int totalOldXP = mcMMO.p.getFormulaManager().calculateTotalExperience(oldLevel, oldXPLevel); if (totalOldXP == 0) { continue; } - int[] newExperienceValues = mcMMO.getFormulaManager().calculateNewLevel(primarySkillType, (int) Math.floor(totalOldXP / ExperienceConfig.getInstance().getExpModifier()), formulaType); + int[] newExperienceValues = mcMMO.p.getFormulaManager().calculateNewLevel(primarySkillType, (int) Math.floor(totalOldXP / ExperienceConfig.getInstance().getExpModifier()), formulaType); int newLevel = newExperienceValues[0]; int newXPlevel = newExperienceValues[1]; diff --git a/src/main/java/com/gmail/nossr50/util/EventUtils.java b/src/main/java/com/gmail/nossr50/util/EventUtils.java index 5d8ed9035f..d5aff8b6bb 100644 --- a/src/main/java/com/gmail/nossr50/util/EventUtils.java +++ b/src/main/java/com/gmail/nossr50/util/EventUtils.java @@ -263,7 +263,6 @@ public static boolean tryLevelChangeEvent(@NotNull McMMOPlayer mmoPlayer, Primar if (isLevelUp) { NotificationManager.processLevelUpBroadcasting(mmoPlayer, skill, mmoPlayer.getSkillLevel(skill)); NotificationManager.processPowerLevelUpBroadcasting(mmoPlayer, mmoPlayer.getPowerLevel()); - } } diff --git a/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java b/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java index 6685e816b1..a120f4b9b6 100644 --- a/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java +++ b/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java @@ -6,6 +6,7 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.LogUtils; import org.bukkit.configuration.file.YamlConfiguration; +import org.jetbrains.annotations.VisibleForTesting; import java.io.File; import java.util.HashMap; @@ -25,7 +26,19 @@ public class FormulaManager { public FormulaManager() { /* Setting for Classic Mode (Scales a lot of stuff up by * 10) */ initExperienceNeededMaps(); - loadFormula(); + if (!formulaFile.exists()) { + previousFormula = FormulaType.UNKNOWN; + return; + } + + previousFormula = FormulaType.getFormulaType(YamlConfiguration.loadConfiguration(formulaFile).getString("Previous_Formula", "UNKNOWN")); + } + + @VisibleForTesting + public FormulaManager(FormulaType previousFormulaType) { + /* Setting for Classic Mode (Scales a lot of stuff up by * 10) */ + initExperienceNeededMaps(); + this.previousFormula = previousFormulaType; } /** @@ -122,7 +135,7 @@ public int getXPtoNextLevel(int level, FormulaType formulaType) { */ //TODO: When the heck is Unknown used? - if (formulaType == FormulaType.UNKNOWN) { + if (formulaType == null || formulaType == FormulaType.UNKNOWN) { formulaType = FormulaType.LINEAR; } @@ -209,18 +222,6 @@ private int calculateXPNeeded(int level, FormulaType formulaType) { } } - /** - * Load formula file. - */ - public void loadFormula() { - if (!formulaFile.exists()) { - previousFormula = FormulaType.UNKNOWN; - return; - } - - previousFormula = FormulaType.getFormulaType(YamlConfiguration.loadConfiguration(formulaFile).getString("Previous_Formula", "UNKNOWN")); - } - /** * Save formula file. */ diff --git a/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java b/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java index 5ae7096835..ac81bc679a 100644 --- a/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java +++ b/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java @@ -139,7 +139,7 @@ private static McMMOPlayerNotificationEvent checkNotificationEvent(Player player notificationType, message, destination, mcMMO.p.getAdvancedConfig().doesNotificationSendCopyToChat(notificationType)); //Call event - Bukkit.getServer().getPluginManager().callEvent(customEvent); + mcMMO.p.getServer().getPluginManager().callEvent(customEvent); return customEvent; } diff --git a/src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java b/src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java index 831b20f175..a260b7ad41 100644 --- a/src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java +++ b/src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java @@ -3,13 +3,18 @@ import com.gmail.nossr50.commands.levelup.LevelUpCommandManager; import com.gmail.nossr50.config.*; import com.gmail.nossr50.config.experience.ExperienceConfig; +import com.gmail.nossr50.datatypes.experience.FormulaType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.events.experience.McMMOPlayerLevelUpEvent; +import com.gmail.nossr50.events.experience.McMMOPlayerPreXpGainEvent; import com.gmail.nossr50.listeners.SelfListener; import com.gmail.nossr50.util.*; import com.gmail.nossr50.util.blockmeta.ChunkManager; +import com.gmail.nossr50.util.experience.FormulaManager; +import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillTools; @@ -26,8 +31,10 @@ import org.junit.jupiter.api.BeforeEach; import org.mockito.MockedStatic; import org.mockito.Mockito; +import org.mockito.internal.matchers.Not; import java.util.UUID; +import java.util.function.Function; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; @@ -39,11 +46,11 @@ public abstract class MMOTestEnvironmentBasic { protected MockedStatic mockedBukkit; protected MockedStatic mockedChatConfig; protected MockedStatic experienceConfig; + private MockedStatic mockedNotificationManager; protected MockedStatic mockedPermissions; protected MockedStatic mockedRankUtils; protected MockedStatic mockedUserManager; protected MockedStatic mockedMisc; - protected MockedStatic mockedSkillTools; protected MockedStatic mockedEventUtils; protected SelfListener selfListener; protected TransientEntityTracker transientEntityTracker; @@ -57,6 +64,8 @@ public abstract class MMOTestEnvironmentBasic { protected PluginManager pluginManager; protected World world; + private FormulaManager formulaManager; + /* Mocks */ protected Player player; @@ -87,6 +96,10 @@ protected void mockBaseEnvironment() { mcMMO.p = mock(mcMMO.class); when(mcMMO.p.getLogger()).thenReturn(logger); + // formula manager + formulaManager = new FormulaManager(FormulaType.UNKNOWN); + when(mcMMO.p.getFormulaManager()).thenReturn(formulaManager); + // place store chunkManager = mock(ChunkManager.class); when(mcMMO.getPlaceStore()).thenReturn(chunkManager); @@ -115,7 +128,7 @@ protected void mockBaseEnvironment() { mockExperienceConfig(); // wire skill tools - this.skillTools = new SkillTools(mcMMO.p); + this.skillTools = Mockito.spy(new SkillTools(mcMMO.p)); when(mcMMO.p.getSkillTools()).thenReturn(skillTools); this.transientEntityTracker = new TransientEntityTracker(); @@ -123,6 +136,8 @@ protected void mockBaseEnvironment() { mockPermissions(); + mockNotifications(); + mockedRankUtils = Mockito.mockStatic(RankUtils.class); // wire server @@ -132,11 +147,15 @@ protected void mockBaseEnvironment() { // wire plugin manager this.pluginManager = mock(PluginManager.class); when(mockedServer.getPluginManager()).thenReturn(pluginManager); + // Process level up events in our self listener Mockito.doAnswer(invocation -> { selfListener.onPlayerLevelUp(invocation.getArgument(0)); return null; }).when(pluginManager).callEvent(any(McMMOPlayerLevelUpEvent.class)); + // Don't process pre-gain events + Mockito.doAnswer((ignored) -> null).when(pluginManager).callEvent(any(McMMOPlayerPreXpGainEvent.class)); + // wire world this.world = mock(World.class); @@ -177,9 +196,12 @@ protected void mockBaseEnvironment() { private void mockPermissions() { mockedPermissions = Mockito.mockStatic(Permissions.class); when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); - // Mockito.when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn(true); when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); - // Mockito.when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn(true); + when(Permissions.skillEnabled(any(Player.class), any(PrimarySkillType.class))).thenReturn(true); + } + + private void mockNotifications() { + mockedNotificationManager = Mockito.mockStatic(NotificationManager.class); } private void mockRankConfig() { @@ -203,6 +225,10 @@ private void mockGeneralConfig() { generalConfig = mock(GeneralConfig.class); when(generalConfig.getLocale()).thenReturn("en_US"); when(mcMMO.p.getGeneralConfig()).thenReturn(generalConfig); + + // Experience related + when(generalConfig.getLevelCap(any(PrimarySkillType.class))).thenReturn(Integer.MAX_VALUE); + when(generalConfig.getPowerLevelCap()).thenReturn(Integer.MAX_VALUE); } private void mockExperienceConfig() { @@ -212,6 +238,12 @@ private void mockExperienceConfig() { // Combat when(ExperienceConfig.getInstance().getCombatXP(EntityType.COW)).thenReturn(1D); + when(ExperienceConfig.getInstance().getFormulaType()).thenReturn(FormulaType.LINEAR); + when(ExperienceConfig.getInstance().getBase(FormulaType.LINEAR)).thenReturn(1020); + when(ExperienceConfig.getInstance().getMultiplier(FormulaType.LINEAR)).thenReturn(20D); + when(ExperienceConfig.getInstance().getFormulaSkillModifier(any(PrimarySkillType.class))).thenReturn(1D); + when(ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()).thenReturn(1D); + when(ExperienceConfig.getInstance().getExpModifier()).thenReturn(1D); } protected void cleanupBaseEnvironment() { @@ -243,5 +275,8 @@ protected void cleanupBaseEnvironment() { if (mockedEventUtils != null) { mockedEventUtils.close(); } + if (mockedNotificationManager != null) { + mockedNotificationManager.close(); + } } } diff --git a/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java b/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java index cc2dad328b..7c47d01e70 100644 --- a/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java +++ b/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java @@ -2,6 +2,7 @@ import com.gmail.nossr50.MMOTestEnvironmentBasic; import com.gmail.nossr50.datatypes.experience.XPGainReason; +import com.gmail.nossr50.datatypes.experience.XPGainSource; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.events.experience.McMMOPlayerLevelUpEvent; @@ -11,11 +12,9 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; -import java.util.Set; import java.util.function.BiPredicate; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -51,6 +50,71 @@ void levelUpShouldRunCommandFiveTimes() { mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), any()), atLeast(5)); } + @Test + void levelUpViaXPGainShouldRunCommandFiveTimes() { + // GIVEN level up command for Mining should always execute for Mining level up + assert mcMMO.p.getLevelUpCommandManager().isEmpty(); + final String commandStr = "say hello"; + final LevelUpCommand levelUpCommand + = buildLevelUpCommand(commandStr, (s, ignored) -> s == skill); + mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); + + // WHEN player gains 5 levels in mining via command + assertEquals(0, mmoPlayer.getSkillLevel(skill)); + int levelsGained = 5; + for (int i = 0; i < 5; i++) { + mmoPlayer.applyXpGain(skill, mmoPlayer.getProfile().getXpToLevel(skill), XPGainReason.COMMAND, XPGainSource.COMMAND); + } + + // THEN the command should be checked for execution + verify(levelUpCommandManager, times(levelsGained)).apply(any(), any(), any()); + verify(levelUpCommand, times(levelsGained)).process(any(), any(), any()); + + // THEN the command should have executed + verify(levelUpCommand, times(levelsGained)).executeCommand(any(McMMOPlayer.class), any(PrimarySkillType.class), anyInt()); + mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), any()), atLeast(5)); + } + + @Test + void levelUpViaXPGainShouldRunCommandFiveTimesWithPlaceholders() { + // GIVEN level up command for Mining should always execute for Mining level up + assert mcMMO.p.getLevelUpCommandManager().isEmpty(); + String playerName = "Momshroom"; + when (player.getName()).thenReturn(playerName); + assertEquals(player.getName(), playerName); + final String commandStr = "say hello %player%, you have reached level %level%"; + final String expectedStr1 = "say hello " + playerName + ", you have reached level 1"; + final String expectedStr2 = "say hello " + playerName + ", you have reached level 2"; + final String expectedStr3 = "say hello " + playerName + ", you have reached level 3"; + final String expectedStr4 = "say hello " + playerName + ", you have reached level 4"; + final String expectedStr5 = "say hello " + playerName + ", you have reached level 5"; + final LevelUpCommand levelUpCommand + = buildLevelUpCommand(commandStr, (s, ignored) -> s == skill); + mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); + + // WHEN player gains 5 levels in mining via command + assertEquals(0, mmoPlayer.getSkillLevel(skill)); + int levelsGained = 5; + for (int i = 0; i < 5; i++) { + mmoPlayer.applyXpGain(skill, mmoPlayer.getProfile().getXpToLevel(skill), XPGainReason.COMMAND, XPGainSource.COMMAND); + } + + // THEN the command should be checked for execution + verify(levelUpCommandManager, times(levelsGained)).apply(any(), any(), any()); + verify(levelUpCommand, times(levelsGained)).process(any(), any(), any()); + + // THEN the command should have executed + verify(levelUpCommand, times(levelsGained)).executeCommand(any(McMMOPlayer.class), any(PrimarySkillType.class), anyInt()); + mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), any()), atLeast(5)); + // AND THEN the message for each level up should have happened at least once + // verify that Bukkit.dispatchCommand got executed at least 5 times with the correct injectedCommand + mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), eq(expectedStr1))); + mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), eq(expectedStr2))); + mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), eq(expectedStr3))); + mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), eq(expectedStr4))); + mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), eq(expectedStr5))); + } + @Test void levelUpShouldRunCommandFiveTimesWithPlaceholders() { // GIVEN level up command for Mining should always execute for Mining level up @@ -80,7 +144,7 @@ void levelUpShouldRunCommandFiveTimesWithPlaceholders() { } @Test - void levelUpShouldRunCommandFiveTimesWithPlaceholdersForLevel() { + void levelUpViaAddLevelsShouldRunCommandFiveTimesWithPlaceholdersForLevel() { // GIVEN level up command for Mining should always execute for Mining level up assert mcMMO.p.getLevelUpCommandManager().isEmpty(); String playerName = "Momshroom"; @@ -97,11 +161,17 @@ void levelUpShouldRunCommandFiveTimesWithPlaceholdersForLevel() { final LevelUpCommand levelUpCommand = buildLevelUpCommand(commandStr, (s, ignored) -> s == skill); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); - int levelsGained = 5; // WHEN player gains 5 levels in mining - McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(player, skill, levelsGained, XPGainReason.PVE); - selfListener.onPlayerLevelUp(event); + int levelsGained = 5; + mmoPlayer.getProfile().addLevels(skill, levelsGained); + EventUtils.tryLevelChangeEvent( + player, + skill, + levelsGained, + mmoPlayer.getProfile().getSkillXpLevelRaw(skill), + true, + XPGainReason.COMMAND); // THEN the command should be checked for execution verify(levelUpCommandManager).apply(any(), any(), any()); From 847095aff4c8670ff7497383e5fc583e3b6d9768 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 28 Jan 2024 16:57:26 -0800 Subject: [PATCH 10/13] Add power level commands to commands on level up --- .../commands/levelup/CommandsOnLevel.java | 4 + .../commands/levelup/LevelUpCommand.java | 105 --------- .../levelup/LevelUpCommandManager.java | 67 ++++-- .../commands/levelup/PowerLevelUpCommand.java | 98 ++++++++ .../levelup/PowerLevelUpCommandBuilder.java | 59 +++++ ...mandImpl.java => SkillLevelUpCommand.java} | 9 +- .../levelup/SkillLevelUpCommandBuilder.java | 82 +++++++ .../config/CommandOnLevelUpConfig.java | 82 ++++++- .../nossr50/datatypes/player/McMMOPlayer.java | 1 - .../gmail/nossr50/listeners/SelfListener.java | 9 +- .../nossr50/MMOTestEnvironmentBasic.java | 56 ++--- .../commands/levelup/LevelUpCommandTest.java | 213 ++++++++++++------ 12 files changed, 537 insertions(+), 248 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/commands/levelup/CommandsOnLevel.java delete mode 100644 src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java create mode 100644 src/main/java/com/gmail/nossr50/commands/levelup/PowerLevelUpCommand.java create mode 100644 src/main/java/com/gmail/nossr50/commands/levelup/PowerLevelUpCommandBuilder.java rename src/main/java/com/gmail/nossr50/commands/levelup/{LevelUpCommandImpl.java => SkillLevelUpCommand.java} (89%) create mode 100644 src/main/java/com/gmail/nossr50/commands/levelup/SkillLevelUpCommandBuilder.java diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/CommandsOnLevel.java b/src/main/java/com/gmail/nossr50/commands/levelup/CommandsOnLevel.java new file mode 100644 index 0000000000..eed723aa27 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/commands/levelup/CommandsOnLevel.java @@ -0,0 +1,4 @@ +package com.gmail.nossr50.commands.levelup; + +public interface CommandsOnLevel { +} diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java deleted file mode 100644 index 02876bfa18..0000000000 --- a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.gmail.nossr50.commands.levelup; - -import com.gmail.nossr50.datatypes.player.McMMOPlayer; -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; -import java.util.LinkedList; -import java.util.Set; -import java.util.function.BiPredicate; - -import static java.util.Objects.requireNonNull; - -/** - * Represents a command to be executed on a level up - */ -public interface LevelUpCommand { - /** - * Process the command - * - * @param player the player - * @param primarySkillType the skill type - * @param levelsGained the levels gained - */ - void process(McMMOPlayer player, PrimarySkillType primarySkillType, Set levelsGained); - - /** - * Execute the command - * @param player the player - * @param primarySkillType the skill - * @param level the level of the skill - */ - void executeCommand(McMMOPlayer player, PrimarySkillType primarySkillType, int level); - - class LevelUpCommandBuilder { - private Set skillFilter = null; - private Set levels = null; - private LinkedList commands = null; - private BiPredicate predicate = null; - private boolean logInfo; - - public LevelUpCommandBuilder() { - this.logInfo = false; - } - - public LevelUpCommandBuilder withPredicate(BiPredicate predicate) { - this.predicate = predicate; - return this; - } - - public LevelUpCommandBuilder withLogInfo(boolean logInfo) { - this.logInfo = logInfo; - return this; - } - - public LevelUpCommandBuilder command(@NotNull String command) { - this.commands = new LinkedList<>(); - this.commands.add(command); - return this; - } - - public LevelUpCommandBuilder commands(@NotNull Collection command) { - this.commands = new LinkedList<>(command); - return this; - } - - public LevelUpCommandBuilder withLevels(@NotNull Collection levels) { - requireNonNull(levels, "levels is null!"); - this.levels = Set.copyOf(levels); - return this; - } - - public LevelUpCommandBuilder withSkillFilter(@NotNull Set skillFilter) { - requireNonNull(skillFilter, "skillFilter is null!"); - if (skillFilter.isEmpty()) { - throw new IllegalArgumentException("skillFilter is empty"); - } - this.skillFilter = skillFilter; - return this; - } - - public LevelUpCommandBuilder withSkillFilter(@NotNull PrimarySkillType skill) { - requireNonNull(skill, "skill is null!"); - this.skillFilter = Set.of(skill); - return this; - } - - public LevelUpCommand build() { - requireNonNull(commands, "commandStr is null"); - if (predicate == null) { - requireNonNull(levels, "levels is null"); - - return new LevelUpCommandImpl((skill, level) -> { - if (skillFilter == null) { - return levels.contains(level); - } else { - return skillFilter.contains(skill) && levels.contains(level); - } - }, commands, logInfo); - } - - return new LevelUpCommandImpl(predicate, commands, logInfo); - } - } -} diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java index 72a6e9633f..c1ae12a909 100644 --- a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java +++ b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java @@ -9,26 +9,32 @@ import java.util.Objects; import java.util.Set; +import static java.util.Objects.requireNonNull; + /** * Manages commands to be executed on level up */ public class LevelUpCommandManager { - private final @NotNull Set commands; + private final @NotNull Set skillLevelCommands; + private final @NotNull Set powerLevelUpCommands; private final @NotNull mcMMO plugin; public LevelUpCommandManager(@NotNull mcMMO plugin) { - this.plugin = plugin; - this.commands = new HashSet<>(); + this.plugin = requireNonNull(plugin, "plugin cannot be null"); + this.skillLevelCommands = new HashSet<>(); + this.powerLevelUpCommands = new HashSet<>(); } - /** - * Register a level up command to be executed on level up - * - * @param levelUpCommand the levelUpCommand - */ - public void registerCommand(@NotNull LevelUpCommand levelUpCommand) { - commands.add(levelUpCommand); - mcMMO.p.getLogger().info("Registered levelUpCommand on level up: " + levelUpCommand); + public void registerCommand(@NotNull SkillLevelUpCommand skillLevelUpCommand) { + requireNonNull(skillLevelUpCommand, "skillLevelUpCommand cannot be null"); + skillLevelCommands.add(skillLevelUpCommand); + mcMMO.p.getLogger().info("Registered level up command - SkillLevelUpCommand: " + skillLevelUpCommand); + } + + public void registerCommand(@NotNull PowerLevelUpCommand powerLevelUpCommand) { + requireNonNull(powerLevelUpCommand, "powerLevelUpCommand cannot be null"); + powerLevelUpCommands.add(powerLevelUpCommand); + mcMMO.p.getLogger().info("Registered level up command - PowerLevelUpCommand: " + powerLevelUpCommand); } /** @@ -38,29 +44,41 @@ public void registerCommand(@NotNull LevelUpCommand levelUpCommand) { * @param primarySkillType the skill type * @param levelsGained the levels gained */ - public void apply(@NotNull McMMOPlayer mmoPlayer, @NotNull PrimarySkillType primarySkillType, Set levelsGained) { + public void applySkillLevelUp(@NotNull McMMOPlayer mmoPlayer, @NotNull PrimarySkillType primarySkillType, Set levelsGained) { if (!mmoPlayer.getPlayer().isOnline()) { return; } - for (LevelUpCommand command : commands) { + for (SkillLevelUpCommand command : skillLevelCommands) { command.process(mmoPlayer, primarySkillType, levelsGained); } } + public void applyPowerLevelUp(@NotNull McMMOPlayer mmoPlayer, Set levelsGained) { + if (!mmoPlayer.getPlayer().isOnline()) { + return; + } + + for (PowerLevelUpCommand command : powerLevelUpCommands) { + command.process(mmoPlayer, levelsGained); + } + } + + public @NotNull Set getSkillLevelCommands() { + return skillLevelCommands; + } + + public @NotNull Set getPowerLevelUpCommands() { + return powerLevelUpCommands; + } + /** * Clear all registered commands */ public void clear() { mcMMO.p.getLogger().info("Clearing registered commands on level up"); - commands.clear(); - } - - /** - * @return true if there are no registered commands - */ - public boolean isEmpty() { - return commands.isEmpty(); + skillLevelCommands.clear(); + powerLevelUpCommands.clear(); } @Override @@ -68,18 +86,19 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; LevelUpCommandManager that = (LevelUpCommandManager) o; - return Objects.equals(commands, that.commands) && Objects.equals(plugin, that.plugin); + return Objects.equals(skillLevelCommands, that.skillLevelCommands) && Objects.equals(powerLevelUpCommands, that.powerLevelUpCommands) && Objects.equals(plugin, that.plugin); } @Override public int hashCode() { - return Objects.hash(commands, plugin); + return Objects.hash(skillLevelCommands, powerLevelUpCommands, plugin); } @Override public String toString() { return "LevelUpCommandManager{" + - "commands=" + commands + + "skillLevelCommands=" + skillLevelCommands + + ", powerLevelUpCommands=" + powerLevelUpCommands + ", plugin=" + plugin + '}'; } diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/PowerLevelUpCommand.java b/src/main/java/com/gmail/nossr50/commands/levelup/PowerLevelUpCommand.java new file mode 100644 index 0000000000..754eff0f29 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/commands/levelup/PowerLevelUpCommand.java @@ -0,0 +1,98 @@ +package com.gmail.nossr50.commands.levelup; + +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.LogUtils; +import org.bukkit.Bukkit; +import org.jetbrains.annotations.NotNull; + +import java.util.LinkedList; +import java.util.Objects; +import java.util.Set; +import java.util.function.Predicate; + +public class PowerLevelUpCommand implements CommandsOnLevel { + private final Predicate predicate; + private final boolean logInfo; + private final @NotNull LinkedList commands; + + public PowerLevelUpCommand(@NotNull Predicate predicate, @NotNull String command, boolean logInfo) { + this.predicate = predicate; + this.commands = new LinkedList<>(); + this.commands.add(command); + this.logInfo = logInfo; + } + + public PowerLevelUpCommand(@NotNull Predicate predicate, @NotNull LinkedList commands, boolean logInfo) { + this.predicate = predicate; + this.commands = commands; + this.logInfo = logInfo; + } + + public void process(McMMOPlayer player, Set levelsGained) { + for (int i : levelsGained) { + if (predicate.test(i)) { + // execute command via server console in Bukkit + if(logInfo) { + mcMMO.p.getLogger().info("Executing command: " + commands); + } else { + LogUtils.debug(mcMMO.p.getLogger(), "Executing command: " + commands); + } + executeCommand(player, i); + } + } + } + + public void executeCommand(McMMOPlayer player, int level) { + // TODO: Change this to debug later + mcMMO.p.getLogger().info("Executing commands for level up: " + commands); + for (String command : commands) { + // TODO: Change this to debug later + mcMMO.p.getLogger().info("Executing command: " + command); + String injectedCommand = injectedCommand(command, player, level); + // TODO: Remove verbose logging later + if (!injectedCommand.equalsIgnoreCase(command)) { + mcMMO.p.getLogger().info(("Command has been injected with new values: " + injectedCommand)); + } + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), injectedCommand); + } + } + + private String injectedCommand(String command, McMMOPlayer player, int level) { + // replace %player% with player name, %skill% with skill name, and %level% with level + command = safeReplace(command, "%player%", player.getPlayer().getName()); + command = safeReplace(command, "%skill%", "power level"); + command = safeReplace(command, "%level%", String.valueOf(level)); + return command; + } + + private String safeReplace(String targetStr, String toReplace, String replacement) { + if (replacement == null) { + return targetStr; + } + + return targetStr.replace(toReplace, replacement); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PowerLevelUpCommand that = (PowerLevelUpCommand) o; + return logInfo == that.logInfo && Objects.equals(predicate, that.predicate) && Objects.equals(commands, that.commands); + } + + @Override + public int hashCode() { + return Objects.hash(predicate, logInfo, commands); + } + + @Override + public String toString() { + return "PowerLevelUpCommand{" + + "predicate=" + predicate + + ", logInfo=" + logInfo + + ", commands=" + commands + + '}'; + } +} diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/PowerLevelUpCommandBuilder.java b/src/main/java/com/gmail/nossr50/commands/levelup/PowerLevelUpCommandBuilder.java new file mode 100644 index 0000000000..a80c0251ee --- /dev/null +++ b/src/main/java/com/gmail/nossr50/commands/levelup/PowerLevelUpCommandBuilder.java @@ -0,0 +1,59 @@ +package com.gmail.nossr50.commands.levelup; + +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.Set; +import java.util.function.Predicate; + +import static java.util.Objects.requireNonNull; + +public class PowerLevelUpCommandBuilder { + private Set levels = null; + private LinkedList commands = null; + private Predicate predicate = null; + private boolean logInfo; + + public PowerLevelUpCommandBuilder() { + this.logInfo = false; + } + + public PowerLevelUpCommandBuilder withPredicate(Predicate predicate) { + this.predicate = predicate; + return this; + } + + public PowerLevelUpCommandBuilder withLogInfo(boolean logInfo) { + this.logInfo = logInfo; + return this; + } + + public PowerLevelUpCommandBuilder command(@NotNull String command) { + this.commands = new LinkedList<>(); + this.commands.add(command); + return this; + } + + public PowerLevelUpCommandBuilder commands(@NotNull Collection command) { + this.commands = new LinkedList<>(command); + return this; + } + + public PowerLevelUpCommandBuilder withLevels(@NotNull Collection levels) { + requireNonNull(levels, "levels is null!"); + this.levels = Set.copyOf(levels); + return this; + } + + public PowerLevelUpCommand build() { + requireNonNull(commands, "commandStr is null"); + if (predicate == null) { + requireNonNull(levels, "levels is null"); + + return new PowerLevelUpCommand((level) -> levels.contains(level), commands, logInfo); + } + + return new PowerLevelUpCommand(predicate, commands, logInfo); + } +} diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java b/src/main/java/com/gmail/nossr50/commands/levelup/SkillLevelUpCommand.java similarity index 89% rename from src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java rename to src/main/java/com/gmail/nossr50/commands/levelup/SkillLevelUpCommand.java index 935abed0a8..798abbe67c 100644 --- a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandImpl.java +++ b/src/main/java/com/gmail/nossr50/commands/levelup/SkillLevelUpCommand.java @@ -12,25 +12,24 @@ import java.util.Set; import java.util.function.BiPredicate; -public class LevelUpCommandImpl implements LevelUpCommand { +public class SkillLevelUpCommand implements CommandsOnLevel { private final BiPredicate predicate; private final boolean logInfo; private final @NotNull LinkedList commands; - public LevelUpCommandImpl(@NotNull BiPredicate predicate, @NotNull String command, boolean logInfo) { + public SkillLevelUpCommand(@NotNull BiPredicate predicate, @NotNull String command, boolean logInfo) { this.predicate = predicate; this.commands = new LinkedList<>(); this.commands.add(command); this.logInfo = logInfo; } - public LevelUpCommandImpl(@NotNull BiPredicate predicate, @NotNull LinkedList commands, boolean logInfo) { + public SkillLevelUpCommand(@NotNull BiPredicate predicate, @NotNull LinkedList commands, boolean logInfo) { this.predicate = predicate; this.commands = commands; this.logInfo = logInfo; } - @Override public void process(McMMOPlayer player, PrimarySkillType primarySkillType, Set levelsGained) { for (int i : levelsGained) { if (predicate.test(primarySkillType, i)) { @@ -80,7 +79,7 @@ private String safeReplace(String targetStr, String toReplace, String replacemen public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - LevelUpCommandImpl that = (LevelUpCommandImpl) o; + SkillLevelUpCommand that = (SkillLevelUpCommand) o; return logInfo == that.logInfo && Objects.equals(predicate, that.predicate) && Objects.equals(commands, that.commands); } diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/SkillLevelUpCommandBuilder.java b/src/main/java/com/gmail/nossr50/commands/levelup/SkillLevelUpCommandBuilder.java new file mode 100644 index 0000000000..98b731d969 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/commands/levelup/SkillLevelUpCommandBuilder.java @@ -0,0 +1,82 @@ +package com.gmail.nossr50.commands.levelup; + +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.Set; +import java.util.function.BiPredicate; + +import static java.util.Objects.requireNonNull; + +public class SkillLevelUpCommandBuilder { + private Set skillFilter = null; + private Set levels = null; + private LinkedList commands = null; + private BiPredicate predicate = null; + private boolean logInfo; + + public SkillLevelUpCommandBuilder() { + this.logInfo = false; + } + + public SkillLevelUpCommandBuilder withPredicate(BiPredicate predicate) { + this.predicate = predicate; + return this; + } + + public SkillLevelUpCommandBuilder withLogInfo(boolean logInfo) { + this.logInfo = logInfo; + return this; + } + + public SkillLevelUpCommandBuilder command(@NotNull String command) { + this.commands = new LinkedList<>(); + this.commands.add(command); + return this; + } + + public SkillLevelUpCommandBuilder commands(@NotNull Collection command) { + this.commands = new LinkedList<>(command); + return this; + } + + public SkillLevelUpCommandBuilder withLevels(@NotNull Collection levels) { + requireNonNull(levels, "levels is null!"); + this.levels = Set.copyOf(levels); + return this; + } + + public SkillLevelUpCommandBuilder withSkillFilter(@NotNull Set skillFilter) { + requireNonNull(skillFilter, "skillFilter is null!"); + if (skillFilter.isEmpty()) { + throw new IllegalArgumentException("skillFilter is empty"); + } + this.skillFilter = skillFilter; + return this; + } + + public SkillLevelUpCommandBuilder withSkillFilter(@NotNull PrimarySkillType skill) { + requireNonNull(skill, "skill is null!"); + this.skillFilter = Set.of(skill); + return this; + } + + public SkillLevelUpCommand build() { + requireNonNull(commands, "commandStr is null"); + if (predicate == null) { + requireNonNull(levels, "levels is null"); + + return new SkillLevelUpCommand((skill, level) -> { + if (skillFilter == null) { + return levels.contains(level); + } else { + return skillFilter.contains(skill) && levels.contains(level); + } + }, commands, logInfo); + } + + return new SkillLevelUpCommand(predicate, commands, logInfo); + } +} diff --git a/src/main/java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java b/src/main/java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java index 7d4a7e388f..dcac847bc5 100644 --- a/src/main/java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java +++ b/src/main/java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java @@ -1,6 +1,9 @@ package com.gmail.nossr50.config; -import com.gmail.nossr50.commands.levelup.LevelUpCommand; +import com.gmail.nossr50.commands.levelup.PowerLevelUpCommand; +import com.gmail.nossr50.commands.levelup.PowerLevelUpCommandBuilder; +import com.gmail.nossr50.commands.levelup.SkillLevelUpCommand; +import com.gmail.nossr50.commands.levelup.SkillLevelUpCommandBuilder; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.LogUtils; @@ -22,6 +25,7 @@ public class CommandOnLevelUpConfig extends BukkitConfig { public static final String CONDITION_SECTION = "condition"; public static final String ENABLED = "enabled"; public static final String COMMANDS = "commands"; + public static final String POWER_LEVEL_SECTION = "power_level"; public CommandOnLevelUpConfig(@NotNull File dataFolder) { super("levelupcommands.yml", dataFolder); @@ -44,20 +48,26 @@ protected void loadKeys() { continue; } - LevelUpCommand levelUpCommand = buildCommand(commandSection); - if (levelUpCommand == null) { + SkillLevelUpCommand skillLevelUpCommand = buildSkillLevelUpCommand(commandSection); + PowerLevelUpCommand powerLevelUpCommand = buildPowerLevelUpCommand(commandSection); + + if (skillLevelUpCommand == null && powerLevelUpCommand == null) { mcMMO.p.getLogger().severe("Invalid command format for key: " + key); - continue; } else { - mcMMO.p.getLogger().info("Command successfully loaded from config for key: " + key); - mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); + if(skillLevelUpCommand != null) { + mcMMO.p.getLevelUpCommandManager().registerCommand(skillLevelUpCommand); + mcMMO.p.getLogger().info("Skill Level up command successfully loaded from config for key: " + key); + } + if(powerLevelUpCommand != null) { + mcMMO.p.getLevelUpCommandManager().registerCommand(powerLevelUpCommand); + mcMMO.p.getLogger().info("Power Level up command successfully loaded from config for key: " + key); + } } } } - @Nullable - private LevelUpCommand buildCommand(final ConfigurationSection commandSection) { - LevelUpCommand.LevelUpCommandBuilder builder = new LevelUpCommand.LevelUpCommandBuilder(); + private @NotNull SkillLevelUpCommand buildSkillLevelUpCommand(final ConfigurationSection commandSection) { + SkillLevelUpCommandBuilder builder = new SkillLevelUpCommandBuilder(); // check if command is enabled if (!commandSection.getBoolean(ENABLED, true)) { return null; @@ -129,6 +139,60 @@ private LevelUpCommand buildCommand(final ConfigurationSection commandSection) { return builder.build(); } + private @Nullable PowerLevelUpCommand buildPowerLevelUpCommand(final ConfigurationSection commandSection) { + PowerLevelUpCommandBuilder builder = new PowerLevelUpCommandBuilder(); + // check if command is enabled + if (!commandSection.getBoolean(ENABLED, true)) { + return null; + } + + /* Condition Section */ + ConfigurationSection condition = commandSection.getConfigurationSection(CONDITION_SECTION); + if (condition == null) { + mcMMO.p.getLogger().severe("No condition section found for command named " + commandSection.getName()); + return null; + } + + // No power level condition + if (!condition.contains(POWER_LEVEL_SECTION)) { + return null; + } + + // for now only simple condition is supported + if (!condition.contains(LEVELS_SECTION)) { + mcMMO.p.getLogger().severe("No condition.levels section found for power level command named " + + commandSection.getName()); + return null; + } + + Collection levels = condition.getIntegerList(LEVELS_SECTION); + if (levels.isEmpty()) { + mcMMO.p.getLogger().severe("No valid levels found in condition.levels for power level command named " + + commandSection.getName()); + return null; + } + builder.withLevels(levels); + + // commands + if (commandSection.isString(COMMANDS)) { + String command = commandSection.getString(COMMANDS); + if (command != null) { + builder.command(command); + } + } else { + List commands = commandSection.getStringList(COMMANDS); + if (commands.isEmpty()) { + mcMMO.p.getLogger().severe("No commands defined for power level command named " + + commandSection.getName()); + return null; + } else { + builder.commands(commands); + } + } + + return builder.build(); + } + private Set getSkillsFromFilter(Set skillFilter) { return mcMMO.p.getSkillTools().matchSkills(skillFilter); } diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index e96cd56685..91dfe17e53 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -54,7 +54,6 @@ import com.gmail.nossr50.util.sounds.SoundType; import net.kyori.adventure.identity.Identified; import net.kyori.adventure.identity.Identity; -import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.block.Block; diff --git a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java index e72c82194d..dce1bc44b1 100644 --- a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java @@ -60,11 +60,18 @@ public void onPlayerLevelUp(McMMOPlayerLevelUpEvent event) { } final Set levelsAchieved = new LinkedHashSet<>(); + final Set powerLevelsAchieved = new LinkedHashSet<>(); int startingLevel = event.getSkillLevel() - event.getLevelsGained(); + int startingPowerLevel = mcMMOPlayer.getPowerLevel() - event.getLevelsGained(); for (int i = 0; i < event.getLevelsGained(); i++) { levelsAchieved.add(startingLevel + (i + 1)); } - plugin.getLevelUpCommandManager().apply(mcMMOPlayer, skill, levelsAchieved); + for (int i = 0; i < event.getLevelsGained(); i++) { + powerLevelsAchieved.add(startingPowerLevel + (i + 1)); + } + + plugin.getLevelUpCommandManager().applySkillLevelUp(mcMMOPlayer, skill, levelsAchieved); + plugin.getLevelUpCommandManager().applyPowerLevelUp(mcMMOPlayer, powerLevelsAchieved); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) diff --git a/src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java b/src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java index a260b7ad41..106648c972 100644 --- a/src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java +++ b/src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java @@ -24,17 +24,14 @@ import org.bukkit.command.ConsoleCommandSender; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.plugin.PluginManager; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.mockito.MockedStatic; import org.mockito.Mockito; -import org.mockito.internal.matchers.Not; import java.util.UUID; -import java.util.function.Function; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; @@ -67,15 +64,7 @@ public abstract class MMOTestEnvironmentBasic { private FormulaManager formulaManager; /* Mocks */ - protected Player player; - - protected UUID playerUUID = UUID.randomUUID(); - protected ItemStack itemInMainHand; - protected PlayerInventory playerInventory; - protected PlayerProfile playerProfile; - protected McMMOPlayer mmoPlayer; - protected String playerName = "testPlayer"; protected ChunkManager chunkManager; @@ -163,29 +152,12 @@ protected void mockBaseEnvironment() { this.mockedMisc = Mockito.mockStatic(Misc.class); // Mockito.when(Misc.getBlockCenter(any())).thenReturn(new Location(world, 0, 0, 0)); - // setup player and player related mocks after everything else - this.player = mock(Player.class); - when(player.getUniqueId()).thenReturn(playerUUID); - - // wire inventory - this.playerInventory = mock(PlayerInventory.class); - when(player.getInventory()).thenReturn(playerInventory); - - // PlayerProfile and McMMOPlayer are partially mocked - playerProfile = Mockito.spy(new PlayerProfile("testPlayer", player.getUniqueId(), 0)); - when(playerProfile.isLoaded()).thenReturn(true); - mmoPlayer = Mockito.spy(new McMMOPlayer(player, playerProfile)); - // wire user manager this.mockedUserManager = Mockito.mockStatic(UserManager.class); - when(UserManager.getPlayer(player)).thenReturn(mmoPlayer); // Self listener selfListener = Mockito.spy(new SelfListener(mcMMO.p)); - // Player online status - when(player.isOnline()).thenReturn(true); - // Console command sender consoleCommandSender = mock(ConsoleCommandSender.class); when(consoleCommandSender.getName()).thenReturn("CONSOLE"); @@ -279,4 +251,32 @@ protected void cleanupBaseEnvironment() { mockedNotificationManager.close(); } } + + protected McMMOPlayer getMMOPlayer(UUID playerUUID, String playerName, int startingLevel) { + Player player = mock(Player.class); + // Player UUID + when(player.getUniqueId()).thenReturn(playerUUID); + // Player name + when(player.getName()).thenReturn(playerName); + + // Player Inventory + this.playerInventory = mock(PlayerInventory.class); + when(player.getInventory()).thenReturn(playerInventory); + + // Player Profile + PlayerProfile playerProfile = Mockito.spy(new PlayerProfile(playerName, player.getUniqueId(), startingLevel)); + when(playerProfile.isLoaded()).thenReturn(true); + // McMMOPlayer + McMMOPlayer mmoPlayer = Mockito.spy(new McMMOPlayer(player, playerProfile)); + // Wire UserManager + when(UserManager.getPlayer(player)).thenReturn(mmoPlayer); + // Player is online + when(player.isOnline()).thenReturn(true); + + return mmoPlayer; + } + + protected McMMOPlayer getMMOPlayer(UUID playerUUID, String playerName) { + return getMMOPlayer(playerUUID, playerName, 0); + } } diff --git a/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java b/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java index 7c47d01e70..59cd22a6ef 100644 --- a/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java +++ b/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java @@ -9,98 +9,98 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.EventUtils; import org.bukkit.Bukkit; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import java.util.UUID; import java.util.function.BiPredicate; +import java.util.function.Predicate; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; class LevelUpCommandTest extends MMOTestEnvironmentBasic { - private final PrimarySkillType skill = PrimarySkillType.MINING; - private final PrimarySkillType otherSkill = PrimarySkillType.WOODCUTTING; + private final PrimarySkillType mining = PrimarySkillType.MINING; + private final PrimarySkillType woodcutting = PrimarySkillType.WOODCUTTING; + private McMMOPlayer mmoPlayer; + private final String playerName = "Momshroom"; + + @BeforeEach + void beforeEach() { + mcMMO.p.getLevelUpCommandManager().getSkillLevelCommands().clear(); + mcMMO.p.getLevelUpCommandManager().getPowerLevelUpCommands().clear(); + + this.mmoPlayer = getMMOPlayer(UUID.randomUUID(), playerName, 0); + } @Test - void levelUpShouldRunCommandFiveTimes() { + void skillLevelUpShouldRunFiveTimes() { // GIVEN level up command for Mining should always execute for Mining level up - assert mcMMO.p.getLevelUpCommandManager().isEmpty(); + assert mcMMO.p.getLevelUpCommandManager().getSkillLevelCommands().isEmpty(); final String commandStr = "say hello"; - final LevelUpCommand levelUpCommand - = buildLevelUpCommand(commandStr, (s, ignored) -> s == skill); + final SkillLevelUpCommand levelUpCommand + = buildSkillLevelUpCommand(commandStr, (s, ignored) -> s == mining); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); // WHEN player gains 5 levels in mining via command - assertEquals(0, mmoPlayer.getSkillLevel(skill)); - int levelsGained = 5; - EventUtils.tryLevelChangeEvent( - player, - skill, - levelsGained, - mmoPlayer.getProfile().getSkillXpLevelRaw(skill), - true, - XPGainReason.COMMAND); + levelPlayerViaXP(mmoPlayer, mining, 5); // THEN the command should be checked for execution - verify(levelUpCommandManager).apply(any(), any(), any()); - verify(levelUpCommand).process(any(), any(), any()); + verify(levelUpCommandManager, atLeastOnce()).applySkillLevelUp(any(), any(), any()); + verify(levelUpCommand, atLeastOnce()).process(any(), any(), any()); + // THEN the command should have executed - verify(levelUpCommand, times(levelsGained)).executeCommand(any(McMMOPlayer.class), any(PrimarySkillType.class), anyInt()); + verify(levelUpCommand, times(5)).executeCommand(any(McMMOPlayer.class), any(PrimarySkillType.class), anyInt()); mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), any()), atLeast(5)); } @Test - void levelUpViaXPGainShouldRunCommandFiveTimes() { + void skillLevelUpViaXPGainShouldRunFiveTimes() { // GIVEN level up command for Mining should always execute for Mining level up - assert mcMMO.p.getLevelUpCommandManager().isEmpty(); + assert mcMMO.p.getLevelUpCommandManager().getSkillLevelCommands().isEmpty(); final String commandStr = "say hello"; - final LevelUpCommand levelUpCommand - = buildLevelUpCommand(commandStr, (s, ignored) -> s == skill); + final SkillLevelUpCommand levelUpCommand + = buildSkillLevelUpCommand(commandStr, (s, ignored) -> s == mining); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); // WHEN player gains 5 levels in mining via command - assertEquals(0, mmoPlayer.getSkillLevel(skill)); - int levelsGained = 5; - for (int i = 0; i < 5; i++) { - mmoPlayer.applyXpGain(skill, mmoPlayer.getProfile().getXpToLevel(skill), XPGainReason.COMMAND, XPGainSource.COMMAND); - } + levelPlayerViaXP(mmoPlayer, mining, 5); // THEN the command should be checked for execution - verify(levelUpCommandManager, times(levelsGained)).apply(any(), any(), any()); - verify(levelUpCommand, times(levelsGained)).process(any(), any(), any()); + verify(levelUpCommandManager, times(5)).applySkillLevelUp(any(), any(), any()); + verify(levelUpCommand, times(5)).process(any(), any(), any()); // THEN the command should have executed - verify(levelUpCommand, times(levelsGained)).executeCommand(any(McMMOPlayer.class), any(PrimarySkillType.class), anyInt()); + verify(levelUpCommand, times(5)).executeCommand(any(McMMOPlayer.class), any(PrimarySkillType.class), anyInt()); mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), any()), atLeast(5)); } @Test - void levelUpViaXPGainShouldRunCommandFiveTimesWithPlaceholders() { + void skillLevelUpViaXPGainShouldRunCommandFiveTimesWithPlaceholders() { // GIVEN level up command for Mining should always execute for Mining level up - assert mcMMO.p.getLevelUpCommandManager().isEmpty(); - String playerName = "Momshroom"; - when (player.getName()).thenReturn(playerName); - assertEquals(player.getName(), playerName); + assert mcMMO.p.getLevelUpCommandManager().getSkillLevelCommands().isEmpty(); + assertEquals(mmoPlayer.getPlayer().getName(), playerName); final String commandStr = "say hello %player%, you have reached level %level%"; final String expectedStr1 = "say hello " + playerName + ", you have reached level 1"; final String expectedStr2 = "say hello " + playerName + ", you have reached level 2"; final String expectedStr3 = "say hello " + playerName + ", you have reached level 3"; final String expectedStr4 = "say hello " + playerName + ", you have reached level 4"; final String expectedStr5 = "say hello " + playerName + ", you have reached level 5"; - final LevelUpCommand levelUpCommand - = buildLevelUpCommand(commandStr, (s, ignored) -> s == skill); + final SkillLevelUpCommand levelUpCommand + = buildSkillLevelUpCommand(commandStr, (s, ignored) -> s == mining); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); // WHEN player gains 5 levels in mining via command - assertEquals(0, mmoPlayer.getSkillLevel(skill)); + assertEquals(0, mmoPlayer.getSkillLevel(mining)); int levelsGained = 5; for (int i = 0; i < 5; i++) { - mmoPlayer.applyXpGain(skill, mmoPlayer.getProfile().getXpToLevel(skill), XPGainReason.COMMAND, XPGainSource.COMMAND); + mmoPlayer.applyXpGain(mining, mmoPlayer.getProfile().getXpToLevel(mining), XPGainReason.COMMAND, XPGainSource.COMMAND); } // THEN the command should be checked for execution - verify(levelUpCommandManager, times(levelsGained)).apply(any(), any(), any()); + verify(levelUpCommandManager, times(levelsGained)).applySkillLevelUp(any(), any(), any()); verify(levelUpCommand, times(levelsGained)).process(any(), any(), any()); // THEN the command should have executed @@ -116,26 +116,24 @@ void levelUpViaXPGainShouldRunCommandFiveTimesWithPlaceholders() { } @Test - void levelUpShouldRunCommandFiveTimesWithPlaceholders() { + void skillLevelUpShouldRunCommandFiveTimesWithPlaceholders() { // GIVEN level up command for Mining should always execute for Mining level up - assert mcMMO.p.getLevelUpCommandManager().isEmpty(); - String playerName = "Momshroom"; - when (player.getName()).thenReturn(playerName); - assertEquals(player.getName(), playerName); + assert mcMMO.p.getLevelUpCommandManager().getSkillLevelCommands().isEmpty(); + assertEquals(mmoPlayer.getPlayer().getName(), playerName); final String commandStr = "say hello %player%"; final String expectedStr = "say hello " + playerName; - final LevelUpCommand levelUpCommand - = buildLevelUpCommand(commandStr, (s, ignored) -> s == skill); + final SkillLevelUpCommand levelUpCommand + = buildSkillLevelUpCommand(commandStr, (s, ignored) -> s == mining); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); int levelsGained = 5; // WHEN player gains 5 levels in mining - McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(player, skill, levelsGained, XPGainReason.PVE); + McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(mmoPlayer.getPlayer(), mining, levelsGained, XPGainReason.PVE); selfListener.onPlayerLevelUp(event); // THEN the command should be checked for execution - verify(levelUpCommandManager).apply(any(), any(), any()); + verify(levelUpCommandManager).applySkillLevelUp(any(), any(), any()); verify(levelUpCommand).process(any(), any(), any()); // THEN the command should have executed verify(levelUpCommand, times(levelsGained)).executeCommand(any(McMMOPlayer.class), any(PrimarySkillType.class), anyInt()); @@ -144,12 +142,10 @@ void levelUpShouldRunCommandFiveTimesWithPlaceholders() { } @Test - void levelUpViaAddLevelsShouldRunCommandFiveTimesWithPlaceholdersForLevel() { + void skillLevelUpViaAddLevelsShouldRunCommandFiveTimesWithPlaceholdersForLevel() { // GIVEN level up command for Mining should always execute for Mining level up - assert mcMMO.p.getLevelUpCommandManager().isEmpty(); - String playerName = "Momshroom"; - when (player.getName()).thenReturn(playerName); - assertEquals(player.getName(), playerName); + assert mcMMO.p.getLevelUpCommandManager().getSkillLevelCommands().isEmpty(); + assertEquals(mmoPlayer.getPlayer().getName(), playerName); final String commandStr = "say hello %player%, you have reached level %level%"; final String expectedStr1 = "say hello " + playerName + ", you have reached level 1"; @@ -158,23 +154,23 @@ void levelUpViaAddLevelsShouldRunCommandFiveTimesWithPlaceholdersForLevel() { final String expectedStr4 = "say hello " + playerName + ", you have reached level 4"; final String expectedStr5 = "say hello " + playerName + ", you have reached level 5"; - final LevelUpCommand levelUpCommand - = buildLevelUpCommand(commandStr, (s, ignored) -> s == skill); + final SkillLevelUpCommand levelUpCommand + = buildSkillLevelUpCommand(commandStr, (s, ignored) -> s == mining); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); // WHEN player gains 5 levels in mining int levelsGained = 5; - mmoPlayer.getProfile().addLevels(skill, levelsGained); + mmoPlayer.getProfile().addLevels(mining, levelsGained); EventUtils.tryLevelChangeEvent( - player, - skill, + mmoPlayer.getPlayer(), + mining, levelsGained, - mmoPlayer.getProfile().getSkillXpLevelRaw(skill), + mmoPlayer.getProfile().getSkillXpLevelRaw(mining), true, XPGainReason.COMMAND); // THEN the command should be checked for execution - verify(levelUpCommandManager).apply(any(), any(), any()); + verify(levelUpCommandManager).applySkillLevelUp(any(), any(), any()); verify(levelUpCommand).process(any(), any(), any()); // THEN the command should have executed verify(levelUpCommand, times(levelsGained)).executeCommand(any(McMMOPlayer.class), any(PrimarySkillType.class), anyInt()); @@ -187,53 +183,120 @@ void levelUpViaAddLevelsShouldRunCommandFiveTimesWithPlaceholdersForLevel() { } @Test - void levelUpShouldRunCommandAtLeastOnce() { + void skillLevelUpShouldRunCommandAtLeastOnce() { // GIVEN level up command for Mining should always execute for Mining level up - assert mcMMO.p.getLevelUpCommandManager().isEmpty(); + assert mcMMO.p.getLevelUpCommandManager().getSkillLevelCommands().isEmpty(); final String commandStr = "say hello"; - final LevelUpCommand levelUpCommand - = buildLevelUpCommand(commandStr, (s, ignored) -> s == skill); + final SkillLevelUpCommand levelUpCommand + = buildSkillLevelUpCommand(commandStr, (s, ignored) -> s == mining); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); int levelsGained = 1; // WHEN player gains 5 levels in mining - McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(player, skill, levelsGained, XPGainReason.PVE); + McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(mmoPlayer.getPlayer(), mining, levelsGained, XPGainReason.PVE); selfListener.onPlayerLevelUp(event); // THEN the command should be checked for execution - verify(levelUpCommandManager).apply(any(), any(), any()); + verify(levelUpCommandManager).applySkillLevelUp(any(), any(), any()); verify(levelUpCommand).process(any(), any(), any()); // THEN the command should have executed verify(levelUpCommand).executeCommand(any(McMMOPlayer.class), any(PrimarySkillType.class), anyInt()); } @Test - void levelUpShouldNotRunCommand() { + void skillLevelUpShouldNotRunCommand() { // GIVEN level up command for Woodcutting should not execute for Mining level up - assert mcMMO.p.getLevelUpCommandManager().isEmpty(); + assert mcMMO.p.getLevelUpCommandManager().getSkillLevelCommands().isEmpty(); final String commandStr = "say hello"; - final LevelUpCommand levelUpCommand - = buildLevelUpCommand(commandStr, (s, ignored) -> s == otherSkill); + final SkillLevelUpCommand levelUpCommand + = buildSkillLevelUpCommand(commandStr, (s, ignored) -> s == woodcutting); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); int levelsGained = 5; // WHEN player gains 5 levels in mining - McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(player, skill, levelsGained, XPGainReason.PVE); + McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(mmoPlayer.getPlayer(), mining, levelsGained, XPGainReason.PVE); selfListener.onPlayerLevelUp(event); // THEN the command should be checked for execution - verify(levelUpCommandManager).apply(any(), any(), any()); + verify(levelUpCommandManager).applySkillLevelUp(any(), any(), any()); verify(levelUpCommand).process(any(), any(), any()); // THEN the command should not be run verify(levelUpCommand, never()).executeCommand(any(McMMOPlayer.class), any(PrimarySkillType.class), anyInt()); } - private LevelUpCommand buildLevelUpCommand(String commandStr, BiPredicate predicate) { - LevelUpCommand.LevelUpCommandBuilder builder = new LevelUpCommand.LevelUpCommandBuilder(); + @Test + public void skillLevelUpShouldAlwaysRunPowerlevelCommand() { + // GIVEN level up command for power level should always execute for any level up + assert mcMMO.p.getLevelUpCommandManager().getSkillLevelCommands().isEmpty(); + final String commandStr = "say hello"; + final PowerLevelUpCommand powerLevelUpCommand + = buildPowerLevelUpCommand(commandStr, (i) -> true); + mcMMO.p.getLevelUpCommandManager().registerCommand(powerLevelUpCommand); + + // WHEN player gains 10 levels + levelPlayerViaXP(mmoPlayer, mining, 10); + + // THEN the command should be checked for execution + verify(levelUpCommandManager, atLeastOnce()).applyPowerLevelUp(any(), any()); + verify(powerLevelUpCommand, atLeastOnce()).process(any(), any()); + // THEN the command should have executed + verify(powerLevelUpCommand, times(10)).executeCommand(any(McMMOPlayer.class), anyInt()); + } + + @Test + public void skillLevelUpShouldRunPowerlevelCommandOnce() { + // GIVEN level up command for power level should always execute for any level up + assert mcMMO.p.getLevelUpCommandManager().getSkillLevelCommands().isEmpty(); + final String commandStr = "say hello"; + final PowerLevelUpCommand powerLevelUpCommand + = buildPowerLevelUpCommand(commandStr, (i) -> i == 5); + mcMMO.p.getLevelUpCommandManager().registerCommand(powerLevelUpCommand); + + // WHEN player gains 5 levels + levelPlayerViaXP(mmoPlayer, mining, 5); + + // THEN the command should be checked for execution + verify(levelUpCommandManager, atLeastOnce()).applyPowerLevelUp(any(), any()); + verify(powerLevelUpCommand, atLeastOnce()).process(any(), any()); + + // THEN the command should have executed + verify(powerLevelUpCommand, times(1)).executeCommand(any(McMMOPlayer.class), anyInt()); + } + + private SkillLevelUpCommand buildSkillLevelUpCommand(String commandStr, BiPredicate predicate) { + final SkillLevelUpCommandBuilder builder = new SkillLevelUpCommandBuilder(); builder.command(commandStr) .withPredicate(predicate) .withLogInfo(true); return Mockito.spy(builder.build()); } + + private PowerLevelUpCommand buildPowerLevelUpCommand(String commandStr, Predicate predicate) { + final PowerLevelUpCommandBuilder builder = new PowerLevelUpCommandBuilder(); + builder.command(commandStr) + .withPredicate(predicate) + .withLogInfo(true); + return Mockito.spy(builder.build()); + } + + private void levelPlayerViaXP(McMMOPlayer mmoPlayer, PrimarySkillType skill, int levelsGained) { + assertEquals(0, mmoPlayer.getSkillLevel(skill)); + for (int i = 0; i < levelsGained; i++) { + mmoPlayer.applyXpGain(mining, mmoPlayer.getProfile().getXpToLevel(skill), XPGainReason.COMMAND, XPGainSource.COMMAND); + } + assertEquals(levelsGained, mmoPlayer.getSkillLevel(skill)); + } + + private void levelPlayerViaLevelChangeEvent(McMMOPlayer mmoPlayer, PrimarySkillType skill, int levelsGained) { + assertEquals(0, mmoPlayer.getSkillLevel(skill)); + EventUtils.tryLevelChangeEvent( + mmoPlayer.getPlayer(), + skill, + levelsGained, + mmoPlayer.getProfile().getSkillXpLevelRaw(skill), + true, + XPGainReason.COMMAND); + assertEquals(levelsGained, mmoPlayer.getSkillLevel(skill)); + } } \ No newline at end of file From 37949d07f6c674cfe1890ef8592c8cb5af753764 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sat, 17 Feb 2024 16:19:46 -0800 Subject: [PATCH 11/13] logging changes --- .../commands/levelup/LevelUpCommandManager.java | 5 +++-- .../nossr50/commands/levelup/PowerLevelUpCommand.java | 10 ++++------ .../nossr50/commands/levelup/SkillLevelUpCommand.java | 9 +++------ 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java index c1ae12a909..d5b714abbd 100644 --- a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java +++ b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java @@ -3,6 +3,7 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.LogUtils; import org.jetbrains.annotations.NotNull; import java.util.HashSet; @@ -28,13 +29,13 @@ public LevelUpCommandManager(@NotNull mcMMO plugin) { public void registerCommand(@NotNull SkillLevelUpCommand skillLevelUpCommand) { requireNonNull(skillLevelUpCommand, "skillLevelUpCommand cannot be null"); skillLevelCommands.add(skillLevelUpCommand); - mcMMO.p.getLogger().info("Registered level up command - SkillLevelUpCommand: " + skillLevelUpCommand); + LogUtils.debug(mcMMO.p.getLogger(), "Registered level up command - SkillLevelUpCommand: " + skillLevelUpCommand); } public void registerCommand(@NotNull PowerLevelUpCommand powerLevelUpCommand) { requireNonNull(powerLevelUpCommand, "powerLevelUpCommand cannot be null"); powerLevelUpCommands.add(powerLevelUpCommand); - mcMMO.p.getLogger().info("Registered level up command - PowerLevelUpCommand: " + powerLevelUpCommand); + LogUtils.debug(mcMMO.p.getLogger(), "Registered level up command - PowerLevelUpCommand: " + powerLevelUpCommand); } /** diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/PowerLevelUpCommand.java b/src/main/java/com/gmail/nossr50/commands/levelup/PowerLevelUpCommand.java index 754eff0f29..5d97a5d3ca 100644 --- a/src/main/java/com/gmail/nossr50/commands/levelup/PowerLevelUpCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/levelup/PowerLevelUpCommand.java @@ -44,15 +44,12 @@ public void process(McMMOPlayer player, Set levelsGained) { } public void executeCommand(McMMOPlayer player, int level) { - // TODO: Change this to debug later - mcMMO.p.getLogger().info("Executing commands for level up: " + commands); + LogUtils.debug(mcMMO.p.getLogger(), "Executing commands for level up: " + commands); for (String command : commands) { - // TODO: Change this to debug later - mcMMO.p.getLogger().info("Executing command: " + command); + LogUtils.debug(mcMMO.p.getLogger(), "Executing command: " + command); String injectedCommand = injectedCommand(command, player, level); - // TODO: Remove verbose logging later if (!injectedCommand.equalsIgnoreCase(command)) { - mcMMO.p.getLogger().info(("Command has been injected with new values: " + injectedCommand)); + LogUtils.debug(mcMMO.p.getLogger(), ("Command has been injected with new values: " + injectedCommand)); } Bukkit.dispatchCommand(Bukkit.getConsoleSender(), injectedCommand); } @@ -61,6 +58,7 @@ public void executeCommand(McMMOPlayer player, int level) { private String injectedCommand(String command, McMMOPlayer player, int level) { // replace %player% with player name, %skill% with skill name, and %level% with level command = safeReplace(command, "%player%", player.getPlayer().getName()); + command = safeReplace(command, "%power_level%", "power level"); command = safeReplace(command, "%skill%", "power level"); command = safeReplace(command, "%level%", String.valueOf(level)); return command; diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/SkillLevelUpCommand.java b/src/main/java/com/gmail/nossr50/commands/levelup/SkillLevelUpCommand.java index 798abbe67c..246bb0d215 100644 --- a/src/main/java/com/gmail/nossr50/commands/levelup/SkillLevelUpCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/levelup/SkillLevelUpCommand.java @@ -45,15 +45,12 @@ public void process(McMMOPlayer player, PrimarySkillType primarySkillType, Set Date: Sat, 17 Feb 2024 16:22:22 -0800 Subject: [PATCH 12/13] fix annotation --- .../java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java b/src/main/java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java index dcac847bc5..8ace6035e4 100644 --- a/src/main/java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java +++ b/src/main/java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java @@ -66,7 +66,7 @@ protected void loadKeys() { } } - private @NotNull SkillLevelUpCommand buildSkillLevelUpCommand(final ConfigurationSection commandSection) { + private @Nullable SkillLevelUpCommand buildSkillLevelUpCommand(final ConfigurationSection commandSection) { SkillLevelUpCommandBuilder builder = new SkillLevelUpCommandBuilder(); // check if command is enabled if (!commandSection.getBoolean(ENABLED, true)) { @@ -171,6 +171,7 @@ protected void loadKeys() { + commandSection.getName()); return null; } + builder.withLevels(levels); // commands From 9b5be855fd09056e1a81d6e6ee12925b6da63a32 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 18 Feb 2024 15:45:51 -0800 Subject: [PATCH 13/13] (WIP) reworking level up commands to have multiple requirements --- .../commands/levelup/LevelUpCommand.java | 114 +++++++ .../levelup/LevelUpCommandBuilder.java | 79 +++++ .../levelup/LevelUpCommandManager.java | 55 +--- .../commands/levelup/PowerLevelUpCommand.java | 96 ------ .../levelup/PowerLevelUpCommandBuilder.java | 59 ---- .../commands/levelup/SkillLevelUpCommand.java | 96 ------ .../levelup/SkillLevelUpCommandBuilder.java | 82 ----- .../config/CommandOnLevelUpConfig.java | 224 +++++--------- .../gmail/nossr50/listeners/SelfListener.java | 3 +- src/main/resources/levelupcommands.yml | 29 +- .../commands/levelup/LevelUpCommandTest.java | 291 +++++++++++------- 11 files changed, 486 insertions(+), 642 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java create mode 100644 src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandBuilder.java delete mode 100644 src/main/java/com/gmail/nossr50/commands/levelup/PowerLevelUpCommand.java delete mode 100644 src/main/java/com/gmail/nossr50/commands/levelup/PowerLevelUpCommandBuilder.java delete mode 100644 src/main/java/com/gmail/nossr50/commands/levelup/SkillLevelUpCommand.java delete mode 100644 src/main/java/com/gmail/nossr50/commands/levelup/SkillLevelUpCommandBuilder.java diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java new file mode 100644 index 0000000000..1e88f81587 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java @@ -0,0 +1,114 @@ +package com.gmail.nossr50.commands.levelup; + +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.LogUtils; +import org.bukkit.Bukkit; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.VisibleForTesting; + +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.function.BiPredicate; +import java.util.function.Predicate; + +public class LevelUpCommand implements CommandsOnLevel { + private final @Nullable List> conditions; + private final @Nullable Predicate powerLevelCondition; + private final boolean logInfo; + private final @NotNull LinkedList commands; + + public LevelUpCommand(@Nullable List> conditions, + @Nullable Predicate powerLevelCondition, + @NotNull LinkedList commands, boolean logInfo) { + this.conditions = conditions; + this.powerLevelCondition = powerLevelCondition; + if (conditions == null && powerLevelCondition == null) + throw new IllegalArgumentException("At least one condition must be set"); + this.commands = commands; + this.logInfo = logInfo; + } + + public void process(@NotNull McMMOPlayer player, @NotNull PrimarySkillType primarySkillType, @NotNull Set levelsGained, + @NotNull Set powerLevelsGained) { + // each predicate has to pass at least once + // we check the predicates against all levels gained to see if they pass at least once + // if all predicates pass at least once, we execute the command + boolean allConditionsPass = (conditions == null) || conditions.stream().allMatch(predicate -> levelsGained.stream().anyMatch(level -> predicate.test(primarySkillType, level))); + // we also check the power level predicate to see if it passes at least once, if this predicate is null, we mark it as passed + boolean powerLevelConditionPass = (powerLevelCondition == null) || powerLevelsGained.stream().anyMatch(powerLevelCondition); + if (allConditionsPass && powerLevelConditionPass) { + executeCommand(player); + } + } + + @VisibleForTesting + void executeCommand(@NotNull McMMOPlayer player) { + LogUtils.debug(mcMMO.p.getLogger(), "Executing level up commands: " + commands); + for (String command : commands) { + LogUtils.debug(mcMMO.p.getLogger(), "Executing command: " + command); + String injectedCommand = injectedCommand(command, player); + if (!injectedCommand.equalsIgnoreCase(command)) { + LogUtils.debug(mcMMO.p.getLogger(), ("Command has been injected with new values: " + injectedCommand)); + } + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), injectedCommand); + } + } + + @VisibleForTesting + String injectedCommand(String command, McMMOPlayer player) { + // TODO: unit tests + StringBuilder commandBuilder = new StringBuilder(command); + + // Replace %player% with player name + replaceAll(commandBuilder, "{@player}", player.getPlayer().getName()); + + // Replace each skill level + for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if (primarySkillType == PrimarySkillType.SMELTING || primarySkillType == PrimarySkillType.SALVAGE) { + continue; + } + replaceAll(commandBuilder, "{@" + primarySkillType.name().toLowerCase() + "_level}", + String.valueOf(player.getSkillLevel(primarySkillType))); + } + + // Replace power level + replaceAll(commandBuilder, "{@power_level}", String.valueOf(player.getPowerLevel())); + + return commandBuilder.toString(); + } + + private void replaceAll(StringBuilder builder, String from, String to) { + int index = builder.indexOf(from); + while (index != -1) { + builder.replace(index, index + from.length(), to); + index = builder.indexOf(from, index + to.length()); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + LevelUpCommand that = (LevelUpCommand) o; + return logInfo == that.logInfo && Objects.equals(conditions, that.conditions) && Objects.equals(commands, that.commands); + } + + @Override + public int hashCode() { + return Objects.hash(conditions, logInfo, commands); + } + + @Override + public String toString() { + return "SkillLevelUpCommand{" + + "conditions=" + conditions + + ", logInfo=" + logInfo + + ", commands=" + commands + + '}'; + } +} diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandBuilder.java b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandBuilder.java new file mode 100644 index 0000000000..d3366e2a85 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandBuilder.java @@ -0,0 +1,79 @@ +package com.gmail.nossr50.commands.levelup; + +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.function.BiPredicate; +import java.util.function.Predicate; + +import static java.util.Objects.requireNonNull; + +public class LevelUpCommandBuilder { + private LinkedList commands = null; + private List> conditions = null; + private Predicate powerLevelCondition = null; + private boolean logInfo; + + public LevelUpCommandBuilder() { + this.logInfo = false; + } + + public LevelUpCommandBuilder withPredicate(BiPredicate condition) { + if (this.conditions == null) { + this.conditions = new LinkedList<>(); + } + + conditions.add(condition); + return this; + } + + public LevelUpCommandBuilder withPowerLevelCondition(Predicate powerLevelCondition) { + if (this.powerLevelCondition != null) { + throw new IllegalStateException("power level condition already set"); + } + + this.powerLevelCondition = powerLevelCondition; + return this; + } + + public LevelUpCommandBuilder withConditions( + @NotNull Collection> conditions) { + if (this.conditions == null) { + this.conditions = new LinkedList<>(); + } else { + throw new IllegalStateException("conditions already set"); + } + + this.conditions.addAll(conditions); + return this; + } + + public LevelUpCommandBuilder withLogInfo(boolean logInfo) { + this.logInfo = logInfo; + return this; + } + + public LevelUpCommandBuilder command(@NotNull String command) { + this.commands = new LinkedList<>(); + this.commands.add(command); + return this; + } + + public LevelUpCommandBuilder commands(@NotNull Collection command) { + this.commands = new LinkedList<>(command); + return this; + } + + public LevelUpCommand build() { + if (conditions == null && powerLevelCondition == null) { + throw new IllegalStateException("no conditions found for level up command"); + } + requireNonNull(commands, "no commands found for level up command"); + + return new LevelUpCommand(conditions, powerLevelCondition, commands, logInfo); + } +} diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java index d5b714abbd..056ec67715 100644 --- a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java +++ b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java @@ -16,26 +16,18 @@ * Manages commands to be executed on level up */ public class LevelUpCommandManager { - private final @NotNull Set skillLevelCommands; - private final @NotNull Set powerLevelUpCommands; + private final @NotNull Set levelUpCommands; private final @NotNull mcMMO plugin; public LevelUpCommandManager(@NotNull mcMMO plugin) { this.plugin = requireNonNull(plugin, "plugin cannot be null"); - this.skillLevelCommands = new HashSet<>(); - this.powerLevelUpCommands = new HashSet<>(); + this.levelUpCommands = new HashSet<>(); } - public void registerCommand(@NotNull SkillLevelUpCommand skillLevelUpCommand) { - requireNonNull(skillLevelUpCommand, "skillLevelUpCommand cannot be null"); - skillLevelCommands.add(skillLevelUpCommand); - LogUtils.debug(mcMMO.p.getLogger(), "Registered level up command - SkillLevelUpCommand: " + skillLevelUpCommand); - } - - public void registerCommand(@NotNull PowerLevelUpCommand powerLevelUpCommand) { - requireNonNull(powerLevelUpCommand, "powerLevelUpCommand cannot be null"); - powerLevelUpCommands.add(powerLevelUpCommand); - LogUtils.debug(mcMMO.p.getLogger(), "Registered level up command - PowerLevelUpCommand: " + powerLevelUpCommand); + public void registerCommand(@NotNull LevelUpCommand levelUpCommand) { + requireNonNull(levelUpCommand, "skillLevelUpCommand cannot be null"); + levelUpCommands.add(levelUpCommand); + LogUtils.debug(mcMMO.p.getLogger(), "Registered level up command - SkillLevelUpCommand: " + levelUpCommand); } /** @@ -45,32 +37,19 @@ public void registerCommand(@NotNull PowerLevelUpCommand powerLevelUpCommand) { * @param primarySkillType the skill type * @param levelsGained the levels gained */ - public void applySkillLevelUp(@NotNull McMMOPlayer mmoPlayer, @NotNull PrimarySkillType primarySkillType, Set levelsGained) { + public void applySkillLevelUp(@NotNull McMMOPlayer mmoPlayer, @NotNull PrimarySkillType primarySkillType, + Set levelsGained, Set powerLevelsGained) { if (!mmoPlayer.getPlayer().isOnline()) { return; } - for (SkillLevelUpCommand command : skillLevelCommands) { - command.process(mmoPlayer, primarySkillType, levelsGained); + for (LevelUpCommand command : levelUpCommands) { + command.process(mmoPlayer, primarySkillType, levelsGained, powerLevelsGained); } } - public void applyPowerLevelUp(@NotNull McMMOPlayer mmoPlayer, Set levelsGained) { - if (!mmoPlayer.getPlayer().isOnline()) { - return; - } - - for (PowerLevelUpCommand command : powerLevelUpCommands) { - command.process(mmoPlayer, levelsGained); - } - } - - public @NotNull Set getSkillLevelCommands() { - return skillLevelCommands; - } - - public @NotNull Set getPowerLevelUpCommands() { - return powerLevelUpCommands; + public @NotNull Set getLevelUpCommands() { + return levelUpCommands; } /** @@ -78,8 +57,7 @@ public void applyPowerLevelUp(@NotNull McMMOPlayer mmoPlayer, Set level */ public void clear() { mcMMO.p.getLogger().info("Clearing registered commands on level up"); - skillLevelCommands.clear(); - powerLevelUpCommands.clear(); + levelUpCommands.clear(); } @Override @@ -87,19 +65,18 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; LevelUpCommandManager that = (LevelUpCommandManager) o; - return Objects.equals(skillLevelCommands, that.skillLevelCommands) && Objects.equals(powerLevelUpCommands, that.powerLevelUpCommands) && Objects.equals(plugin, that.plugin); + return Objects.equals(levelUpCommands, that.levelUpCommands) && Objects.equals(plugin, that.plugin); } @Override public int hashCode() { - return Objects.hash(skillLevelCommands, powerLevelUpCommands, plugin); + return Objects.hash(levelUpCommands, plugin); } @Override public String toString() { return "LevelUpCommandManager{" + - "skillLevelCommands=" + skillLevelCommands + - ", powerLevelUpCommands=" + powerLevelUpCommands + + "levelUpCommands=" + levelUpCommands + ", plugin=" + plugin + '}'; } diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/PowerLevelUpCommand.java b/src/main/java/com/gmail/nossr50/commands/levelup/PowerLevelUpCommand.java deleted file mode 100644 index 5d97a5d3ca..0000000000 --- a/src/main/java/com/gmail/nossr50/commands/levelup/PowerLevelUpCommand.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.gmail.nossr50.commands.levelup; - -import com.gmail.nossr50.datatypes.player.McMMOPlayer; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.LogUtils; -import org.bukkit.Bukkit; -import org.jetbrains.annotations.NotNull; - -import java.util.LinkedList; -import java.util.Objects; -import java.util.Set; -import java.util.function.Predicate; - -public class PowerLevelUpCommand implements CommandsOnLevel { - private final Predicate predicate; - private final boolean logInfo; - private final @NotNull LinkedList commands; - - public PowerLevelUpCommand(@NotNull Predicate predicate, @NotNull String command, boolean logInfo) { - this.predicate = predicate; - this.commands = new LinkedList<>(); - this.commands.add(command); - this.logInfo = logInfo; - } - - public PowerLevelUpCommand(@NotNull Predicate predicate, @NotNull LinkedList commands, boolean logInfo) { - this.predicate = predicate; - this.commands = commands; - this.logInfo = logInfo; - } - - public void process(McMMOPlayer player, Set levelsGained) { - for (int i : levelsGained) { - if (predicate.test(i)) { - // execute command via server console in Bukkit - if(logInfo) { - mcMMO.p.getLogger().info("Executing command: " + commands); - } else { - LogUtils.debug(mcMMO.p.getLogger(), "Executing command: " + commands); - } - executeCommand(player, i); - } - } - } - - public void executeCommand(McMMOPlayer player, int level) { - LogUtils.debug(mcMMO.p.getLogger(), "Executing commands for level up: " + commands); - for (String command : commands) { - LogUtils.debug(mcMMO.p.getLogger(), "Executing command: " + command); - String injectedCommand = injectedCommand(command, player, level); - if (!injectedCommand.equalsIgnoreCase(command)) { - LogUtils.debug(mcMMO.p.getLogger(), ("Command has been injected with new values: " + injectedCommand)); - } - Bukkit.dispatchCommand(Bukkit.getConsoleSender(), injectedCommand); - } - } - - private String injectedCommand(String command, McMMOPlayer player, int level) { - // replace %player% with player name, %skill% with skill name, and %level% with level - command = safeReplace(command, "%player%", player.getPlayer().getName()); - command = safeReplace(command, "%power_level%", "power level"); - command = safeReplace(command, "%skill%", "power level"); - command = safeReplace(command, "%level%", String.valueOf(level)); - return command; - } - - private String safeReplace(String targetStr, String toReplace, String replacement) { - if (replacement == null) { - return targetStr; - } - - return targetStr.replace(toReplace, replacement); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - PowerLevelUpCommand that = (PowerLevelUpCommand) o; - return logInfo == that.logInfo && Objects.equals(predicate, that.predicate) && Objects.equals(commands, that.commands); - } - - @Override - public int hashCode() { - return Objects.hash(predicate, logInfo, commands); - } - - @Override - public String toString() { - return "PowerLevelUpCommand{" + - "predicate=" + predicate + - ", logInfo=" + logInfo + - ", commands=" + commands + - '}'; - } -} diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/PowerLevelUpCommandBuilder.java b/src/main/java/com/gmail/nossr50/commands/levelup/PowerLevelUpCommandBuilder.java deleted file mode 100644 index a80c0251ee..0000000000 --- a/src/main/java/com/gmail/nossr50/commands/levelup/PowerLevelUpCommandBuilder.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.gmail.nossr50.commands.levelup; - -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; -import java.util.LinkedList; -import java.util.Set; -import java.util.function.Predicate; - -import static java.util.Objects.requireNonNull; - -public class PowerLevelUpCommandBuilder { - private Set levels = null; - private LinkedList commands = null; - private Predicate predicate = null; - private boolean logInfo; - - public PowerLevelUpCommandBuilder() { - this.logInfo = false; - } - - public PowerLevelUpCommandBuilder withPredicate(Predicate predicate) { - this.predicate = predicate; - return this; - } - - public PowerLevelUpCommandBuilder withLogInfo(boolean logInfo) { - this.logInfo = logInfo; - return this; - } - - public PowerLevelUpCommandBuilder command(@NotNull String command) { - this.commands = new LinkedList<>(); - this.commands.add(command); - return this; - } - - public PowerLevelUpCommandBuilder commands(@NotNull Collection command) { - this.commands = new LinkedList<>(command); - return this; - } - - public PowerLevelUpCommandBuilder withLevels(@NotNull Collection levels) { - requireNonNull(levels, "levels is null!"); - this.levels = Set.copyOf(levels); - return this; - } - - public PowerLevelUpCommand build() { - requireNonNull(commands, "commandStr is null"); - if (predicate == null) { - requireNonNull(levels, "levels is null"); - - return new PowerLevelUpCommand((level) -> levels.contains(level), commands, logInfo); - } - - return new PowerLevelUpCommand(predicate, commands, logInfo); - } -} diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/SkillLevelUpCommand.java b/src/main/java/com/gmail/nossr50/commands/levelup/SkillLevelUpCommand.java deleted file mode 100644 index 246bb0d215..0000000000 --- a/src/main/java/com/gmail/nossr50/commands/levelup/SkillLevelUpCommand.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.gmail.nossr50.commands.levelup; - -import com.gmail.nossr50.datatypes.player.McMMOPlayer; -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.LogUtils; -import org.bukkit.Bukkit; -import org.jetbrains.annotations.NotNull; - -import java.util.LinkedList; -import java.util.Objects; -import java.util.Set; -import java.util.function.BiPredicate; - -public class SkillLevelUpCommand implements CommandsOnLevel { - private final BiPredicate predicate; - private final boolean logInfo; - private final @NotNull LinkedList commands; - - public SkillLevelUpCommand(@NotNull BiPredicate predicate, @NotNull String command, boolean logInfo) { - this.predicate = predicate; - this.commands = new LinkedList<>(); - this.commands.add(command); - this.logInfo = logInfo; - } - - public SkillLevelUpCommand(@NotNull BiPredicate predicate, @NotNull LinkedList commands, boolean logInfo) { - this.predicate = predicate; - this.commands = commands; - this.logInfo = logInfo; - } - - public void process(McMMOPlayer player, PrimarySkillType primarySkillType, Set levelsGained) { - for (int i : levelsGained) { - if (predicate.test(primarySkillType, i)) { - // execute command via server console in Bukkit - if(logInfo) { - mcMMO.p.getLogger().info("Executing command: " + commands); - } else { - LogUtils.debug(mcMMO.p.getLogger(), "Executing command: " + commands); - } - executeCommand(player, primarySkillType, i); - } - } - } - - public void executeCommand(McMMOPlayer player, PrimarySkillType primarySkillType, int level) { - LogUtils.debug(mcMMO.p.getLogger(), "Executing commands for level up: " + commands); - for (String command : commands) { - LogUtils.debug(mcMMO.p.getLogger(), "Executing command: " + command); - String injectedCommand = injectedCommand(command, player, primarySkillType, level); - if (!injectedCommand.equalsIgnoreCase(command)) { - LogUtils.debug(mcMMO.p.getLogger(), ("Command has been injected with new values: " + injectedCommand)); - } - Bukkit.dispatchCommand(Bukkit.getConsoleSender(), injectedCommand); - } - } - - private String injectedCommand(String command, McMMOPlayer player, PrimarySkillType primarySkillType, int level) { - // replace %player% with player name, %skill% with skill name, and %level% with level - command = safeReplace(command, "%player%", player.getPlayer().getName()); - command = safeReplace(command, "%skill%", primarySkillType.getName()); - command = safeReplace(command, "%level%", String.valueOf(level)); - return command; - } - - private String safeReplace(String targetStr, String toReplace, String replacement) { - if (replacement == null) { - return targetStr; - } - - return targetStr.replace(toReplace, replacement); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - SkillLevelUpCommand that = (SkillLevelUpCommand) o; - return logInfo == that.logInfo && Objects.equals(predicate, that.predicate) && Objects.equals(commands, that.commands); - } - - @Override - public int hashCode() { - return Objects.hash(predicate, logInfo, commands); - } - - @Override - public String toString() { - return "LevelUpCommandImpl{" + - "predicate=" + predicate + - ", logInfo=" + logInfo + - ", commandStr='" + commands + '\'' + - '}'; - } -} diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/SkillLevelUpCommandBuilder.java b/src/main/java/com/gmail/nossr50/commands/levelup/SkillLevelUpCommandBuilder.java deleted file mode 100644 index 98b731d969..0000000000 --- a/src/main/java/com/gmail/nossr50/commands/levelup/SkillLevelUpCommandBuilder.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.gmail.nossr50.commands.levelup; - -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; -import java.util.LinkedList; -import java.util.Set; -import java.util.function.BiPredicate; - -import static java.util.Objects.requireNonNull; - -public class SkillLevelUpCommandBuilder { - private Set skillFilter = null; - private Set levels = null; - private LinkedList commands = null; - private BiPredicate predicate = null; - private boolean logInfo; - - public SkillLevelUpCommandBuilder() { - this.logInfo = false; - } - - public SkillLevelUpCommandBuilder withPredicate(BiPredicate predicate) { - this.predicate = predicate; - return this; - } - - public SkillLevelUpCommandBuilder withLogInfo(boolean logInfo) { - this.logInfo = logInfo; - return this; - } - - public SkillLevelUpCommandBuilder command(@NotNull String command) { - this.commands = new LinkedList<>(); - this.commands.add(command); - return this; - } - - public SkillLevelUpCommandBuilder commands(@NotNull Collection command) { - this.commands = new LinkedList<>(command); - return this; - } - - public SkillLevelUpCommandBuilder withLevels(@NotNull Collection levels) { - requireNonNull(levels, "levels is null!"); - this.levels = Set.copyOf(levels); - return this; - } - - public SkillLevelUpCommandBuilder withSkillFilter(@NotNull Set skillFilter) { - requireNonNull(skillFilter, "skillFilter is null!"); - if (skillFilter.isEmpty()) { - throw new IllegalArgumentException("skillFilter is empty"); - } - this.skillFilter = skillFilter; - return this; - } - - public SkillLevelUpCommandBuilder withSkillFilter(@NotNull PrimarySkillType skill) { - requireNonNull(skill, "skill is null!"); - this.skillFilter = Set.of(skill); - return this; - } - - public SkillLevelUpCommand build() { - requireNonNull(commands, "commandStr is null"); - if (predicate == null) { - requireNonNull(levels, "levels is null"); - - return new SkillLevelUpCommand((skill, level) -> { - if (skillFilter == null) { - return levels.contains(level); - } else { - return skillFilter.contains(skill) && levels.contains(level); - } - }, commands, logInfo); - } - - return new SkillLevelUpCommand(predicate, commands, logInfo); - } -} diff --git a/src/main/java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java b/src/main/java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java index 8ace6035e4..4fbc3a8b93 100644 --- a/src/main/java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java +++ b/src/main/java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java @@ -1,9 +1,7 @@ package com.gmail.nossr50.config; -import com.gmail.nossr50.commands.levelup.PowerLevelUpCommand; -import com.gmail.nossr50.commands.levelup.PowerLevelUpCommandBuilder; -import com.gmail.nossr50.commands.levelup.SkillLevelUpCommand; -import com.gmail.nossr50.commands.levelup.SkillLevelUpCommandBuilder; +import com.gmail.nossr50.commands.levelup.LevelUpCommand; +import com.gmail.nossr50.commands.levelup.LevelUpCommandBuilder; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.LogUtils; @@ -48,153 +46,89 @@ protected void loadKeys() { continue; } - SkillLevelUpCommand skillLevelUpCommand = buildSkillLevelUpCommand(commandSection); - PowerLevelUpCommand powerLevelUpCommand = buildPowerLevelUpCommand(commandSection); + LevelUpCommand levelUpCommand = buildSkillLevelUpCommand(commandSection); - if (skillLevelUpCommand == null && powerLevelUpCommand == null) { + if (levelUpCommand == null) { mcMMO.p.getLogger().severe("Invalid command format for key: " + key); } else { - if(skillLevelUpCommand != null) { - mcMMO.p.getLevelUpCommandManager().registerCommand(skillLevelUpCommand); - mcMMO.p.getLogger().info("Skill Level up command successfully loaded from config for key: " + key); - } - if(powerLevelUpCommand != null) { - mcMMO.p.getLevelUpCommandManager().registerCommand(powerLevelUpCommand); - mcMMO.p.getLogger().info("Power Level up command successfully loaded from config for key: " + key); - } + mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); + mcMMO.p.getLogger().info("Level up command successfully loaded from config for key: " + key); } } } - private @Nullable SkillLevelUpCommand buildSkillLevelUpCommand(final ConfigurationSection commandSection) { - SkillLevelUpCommandBuilder builder = new SkillLevelUpCommandBuilder(); - // check if command is enabled - if (!commandSection.getBoolean(ENABLED, true)) { - return null; - } - /* Condition Section */ - ConfigurationSection condition = commandSection.getConfigurationSection(CONDITION_SECTION); - if (condition == null) { - mcMMO.p.getLogger().severe("No condition section found for command named " + commandSection.getName()); - return null; - } - - // Skill Filter - // check if skills is string or configuration section - if (condition.contains(SKILLS_SECTION)) { - if (condition.isString(SKILLS_SECTION)) { - String skillName = condition.getString(SKILLS_SECTION); - if (skillName != null) { - PrimarySkillType primarySkillType = mcMMO.p.getSkillTools().matchSkill(skillName); - if (primarySkillType != null) { - builder.withSkillFilter(getSkillsFromFilter(new HashSet<>(Set.of(skillName)))); - } - } - } else { - ConfigurationSection skillsSection = condition.getConfigurationSection(SKILLS_SECTION); - if (skillsSection != null) { - Set skillNames = skillsSection.getKeys(false); - Set skillsFromFilter = getSkillsFromFilter(skillNames); - if (skillsFromFilter.isEmpty()) { - LogUtils.debug(mcMMO.p.getLogger(), "No valid skills found for command named " - + commandSection.getName() + "for condition section named " + skillsSection.getName()); - } else { - builder.withSkillFilter(skillsFromFilter); - } - } - } - } - - // for now only simple condition is supported - if (!condition.contains(LEVELS_SECTION)) { - mcMMO.p.getLogger().severe("No condition.levels section found for command named " + commandSection.getName()); - return null; - } - - Collection levels = condition.getIntegerList(LEVELS_SECTION); - if (levels.isEmpty()) { - mcMMO.p.getLogger().severe("No valid levels found in condition.levels for command named " - + commandSection.getName()); - return null; - } - builder.withLevels(levels); - - // commands - if (commandSection.isString(COMMANDS)) { - String command = commandSection.getString(COMMANDS); - if (command != null) { - builder.command(command); - } - } else { - List commands = commandSection.getStringList(COMMANDS); - if (commands.isEmpty()) { - mcMMO.p.getLogger().severe("No commands defined for command named " - + commandSection.getName()); - return null; - } else { - builder.commands(commands); - } - } - - return builder.build(); - } - - private @Nullable PowerLevelUpCommand buildPowerLevelUpCommand(final ConfigurationSection commandSection) { - PowerLevelUpCommandBuilder builder = new PowerLevelUpCommandBuilder(); - // check if command is enabled - if (!commandSection.getBoolean(ENABLED, true)) { - return null; - } - - /* Condition Section */ - ConfigurationSection condition = commandSection.getConfigurationSection(CONDITION_SECTION); - if (condition == null) { - mcMMO.p.getLogger().severe("No condition section found for command named " + commandSection.getName()); - return null; - } - - // No power level condition - if (!condition.contains(POWER_LEVEL_SECTION)) { - return null; - } - - // for now only simple condition is supported - if (!condition.contains(LEVELS_SECTION)) { - mcMMO.p.getLogger().severe("No condition.levels section found for power level command named " - + commandSection.getName()); - return null; - } - - Collection levels = condition.getIntegerList(LEVELS_SECTION); - if (levels.isEmpty()) { - mcMMO.p.getLogger().severe("No valid levels found in condition.levels for power level command named " - + commandSection.getName()); - return null; - } - - builder.withLevels(levels); - - // commands - if (commandSection.isString(COMMANDS)) { - String command = commandSection.getString(COMMANDS); - if (command != null) { - builder.command(command); - } - } else { - List commands = commandSection.getStringList(COMMANDS); - if (commands.isEmpty()) { - mcMMO.p.getLogger().severe("No commands defined for power level command named " - + commandSection.getName()); - return null; - } else { - builder.commands(commands); - } - } - - return builder.build(); - } - - private Set getSkillsFromFilter(Set skillFilter) { - return mcMMO.p.getSkillTools().matchSkills(skillFilter); + private @Nullable LevelUpCommand buildSkillLevelUpCommand(final ConfigurationSection commandSection) { + // TODO: Rework + return null; +// LevelUpCommandBuilder builder = new LevelUpCommandBuilder(); +// // check if command is enabled +// if (!commandSection.getBoolean(ENABLED, true)) { +// return null; +// } +// /* Condition Section */ +// ConfigurationSection condition = commandSection.getConfigurationSection(CONDITION_SECTION); +// if (condition == null) { +// mcMMO.p.getLogger().severe("No condition section found for command named " + commandSection.getName()); +// return null; +// } +// +// // Skill Filter +// // check if skills is string or configuration section +// if (condition.contains(SKILLS_SECTION)) { +// if (condition.isString(SKILLS_SECTION)) { +// String skillName = condition.getString(SKILLS_SECTION); +// if (skillName != null) { +// PrimarySkillType primarySkillType = mcMMO.p.getSkillTools().matchSkill(skillName); +// if (primarySkillType != null) { +// builder.withSkillFilter(getSkillsFromFilter(new HashSet<>(Set.of(skillName)))); +// } +// } +// } else { +// ConfigurationSection skillsSection = condition.getConfigurationSection(SKILLS_SECTION); +// if (skillsSection != null) { +// Set skillNames = skillsSection.getKeys(false); +// Set skillsFromFilter = getSkillsFromFilter(skillNames); +// if (skillsFromFilter.isEmpty()) { +// LogUtils.debug(mcMMO.p.getLogger(), "No valid skills found for command named " +// + commandSection.getName() + "for condition section named " + skillsSection.getName()); +// } else { +// builder.withSkillFilter(skillsFromFilter); +// } +// } +// } +// } +// +// // for now only simple condition is supported +// if (!condition.contains(LEVELS_SECTION)) { +// mcMMO.p.getLogger().severe("No condition.levels section found for command named " + commandSection.getName()); +// return null; +// } +// +// Collection levels = condition.getIntegerList(LEVELS_SECTION); +// if (levels.isEmpty()) { +// mcMMO.p.getLogger().severe("No valid levels found in condition.levels for command named " +// + commandSection.getName()); +// return null; +// } +// builder.withLevels(levels); +// +// // commands +// if (commandSection.isString(COMMANDS)) { +// String command = commandSection.getString(COMMANDS); +// if (command != null) { +// builder.command(command); +// } +// } else { +// List commands = commandSection.getStringList(COMMANDS); +// if (commands.isEmpty()) { +// mcMMO.p.getLogger().severe("No commands defined for command named " +// + commandSection.getName()); +// return null; +// } else { +// builder.commands(commands); +// } +// } +// +// return builder.build(); } } diff --git a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java index dce1bc44b1..7c7f98de3b 100644 --- a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java @@ -70,8 +70,7 @@ public void onPlayerLevelUp(McMMOPlayerLevelUpEvent event) { powerLevelsAchieved.add(startingPowerLevel + (i + 1)); } - plugin.getLevelUpCommandManager().applySkillLevelUp(mcMMOPlayer, skill, levelsAchieved); - plugin.getLevelUpCommandManager().applyPowerLevelUp(mcMMOPlayer, powerLevelsAchieved); + plugin.getLevelUpCommandManager().applySkillLevelUp(mcMMOPlayer, skill, levelsAchieved, powerLevelsAchieved); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) diff --git a/src/main/resources/levelupcommands.yml b/src/main/resources/levelupcommands.yml index eeb390013a..3f8481258e 100644 --- a/src/main/resources/levelupcommands.yml +++ b/src/main/resources/levelupcommands.yml @@ -1,32 +1,23 @@ level_up_commands: - unique_id_here: + woodcutting_and_swords_command: enabled: true condition: - skills: - - 'Swords' - - 'Axes' - levels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + swords: + levels: [10, 100] + woodcutting: + levels: [10, 100] commands: - - "say %player% reached level %level%!" + - "say {@player} reached level {@swords_level} in swords, and {@woodcutting_level} in woodcutting!" - "say Isn't that nice?" run_command_as: 'CONSOLE' log_level: 'INFO' - other_unique_id_here: - enabled: true - condition: - levels: [1, 2, 3, 4, 5] - commands: - - "say this command should execute for all skills, %player%!" - - "say Isn't that fun?" - run_command_as: 'CONSOLE' - log_level: 'DEBUG' power_level_milestones: enabled: true condition: - power_level: true - levels: [ 10, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 2000, 3000, 4000, 5000, 10000, 20000 ] + power_level: + levels: [ 1000, 2000, 3000, 4000, 5000 ] commands: - - "say %player% has reached a power level milestone!" - - "say %player% is now at power level %level%!" + - "say {@player} has reached a power level milestone!" + - "say {@player} is now at power level {@power_level}!" run_command_as: 'CONSOLE' log_level: 'DEBUG' diff --git a/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java b/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java index 59cd22a6ef..6499a80ca5 100644 --- a/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java +++ b/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java @@ -9,28 +9,32 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.EventUtils; import org.bukkit.Bukkit; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import java.util.List; import java.util.UUID; import java.util.function.BiPredicate; import java.util.function.Predicate; +import static com.gmail.nossr50.datatypes.skills.PrimarySkillType.MINING; +import static com.gmail.nossr50.datatypes.skills.PrimarySkillType.WOODCUTTING; +import static java.util.Objects.requireNonNull; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; class LevelUpCommandTest extends MMOTestEnvironmentBasic { - private final PrimarySkillType mining = PrimarySkillType.MINING; - private final PrimarySkillType woodcutting = PrimarySkillType.WOODCUTTING; + private static final BiPredicate ALWAYS_TRUE = (skill, level) -> true; private McMMOPlayer mmoPlayer; private final String playerName = "Momshroom"; @BeforeEach void beforeEach() { - mcMMO.p.getLevelUpCommandManager().getSkillLevelCommands().clear(); - mcMMO.p.getLevelUpCommandManager().getPowerLevelUpCommands().clear(); + mcMMO.p.getLevelUpCommandManager().getLevelUpCommands().clear(); this.mmoPlayer = getMMOPlayer(UUID.randomUUID(), playerName, 0); } @@ -38,73 +42,96 @@ void beforeEach() { @Test void skillLevelUpShouldRunFiveTimes() { // GIVEN level up command for Mining should always execute for Mining level up - assert mcMMO.p.getLevelUpCommandManager().getSkillLevelCommands().isEmpty(); + assert mcMMO.p.getLevelUpCommandManager().getLevelUpCommands().isEmpty(); final String commandStr = "say hello"; - final SkillLevelUpCommand levelUpCommand - = buildSkillLevelUpCommand(commandStr, (s, ignored) -> s == mining); + final LevelUpCommand levelUpCommand = buildLevelUpCommand(commandStr, + (skill, skillLevel) -> skill == MINING && skillLevel >= 1 && skillLevel <= 5); + mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); // WHEN player gains 5 levels in mining via command - levelPlayerViaXP(mmoPlayer, mining, 5); + levelPlayerViaXP(mmoPlayer, MINING, 5); // THEN the command should be checked for execution - verify(levelUpCommandManager, atLeastOnce()).applySkillLevelUp(any(), any(), any()); - verify(levelUpCommand, atLeastOnce()).process(any(), any(), any()); + verify(levelUpCommandManager, atLeastOnce()).applySkillLevelUp(any(), any(), any(), any()); + verify(levelUpCommand, atLeastOnce()).process(any(), any(), any(), any()); // THEN the command should have executed - verify(levelUpCommand, times(5)).executeCommand(any(McMMOPlayer.class), any(PrimarySkillType.class), anyInt()); + verify(levelUpCommand, times(5)).executeCommand(any(McMMOPlayer.class)); mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), any()), atLeast(5)); } + @Test + void dualRequirementsShouldRunOnce() { + // GIVEN + assert mcMMO.p.getLevelUpCommandManager().getLevelUpCommands().isEmpty(); + final String commandStr = "say hello"; + BiPredicate predicate = (skill, skillLevel) -> skill == MINING && skillLevel == 3; + BiPredicate predicate2 = (skill, skillLevel) -> skill == WOODCUTTING && skillLevel == 3; + final LevelUpCommand levelUpCommand = buildLevelUpCommand(commandStr, List.of(predicate, predicate2)); + + mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); + + // WHEN player gains 5 levels in mining and woodcutting via command + levelPlayerViaXP(mmoPlayer, MINING, 5); + levelPlayerViaXP(mmoPlayer, WOODCUTTING, 5); + + // THEN the command should be checked for execution + verify(levelUpCommandManager, atLeastOnce()).applySkillLevelUp(any(), any(), any(), any()); + verify(levelUpCommand, times(10)).process(any(), any(), any(), any()); + + // THEN the command should have executed + verify(levelUpCommand, times(1)).executeCommand(any(McMMOPlayer.class)); + mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), any()), atLeast(1)); + } + @Test void skillLevelUpViaXPGainShouldRunFiveTimes() { // GIVEN level up command for Mining should always execute for Mining level up - assert mcMMO.p.getLevelUpCommandManager().getSkillLevelCommands().isEmpty(); + assert mcMMO.p.getLevelUpCommandManager().getLevelUpCommands().isEmpty(); final String commandStr = "say hello"; - final SkillLevelUpCommand levelUpCommand - = buildSkillLevelUpCommand(commandStr, (s, ignored) -> s == mining); + final LevelUpCommand levelUpCommand = buildLevelUpCommand(commandStr, + (skill, skillLevel) -> skill == MINING && skillLevel >= 1 && skillLevel <= 5); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); // WHEN player gains 5 levels in mining via command - levelPlayerViaXP(mmoPlayer, mining, 5); + levelPlayerViaXP(mmoPlayer, MINING, 5); // THEN the command should be checked for execution - verify(levelUpCommandManager, times(5)).applySkillLevelUp(any(), any(), any()); - verify(levelUpCommand, times(5)).process(any(), any(), any()); + verify(levelUpCommandManager, times(5)).applySkillLevelUp(any(), any(), any(), any()); + verify(levelUpCommand, times(5)).process(any(), any(), any(), any()); // THEN the command should have executed - verify(levelUpCommand, times(5)).executeCommand(any(McMMOPlayer.class), any(PrimarySkillType.class), anyInt()); + verify(levelUpCommand, times(5)).executeCommand(any(McMMOPlayer.class)); mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), any()), atLeast(5)); } @Test void skillLevelUpViaXPGainShouldRunCommandFiveTimesWithPlaceholders() { // GIVEN level up command for Mining should always execute for Mining level up - assert mcMMO.p.getLevelUpCommandManager().getSkillLevelCommands().isEmpty(); + assert mcMMO.p.getLevelUpCommandManager().getLevelUpCommands().isEmpty(); assertEquals(mmoPlayer.getPlayer().getName(), playerName); - final String commandStr = "say hello %player%, you have reached level %level%"; + final String commandStr = "say hello {@player}, you have reached level {@mining_level}"; final String expectedStr1 = "say hello " + playerName + ", you have reached level 1"; final String expectedStr2 = "say hello " + playerName + ", you have reached level 2"; final String expectedStr3 = "say hello " + playerName + ", you have reached level 3"; final String expectedStr4 = "say hello " + playerName + ", you have reached level 4"; final String expectedStr5 = "say hello " + playerName + ", you have reached level 5"; - final SkillLevelUpCommand levelUpCommand - = buildSkillLevelUpCommand(commandStr, (s, ignored) -> s == mining); + final LevelUpCommand levelUpCommand = buildLevelUpCommand(commandStr, + (skill, skillLevel) -> skill == MINING && skillLevel >= 1 && skillLevel <= 5); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); // WHEN player gains 5 levels in mining via command - assertEquals(0, mmoPlayer.getSkillLevel(mining)); + assertEquals(0, mmoPlayer.getSkillLevel(MINING)); int levelsGained = 5; - for (int i = 0; i < 5; i++) { - mmoPlayer.applyXpGain(mining, mmoPlayer.getProfile().getXpToLevel(mining), XPGainReason.COMMAND, XPGainSource.COMMAND); - } + levelPlayerViaXP(mmoPlayer, MINING, levelsGained); // THEN the command should be checked for execution - verify(levelUpCommandManager, times(levelsGained)).applySkillLevelUp(any(), any(), any()); - verify(levelUpCommand, times(levelsGained)).process(any(), any(), any()); + verify(levelUpCommandManager, times(levelsGained)).applySkillLevelUp(any(), any(), any(), any()); + verify(levelUpCommand, times(levelsGained)).process(any(), any(), any(), any()); // THEN the command should have executed - verify(levelUpCommand, times(levelsGained)).executeCommand(any(McMMOPlayer.class), any(PrimarySkillType.class), anyInt()); + verify(levelUpCommand, times(levelsGained)).executeCommand(any(McMMOPlayer.class)); mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), any()), atLeast(5)); // AND THEN the message for each level up should have happened at least once // verify that Bukkit.dispatchCommand got executed at least 5 times with the correct injectedCommand @@ -116,64 +143,110 @@ void skillLevelUpViaXPGainShouldRunCommandFiveTimesWithPlaceholders() { } @Test - void skillLevelUpShouldRunCommandFiveTimesWithPlaceholders() { + void skillLevelUpShouldRunCommandThreeTimesWithPlaceholders() { + /* + This test executes a player leveling up 5 times. + With level 3 separate registered level up commands. + Each registered command runs only once. + */ // GIVEN level up command for Mining should always execute for Mining level up - assert mcMMO.p.getLevelUpCommandManager().getSkillLevelCommands().isEmpty(); + assert mcMMO.p.getLevelUpCommandManager().getLevelUpCommands().isEmpty(); assertEquals(mmoPlayer.getPlayer().getName(), playerName); - final String commandStr = "say hello %player%"; + final String commandStr = "say hello {@player}"; final String expectedStr = "say hello " + playerName; - final SkillLevelUpCommand levelUpCommand - = buildSkillLevelUpCommand(commandStr, (s, ignored) -> s == mining); - mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); + final LevelUpCommand levelUpCommandOne = buildLevelUpCommand(commandStr, (skill, level) -> skill == MINING && level == 1); + mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommandOne); + final LevelUpCommand levelUpCommandTwo = buildLevelUpCommand(commandStr, (skill, level) -> skill == MINING && level == 2); + mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommandTwo); + final LevelUpCommand levelUpCommandThree = buildLevelUpCommand(commandStr, (skill, level) -> skill == MINING && level == 3); + mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommandThree); int levelsGained = 5; // WHEN player gains 5 levels in mining - McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(mmoPlayer.getPlayer(), mining, levelsGained, XPGainReason.PVE); - selfListener.onPlayerLevelUp(event); + levelPlayerViaXP(mmoPlayer, MINING, levelsGained); // THEN the command should be checked for execution - verify(levelUpCommandManager).applySkillLevelUp(any(), any(), any()); - verify(levelUpCommand).process(any(), any(), any()); + verify(levelUpCommandManager, times(levelsGained)).applySkillLevelUp(any(), any(), any(), any()); + verify(levelUpCommandOne, times(levelsGained)).process(any(), any(), any(), any()); + verify(levelUpCommandTwo, times(levelsGained)).process(any(), any(), any(), any()); + verify(levelUpCommandThree, times(levelsGained)).process(any(), any(), any(), any()); // THEN the command should have executed - verify(levelUpCommand, times(levelsGained)).executeCommand(any(McMMOPlayer.class), any(PrimarySkillType.class), anyInt()); - // verify that Bukkit.dispatchCommand got executed at least 5 times with the correct injectedCommand - mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), eq(expectedStr)), atLeast(5)); + verify(levelUpCommandOne, times(1)).executeCommand(any(McMMOPlayer.class)); + verify(levelUpCommandTwo, times(1)).executeCommand(any(McMMOPlayer.class)); + verify(levelUpCommandThree, times(1)).executeCommand(any(McMMOPlayer.class)); + // verify that Bukkit.dispatchCommand got executed at least 20 times with the correct injectedCommand + mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), eq(expectedStr)), atLeast(3)); } @Test - void skillLevelUpViaAddLevelsShouldRunCommandFiveTimesWithPlaceholdersForLevel() { + void skillLevelUpShouldRunCommandFourTimesWithPlaceholders() { + /* + This test executes a player leveling up 5 times. + With level 3 separate registered level up commands. + One command runs twice, the others run once. + */ // GIVEN level up command for Mining should always execute for Mining level up - assert mcMMO.p.getLevelUpCommandManager().getSkillLevelCommands().isEmpty(); + assert mcMMO.p.getLevelUpCommandManager().getLevelUpCommands().isEmpty(); assertEquals(mmoPlayer.getPlayer().getName(), playerName); - final String commandStr = "say hello %player%, you have reached level %level%"; + final String commandStr = "say hello {@player}"; + final String expectedStr = "say hello " + playerName; + final LevelUpCommand levelUpCommandOne = buildLevelUpCommand(commandStr, (skill, level) -> skill == MINING && (level == 1 || level == 4)); + mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommandOne); + final LevelUpCommand levelUpCommandTwo = buildLevelUpCommand(commandStr, (skill, level) -> skill == MINING && level == 2); + mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommandTwo); + final LevelUpCommand levelUpCommandThree = buildLevelUpCommand(commandStr, (skill, level) -> skill == MINING && level == 3); + mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommandThree); + int levelsGained = 5; + + // WHEN player gains 5 levels in mining + levelPlayerViaXP(mmoPlayer, MINING, levelsGained); + + // THEN the command should be checked for execution + verify(levelUpCommandManager, times(levelsGained)).applySkillLevelUp(any(), any(), any(), any()); + verify(levelUpCommandOne, times(levelsGained)).process(any(), any(), any(), any()); + verify(levelUpCommandTwo, times(levelsGained)).process(any(), any(), any(), any()); + verify(levelUpCommandThree, times(levelsGained)).process(any(), any(), any(), any()); + // THEN the command should have executed + verify(levelUpCommandOne, times(2)).executeCommand(any(McMMOPlayer.class)); + verify(levelUpCommandTwo, times(1)).executeCommand(any(McMMOPlayer.class)); + verify(levelUpCommandThree, times(1)).executeCommand(any(McMMOPlayer.class)); + // verify that Bukkit.dispatchCommand got executed at least 20 times with the correct injectedCommand + mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), eq(expectedStr)), atLeast(3)); + } + + @Test + void addLevelsShouldRunCommandFiveTimesWithPlaceholdersForLevel() { + // GIVEN level up command for Mining should always execute for Mining level up + assert mcMMO.p.getLevelUpCommandManager().getLevelUpCommands().isEmpty(); + assertEquals(mmoPlayer.getPlayer().getName(), playerName); + + final String commandStr = "say hello {@player}, you have reached level {@mining_level}"; final String expectedStr1 = "say hello " + playerName + ", you have reached level 1"; final String expectedStr2 = "say hello " + playerName + ", you have reached level 2"; final String expectedStr3 = "say hello " + playerName + ", you have reached level 3"; final String expectedStr4 = "say hello " + playerName + ", you have reached level 4"; final String expectedStr5 = "say hello " + playerName + ", you have reached level 5"; - final SkillLevelUpCommand levelUpCommand - = buildSkillLevelUpCommand(commandStr, (s, ignored) -> s == mining); - mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); + final LevelUpCommand levelUpCommand = buildLevelUpCommand(commandStr, (skill, ignored) -> skill == MINING); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); // WHEN player gains 5 levels in mining int levelsGained = 5; - mmoPlayer.getProfile().addLevels(mining, levelsGained); + mmoPlayer.getProfile().addLevels(MINING, levelsGained); EventUtils.tryLevelChangeEvent( mmoPlayer.getPlayer(), - mining, + MINING, levelsGained, - mmoPlayer.getProfile().getSkillXpLevelRaw(mining), + mmoPlayer.getProfile().getSkillXpLevelRaw(MINING), true, XPGainReason.COMMAND); // THEN the command should be checked for execution - verify(levelUpCommandManager).applySkillLevelUp(any(), any(), any()); - verify(levelUpCommand).process(any(), any(), any()); + verify(levelUpCommandManager).applySkillLevelUp(any(), any(), any(), any()); + verify(levelUpCommand).process(any(), any(), any(), any()); // THEN the command should have executed - verify(levelUpCommand, times(levelsGained)).executeCommand(any(McMMOPlayer.class), any(PrimarySkillType.class), anyInt()); + verify(levelUpCommand, times(1)).executeCommand(any(McMMOPlayer.class)); // verify that Bukkit.dispatchCommand got executed at least 5 times with the correct injectedCommand mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), eq(expectedStr1))); mockedBukkit.verify(() -> Bukkit.dispatchCommand(any(), eq(expectedStr2))); @@ -185,118 +258,128 @@ void skillLevelUpViaAddLevelsShouldRunCommandFiveTimesWithPlaceholdersForLevel() @Test void skillLevelUpShouldRunCommandAtLeastOnce() { // GIVEN level up command for Mining should always execute for Mining level up - assert mcMMO.p.getLevelUpCommandManager().getSkillLevelCommands().isEmpty(); + assert mcMMO.p.getLevelUpCommandManager().getLevelUpCommands().isEmpty(); final String commandStr = "say hello"; - final SkillLevelUpCommand levelUpCommand - = buildSkillLevelUpCommand(commandStr, (s, ignored) -> s == mining); + final LevelUpCommand levelUpCommand = buildLevelUpCommand(commandStr, (skill, ignored) -> skill == MINING); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); int levelsGained = 1; // WHEN player gains 5 levels in mining - McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(mmoPlayer.getPlayer(), mining, levelsGained, XPGainReason.PVE); + McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(mmoPlayer.getPlayer(), MINING, levelsGained, XPGainReason.PVE); selfListener.onPlayerLevelUp(event); // THEN the command should be checked for execution - verify(levelUpCommandManager).applySkillLevelUp(any(), any(), any()); - verify(levelUpCommand).process(any(), any(), any()); + verify(levelUpCommandManager).applySkillLevelUp(any(), any(), any(), any()); + verify(levelUpCommand).process(any(), any(), any(), any()); // THEN the command should have executed - verify(levelUpCommand).executeCommand(any(McMMOPlayer.class), any(PrimarySkillType.class), anyInt()); + verify(levelUpCommand).executeCommand(any(McMMOPlayer.class)); } @Test void skillLevelUpShouldNotRunCommand() { // GIVEN level up command for Woodcutting should not execute for Mining level up - assert mcMMO.p.getLevelUpCommandManager().getSkillLevelCommands().isEmpty(); + assert mcMMO.p.getLevelUpCommandManager().getLevelUpCommands().isEmpty(); final String commandStr = "say hello"; - final SkillLevelUpCommand levelUpCommand - = buildSkillLevelUpCommand(commandStr, (s, ignored) -> s == woodcutting); + final LevelUpCommand levelUpCommand = buildLevelUpCommand(commandStr, (skill, ignored) -> skill == WOODCUTTING); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); int levelsGained = 5; // WHEN player gains 5 levels in mining - McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(mmoPlayer.getPlayer(), mining, levelsGained, XPGainReason.PVE); + McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(mmoPlayer.getPlayer(), MINING, levelsGained, XPGainReason.PVE); selfListener.onPlayerLevelUp(event); // THEN the command should be checked for execution - verify(levelUpCommandManager).applySkillLevelUp(any(), any(), any()); - verify(levelUpCommand).process(any(), any(), any()); + verify(levelUpCommandManager).applySkillLevelUp(any(), any(), any(), any()); + verify(levelUpCommand).process(any(), any(), any(), any()); // THEN the command should not be run - verify(levelUpCommand, never()).executeCommand(any(McMMOPlayer.class), any(PrimarySkillType.class), anyInt()); + verify(levelUpCommand, never()).executeCommand(any(McMMOPlayer.class)); } @Test - public void skillLevelUpShouldAlwaysRunPowerlevelCommand() { - // GIVEN level up command for power level should always execute for any level up - assert mcMMO.p.getLevelUpCommandManager().getSkillLevelCommands().isEmpty(); + public void levelUpShouldAlwaysRunCommand() { + // GIVEN level up command should always execute for any level up + assert mcMMO.p.getLevelUpCommandManager().getLevelUpCommands().isEmpty(); final String commandStr = "say hello"; - final PowerLevelUpCommand powerLevelUpCommand - = buildPowerLevelUpCommand(commandStr, (i) -> true); - mcMMO.p.getLevelUpCommandManager().registerCommand(powerLevelUpCommand); + final LevelUpCommand levelUpCommand = buildLevelUpCommand(commandStr, ALWAYS_TRUE); + mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); // WHEN player gains 10 levels - levelPlayerViaXP(mmoPlayer, mining, 10); + levelPlayerViaXP(mmoPlayer, MINING, 10); // THEN the command should be checked for execution - verify(levelUpCommandManager, atLeastOnce()).applyPowerLevelUp(any(), any()); - verify(powerLevelUpCommand, atLeastOnce()).process(any(), any()); + verify(levelUpCommandManager, atLeastOnce()).applySkillLevelUp(any(), eq(MINING), any(), any()); + verify(levelUpCommand, atLeastOnce()).process(any(), any(), any(), any()); // THEN the command should have executed - verify(powerLevelUpCommand, times(10)).executeCommand(any(McMMOPlayer.class), anyInt()); + verify(levelUpCommand, times(10)).executeCommand(any(McMMOPlayer.class)); } @Test public void skillLevelUpShouldRunPowerlevelCommandOnce() { // GIVEN level up command for power level should always execute for any level up - assert mcMMO.p.getLevelUpCommandManager().getSkillLevelCommands().isEmpty(); + assert mcMMO.p.getLevelUpCommandManager().getLevelUpCommands().isEmpty(); final String commandStr = "say hello"; - final PowerLevelUpCommand powerLevelUpCommand - = buildPowerLevelUpCommand(commandStr, (i) -> i == 5); + final LevelUpCommand powerLevelUpCommand = buildLevelUpCommand(commandStr, + (ignoredA, ignoredB) -> true, (powerlevel) -> powerlevel == 3); mcMMO.p.getLevelUpCommandManager().registerCommand(powerLevelUpCommand); // WHEN player gains 5 levels - levelPlayerViaXP(mmoPlayer, mining, 5); + levelPlayerViaXP(mmoPlayer, MINING, 5); // THEN the command should be checked for execution - verify(levelUpCommandManager, atLeastOnce()).applyPowerLevelUp(any(), any()); - verify(powerLevelUpCommand, atLeastOnce()).process(any(), any()); + verify(levelUpCommandManager, atLeastOnce()).applySkillLevelUp(any(), any(), any(), any()); + verify(powerLevelUpCommand, atLeastOnce()).process(any(), any(), any(), any()); // THEN the command should have executed - verify(powerLevelUpCommand, times(1)).executeCommand(any(McMMOPlayer.class), anyInt()); + verify(powerLevelUpCommand, times(1)).executeCommand(any(McMMOPlayer.class)); } - private SkillLevelUpCommand buildSkillLevelUpCommand(String commandStr, BiPredicate predicate) { - final SkillLevelUpCommandBuilder builder = new SkillLevelUpCommandBuilder(); + private LevelUpCommand buildLevelUpCommand(@NotNull String commandStr, + @NotNull List> conditions, + @Nullable Predicate powerLevelCondition) { + requireNonNull(commandStr, "commandStr cannot be null"); + requireNonNull(conditions, "conditions cannot be null"); + final var builder = new LevelUpCommandBuilder(); + if (powerLevelCondition != null) { + builder.withPowerLevelCondition(powerLevelCondition); + } builder.command(commandStr) - .withPredicate(predicate) + .withConditions(conditions) .withLogInfo(true); return Mockito.spy(builder.build()); } - private PowerLevelUpCommand buildPowerLevelUpCommand(String commandStr, Predicate predicate) { - final PowerLevelUpCommandBuilder builder = new PowerLevelUpCommandBuilder(); + private LevelUpCommand buildLevelUpCommand(@NotNull String commandStr, + @NotNull List> conditions) { + return buildLevelUpCommand(commandStr, conditions, null); + } + + private LevelUpCommand buildLevelUpCommand(@NotNull String commandStr, + @NotNull BiPredicate predicate, + @Nullable Predicate powerLevelCondition) { + requireNonNull(commandStr, "commandStr cannot be null"); + requireNonNull(predicate, "predicate cannot be null"); + final var builder = new LevelUpCommandBuilder(); + if (powerLevelCondition != null) { + builder.withPowerLevelCondition(powerLevelCondition); + } builder.command(commandStr) .withPredicate(predicate) .withLogInfo(true); return Mockito.spy(builder.build()); } - private void levelPlayerViaXP(McMMOPlayer mmoPlayer, PrimarySkillType skill, int levelsGained) { - assertEquals(0, mmoPlayer.getSkillLevel(skill)); - for (int i = 0; i < levelsGained; i++) { - mmoPlayer.applyXpGain(mining, mmoPlayer.getProfile().getXpToLevel(skill), XPGainReason.COMMAND, XPGainSource.COMMAND); - } - assertEquals(levelsGained, mmoPlayer.getSkillLevel(skill)); + private LevelUpCommand buildLevelUpCommand(@NotNull String commandStr, + @NotNull BiPredicate predicate) { + return buildLevelUpCommand(commandStr, predicate, null); } - private void levelPlayerViaLevelChangeEvent(McMMOPlayer mmoPlayer, PrimarySkillType skill, int levelsGained) { + private void levelPlayerViaXP(@NotNull McMMOPlayer mmoPlayer, @NotNull PrimarySkillType skill, int levelsGained) { + System.out.println("Leveling " + mmoPlayer.getPlayer().getName() + " up " + levelsGained + " levels in " + skill.getName()); assertEquals(0, mmoPlayer.getSkillLevel(skill)); - EventUtils.tryLevelChangeEvent( - mmoPlayer.getPlayer(), - skill, - levelsGained, - mmoPlayer.getProfile().getSkillXpLevelRaw(skill), - true, - XPGainReason.COMMAND); + for (int i = 0; i < levelsGained; i++) { + mmoPlayer.applyXpGain(skill, mmoPlayer.getProfile().getXpToLevel(skill), XPGainReason.COMMAND, XPGainSource.COMMAND); + } assertEquals(levelsGained, mmoPlayer.getSkillLevel(skill)); } } \ No newline at end of file