Skip to content

Commit

Permalink
Add power level commands to commands on level up
Browse files Browse the repository at this point in the history
nossr50 committed Jan 29, 2024
1 parent c5ec99a commit 847095a
Showing 12 changed files with 537 additions and 248 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.gmail.nossr50.commands.levelup;

public interface CommandsOnLevel {
}
105 changes: 0 additions & 105 deletions src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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<LevelUpCommand> commands;
private final @NotNull Set<SkillLevelUpCommand> skillLevelCommands;
private final @NotNull Set<PowerLevelUpCommand> 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,48 +44,61 @@ 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<Integer> levelsGained) {
public void applySkillLevelUp(@NotNull McMMOPlayer mmoPlayer, @NotNull PrimarySkillType primarySkillType, Set<Integer> 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<Integer> levelsGained) {
if (!mmoPlayer.getPlayer().isOnline()) {
return;
}

for (PowerLevelUpCommand command : powerLevelUpCommands) {
command.process(mmoPlayer, levelsGained);
}
}

public @NotNull Set<SkillLevelUpCommand> getSkillLevelCommands() {
return skillLevelCommands;
}

public @NotNull Set<PowerLevelUpCommand> 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
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 +
'}';
}
Original file line number Diff line number Diff line change
@@ -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<Integer> predicate;
private final boolean logInfo;
private final @NotNull LinkedList<String> commands;

public PowerLevelUpCommand(@NotNull Predicate<Integer> predicate, @NotNull String command, boolean logInfo) {
this.predicate = predicate;
this.commands = new LinkedList<>();
this.commands.add(command);
this.logInfo = logInfo;
}

public PowerLevelUpCommand(@NotNull Predicate<Integer> predicate, @NotNull LinkedList<String> commands, boolean logInfo) {
this.predicate = predicate;
this.commands = commands;
this.logInfo = logInfo;
}

public void process(McMMOPlayer player, Set<Integer> 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 +
'}';
}
}
Original file line number Diff line number Diff line change
@@ -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<Integer> levels = null;
private LinkedList<String> commands = null;
private Predicate<Integer> predicate = null;
private boolean logInfo;

public PowerLevelUpCommandBuilder() {
this.logInfo = false;
}

public PowerLevelUpCommandBuilder withPredicate(Predicate<Integer> 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<String> command) {
this.commands = new LinkedList<>(command);
return this;
}

public PowerLevelUpCommandBuilder withLevels(@NotNull Collection<Integer> 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);
}
}
Original file line number Diff line number Diff line change
@@ -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<PrimarySkillType, Integer> predicate;
private final boolean logInfo;
private final @NotNull LinkedList<String> commands;

public LevelUpCommandImpl(@NotNull BiPredicate<PrimarySkillType, Integer> predicate, @NotNull String command, boolean logInfo) {
public SkillLevelUpCommand(@NotNull BiPredicate<PrimarySkillType, Integer> predicate, @NotNull String command, boolean logInfo) {
this.predicate = predicate;
this.commands = new LinkedList<>();
this.commands.add(command);
this.logInfo = logInfo;
}

public LevelUpCommandImpl(@NotNull BiPredicate<PrimarySkillType, Integer> predicate, @NotNull LinkedList<String> commands, boolean logInfo) {
public SkillLevelUpCommand(@NotNull BiPredicate<PrimarySkillType, Integer> predicate, @NotNull LinkedList<String> commands, boolean logInfo) {
this.predicate = predicate;
this.commands = commands;
this.logInfo = logInfo;
}

@Override
public void process(McMMOPlayer player, PrimarySkillType primarySkillType, Set<Integer> 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);
}

Original file line number Diff line number Diff line change
@@ -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<PrimarySkillType> skillFilter = null;
private Set<Integer> levels = null;
private LinkedList<String> commands = null;
private BiPredicate<PrimarySkillType, Integer> predicate = null;
private boolean logInfo;

public SkillLevelUpCommandBuilder() {
this.logInfo = false;
}

public SkillLevelUpCommandBuilder withPredicate(BiPredicate<PrimarySkillType, Integer> 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<String> command) {
this.commands = new LinkedList<>(command);
return this;
}

public SkillLevelUpCommandBuilder withLevels(@NotNull Collection<Integer> levels) {
requireNonNull(levels, "levels is null!");
this.levels = Set.copyOf(levels);
return this;
}

public SkillLevelUpCommandBuilder withSkillFilter(@NotNull Set<PrimarySkillType> 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);
}
}
82 changes: 73 additions & 9 deletions src/main/java/com/gmail/nossr50/config/CommandOnLevelUpConfig.java
Original file line number Diff line number Diff line change
@@ -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<Integer> 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<String> 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<PrimarySkillType> getSkillsFromFilter(Set<String> skillFilter) {
return mcMMO.p.getSkillTools().matchSkills(skillFilter);
}
Original file line number Diff line number Diff line change
@@ -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;
9 changes: 8 additions & 1 deletion src/main/java/com/gmail/nossr50/listeners/SelfListener.java
Original file line number Diff line number Diff line change
@@ -60,11 +60,18 @@ public void onPlayerLevelUp(McMMOPlayerLevelUpEvent event) {
}

final Set<Integer> levelsAchieved = new LinkedHashSet<>();
final Set<Integer> 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)
56 changes: 28 additions & 28 deletions src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
213 changes: 138 additions & 75 deletions src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java

Large diffs are not rendered by default.

0 comments on commit 847095a

Please sign in to comment.