From edab455581e17c0b86bebeac6a78b68062f2a481 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 27 Aug 2023 16:19:46 -0700 Subject: [PATCH] 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 f18cd18ca..0f1d8eeed 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 final class ExperienceAPI { * @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 final class ExperienceAPI { * @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 e15063ebf..cf5fce21c 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 929fdcefe..cb350ad81 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 class ExperienceConfig extends BukkitConfig { /* 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 class ExperienceConfig extends BukkitConfig { /* 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 ccf1c991c..af5aa7b74 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 @@ public class Party { 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 a22dd3491..69245f080 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 class McMMOPlayer implements Identified { } 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 976ee3434..432e96e65 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 class PlayerProfile { 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 26640a99f..e72c82194 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 class SelfListener implements Listener { } 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 d421a6870..04f93e96c 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 class mcMMO extends JavaPlugin { 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 331c90f92..2fe1d180a 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 class FormulaConversionTask extends BukkitRunnable { 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 @@ public class FormulaConversionTask extends BukkitRunnable { 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 5d8ed9035..d5aff8b6b 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 final class EventUtils { 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 6685e816b..a120f4b9b 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.datatypes.skills.PrimarySkillType; 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 class FormulaManager { */ //TODO: When the heck is Unknown used? - if (formulaType == FormulaType.UNKNOWN) { + if (formulaType == null || formulaType == FormulaType.UNKNOWN) { formulaType = FormulaType.LINEAR; } @@ -209,18 +222,6 @@ public class FormulaManager { } } - /** - * 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 5ae709683..ac81bc679 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 @@ public class NotificationManager { 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 831b20f17..a260b7ad4 100644 --- a/src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java +++ b/src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java @@ -3,13 +3,18 @@ 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.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.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; @@ -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 @@ public abstract class MMOTestEnvironmentBasic { 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 @@ public abstract class MMOTestEnvironmentBasic { 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 @@ public abstract class MMOTestEnvironmentBasic { mockPermissions(); + mockNotifications(); + mockedRankUtils = Mockito.mockStatic(RankUtils.class); // wire server @@ -132,11 +147,15 @@ public abstract class MMOTestEnvironmentBasic { // 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 @@ public abstract class MMOTestEnvironmentBasic { 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 @@ public abstract class MMOTestEnvironmentBasic { 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 @@ public abstract class MMOTestEnvironmentBasic { // 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 @@ public abstract class MMOTestEnvironmentBasic { 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 cc2dad328..7c47d01e7 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 @@ package com.gmail.nossr50.commands.levelup; 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.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.*; @@ -51,6 +50,71 @@ class LevelUpCommandTest extends MMOTestEnvironmentBasic { 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 @@ class LevelUpCommandTest extends MMOTestEnvironmentBasic { } @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 @@ class LevelUpCommandTest extends MMOTestEnvironmentBasic { 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());