Browse Source

command on level up wip

nossr50 2 years ago
parent
commit
027b79639b

+ 10 - 0
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<Integer> levelsGained);
+}

+ 69 - 0
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<Integer> shouldApply;
+    private final boolean logInfo;
+    private final @NotNull String commandStr;
+
+    private final @NotNull Set<PrimarySkillType> skills;
+
+    public LevelUpCommandImpl(@NotNull Predicate<Integer> shouldApply, @NotNull String commandStr, @NotNull Set<PrimarySkillType> skills, boolean logInfo) {
+        this.shouldApply = shouldApply;
+        this.commandStr = commandStr;
+        this.skills = skills;
+        this.logInfo = logInfo;
+    }
+
+    @Override
+    public void apply(McMMOPlayer player, PrimarySkillType primarySkillType, Set<Integer> 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 +
+                '}';
+    }
+}

+ 43 - 0
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<LevelUpCommand> 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<Integer> 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();
+    }
+}

+ 17 - 0
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() {
+
+    }
+}

+ 1 - 0
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;

+ 15 - 3
src/main/java/com/gmail/nossr50/listeners/SelfListener.java

@@ -20,6 +20,11 @@ import org.bukkit.event.EventHandler;
 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 class SelfListener implements Listener {
 
     @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 class SelfListener implements Listener {
             if(mcMMO.p.getGeneralConfig().getScoreboardsEnabled())
                 ScoreboardManager.handleLevelUp(player, skill);
         }
+
+        final Set<Integer> 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)

+ 13 - 9
src/main/java/com/gmail/nossr50/mcMMO.java

@@ -2,6 +2,7 @@ package com.gmail.nossr50;
 
 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 class mcMMO extends JavaPlugin {
 
             //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 class mcMMO extends JavaPlugin {
     public @NotNull AdvancedConfig getAdvancedConfig() {
         return advancedConfig;
     }
+
+    public @NotNull CommandOnLevelUpConfig getCommandOnLevelUpConfig() {
+        return commandOnLevelUpConfig;
+    }
+
+    public @NotNull LevelUpCommandManager getLevelUpCommandManager() {
+        return levelUpCommandManager;
+    }
 }

+ 23 - 0
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'

+ 230 - 0
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<mcMMO> mockedMcMMO;
+    protected MockedStatic<Bukkit> mockedBukkit;
+    protected MockedStatic<ChatConfig> mockedChatConfig;
+    protected MockedStatic<ExperienceConfig> experienceConfig;
+    protected MockedStatic<Permissions> mockedPermissions;
+    protected MockedStatic<RankUtils> mockedRankUtils;
+    protected MockedStatic<UserManager> mockedUserManager;
+    protected MockedStatic<Misc> mockedMisc;
+    protected MockedStatic<SkillTools> mockedSkillTools;
+    protected MockedStatic<EventUtils> 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();
+        }
+    }
+}

+ 62 - 0
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<Integer> 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());
+    }
+}