Endgame Update (#4840)

General
Added Crossbows Skill, this skill is a WIP and feedback on discord is appreciated.
Added Tridents Skill, this skill is a WIP and feedback on discord is appreciated.
Added the "endgame" triple drop subskill 'Mother Lode' to Mining
Added the "endgame" triple drop subskill 'Clean Cuts' to Woodcutting
Added the "endgame" triple drop subskill 'Verdant Bounty' to Herbalism
Added /mmopower command which simply shows your power level (aliases /mmopowerlevel /powerlevel)

Config
Added 'Send_To_Console' settings to chat.yml to toggle sending party or admin chat messages to console.
Replaced 'Experience_Formula.Modifier' in experience.yml with 'Experience_Formula.Skill_Multiplier' which is easier to understand and less prone to divide by zero bugs.
child.yml config is gone now, feel free to delete it.

Tweaks
Tree Feller now drops 90% less non-wood block rewards (leaves/etc) on average from Knock on Wood.
Treasure drop rate from Shake, Fishing, Hylian, and Excavation now benefit from the Luck perk.
Updated advanced.yml with entries for the new skills

Permission nodes
Added 'mcmmo.commands.mmopower' permission node for the new /mmopower command
Added 'mcmmo.commands.crossbows' permission node
Added 'mcmmo.ability.crossbows.crossbowslimitbreak' permission node
Added 'mcmmo.ability.crossbows.trickshot' permission node
Added 'mcmmo.ability.herbalism.verdantbounty' permission node
Added 'mcmmo.ability.mining.motherlode' permission node
Added 'mcmmo.ability.woodcutting.cleancuts' permission node

Locale
Added locale entries for motherlode, cleancuts, and verdant bounty.

Codebase
Major rewrite for how random chance was handled in the code.
Many skills with RNG elements now send out a SubSkillEvent (which can be used to modify probability or cancel the results), some skills without RNG still send out this event when activated, this event is cancellable so it can be used to make a skill fail.
A lot of new unit tests were added to help keep mcMMO stable as part of this update, of course, more could always be added.

NOTES:
One feature of this update is to provide an endgame benefits to some skills that you can grind for a long time, ideally for a long while. I will likely expand upon this idea in future updates.
A few skills have these endgame-oriented subskills, these new subskills provide a small benefit at first that grows and scales up to level 10,000 (or 1,000 for Standard mode which no one uses) and does not have ranks (other than the initial rank to unlock it).
These endgame sub skills unlock at level 1000 for users with default mcMMO settings, or 100 for those using the optional Standard scaling.
You can tweak the benefits of these skills in advanced.yml, the default settings are meant to be a good starting point.

Crossbows and Tridents are WIP skills, I would like feedback on discord about them.

More info on the new Triple Drop skills (Mother Lode, Clean Cuts, Verdant Bounty):
Currently these start at about 5%  chance and can reach a maximum 50% chance if a player acquired 10,000 skill, you can adjust this in advanced.yml
These skills respect double drop settings from config.yml just like the corresponding Double Drop skills do, if a double drop is disabled for an item, then it's disabled for triple drops too.
I added a new Power Level Command, for now this just shows you your current power level. If I ever add features based on power level, this command will likely display output related to those features.

Regarding Maces, I will likely add that as a WIP skill when the next Minecraft update drops.
This commit is contained in:
Robert Alan Chapton
2024-03-30 06:09:59 -07:00
committed by GitHub
parent bead5feb14
commit 2594dc1bca
141 changed files with 3586 additions and 1991 deletions

View File

@@ -0,0 +1,216 @@
package com.gmail.nossr50;
import com.gmail.nossr50.api.exceptions.InvalidSkillException;
import com.gmail.nossr50.config.AdvancedConfig;
import com.gmail.nossr50.config.ChatConfig;
import com.gmail.nossr50.config.GeneralConfig;
import com.gmail.nossr50.config.RankConfig;
import com.gmail.nossr50.config.experience.ExperienceConfig;
import com.gmail.nossr50.config.party.PartyConfig;
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.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.Location;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.World;
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 java.util.logging.Logger;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
public abstract class MMOTestEnvironment {
protected MockedStatic<mcMMO> mockedMcMMO;
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 TransientEntityTracker transientEntityTracker;
protected AdvancedConfig advancedConfig;
protected PartyConfig partyConfig;
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 MaterialMapStore materialMapStore;
protected void mockBaseEnvironment(Logger logger) throws InvalidSkillException {
mockedMcMMO = Mockito.mockStatic(mcMMO.class);
mcMMO.p = Mockito.mock(mcMMO.class);
when(mcMMO.p.getLogger()).thenReturn(logger);
// place store
chunkManager = Mockito.mock(ChunkManager.class);
when(mcMMO.getPlaceStore()).thenReturn(chunkManager);
// shut off mod manager for woodcutting
when(mcMMO.getModManager()).thenReturn(Mockito.mock(ModManager.class));
when(mcMMO.getModManager().isCustomLog(any())).thenReturn(false);
// chat config
mockedChatConfig = Mockito.mockStatic(ChatConfig.class);
when(ChatConfig.getInstance()).thenReturn(Mockito.mock(ChatConfig.class));
// general config
mockGeneralConfig();
// party config
mockPartyConfig();
// rank config
mockRankConfig();
// wire advanced config
mockAdvancedConfig();
// 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 = Mockito.mock(Server.class);
when(mcMMO.p.getServer()).thenReturn(server);
// wire plugin manager
this.pluginManager = Mockito.mock(PluginManager.class);
when(server.getPluginManager()).thenReturn(pluginManager);
// wire world
this.world = Mockito.mock(World.class);
// wire Misc
this.mockedMisc = Mockito.mockStatic(Misc.class);
when(Misc.getBlockCenter(any())).thenReturn(new Location(world, 0, 0, 0));
// setup player and player related mocks after everything else
this.player = Mockito.mock(Player.class);
when(player.getUniqueId()).thenReturn(playerUUID);
// wire inventory
this.playerInventory = Mockito.mock(PlayerInventory.class);
when(player.getInventory()).thenReturn(playerInventory);
// PlayerProfile and McMMOPlayer are partially mocked
playerProfile = new PlayerProfile("testPlayer", player.getUniqueId(), 0);
mmoPlayer = Mockito.spy(new McMMOPlayer(player, playerProfile));
// wire user manager
this.mockedUserManager = Mockito.mockStatic(UserManager.class);
when(UserManager.getPlayer(player)).thenReturn(mmoPlayer);
this.materialMapStore = new MaterialMapStore();
when(mcMMO.getMaterialMapStore()).thenReturn(materialMapStore);
}
private void mockPermissions() {
mockedPermissions = Mockito.mockStatic(Permissions.class);
when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true);
when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn(true);
when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true);
when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn(true);
when(Permissions.lucky(player, PrimarySkillType.WOODCUTTING)).thenReturn(false); // player is not lucky
}
private void mockRankConfig() {
rankConfig = Mockito.mock(RankConfig.class);
}
private void mockAdvancedConfig() {
this.advancedConfig = Mockito.mock(AdvancedConfig.class);
when(mcMMO.p.getAdvancedConfig()).thenReturn(advancedConfig);
}
private void mockGeneralConfig() {
generalConfig = Mockito.mock(GeneralConfig.class);
when(generalConfig.getTreeFellerThreshold()).thenReturn(100);
when(generalConfig.getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, Material.OAK_LOG)).thenReturn(true);
when(generalConfig.getLocale()).thenReturn("en_US");
when(mcMMO.p.getGeneralConfig()).thenReturn(generalConfig);
}
private void mockPartyConfig() {
partyConfig = Mockito.mock(PartyConfig.class);
when(partyConfig.isPartyEnabled()).thenReturn(false);
when(mcMMO.p.getPartyConfig()).thenReturn(partyConfig);
}
private void mockExperienceConfig() {
experienceConfig = Mockito.mockStatic(ExperienceConfig.class);
when(ExperienceConfig.getInstance()).thenReturn(Mockito.mock(ExperienceConfig.class));
// Combat
when(ExperienceConfig.getInstance().getCombatXP("Cow")).thenReturn(1D);
}
protected void cleanupBaseEnvironment() {
// Clean up resources here if needed.
if (mockedMcMMO != null) {
mockedMcMMO.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();
}
}
}

View File

@@ -31,7 +31,6 @@ import java.util.logging.Logger;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.mock;
//This class uses JUnit5/Jupiter
class FlatFileDatabaseManagerTest {
public static final @NotNull String TEST_FILE_NAME = "test.mcmmo.users";
@@ -39,7 +38,7 @@ class FlatFileDatabaseManagerTest {
public static final @NotNull String BAD_DATA_FILE_LINE_TWENTY_THREE = "nossr51:baddata:::baddata:baddata:640:baddata:1000:1000:1000:baddata:baddata:baddata:baddata:16:0:500:20273:0:0:0:0::1000:0:0:baddata:1593543012:0:0:0:0::1000:0:0:baddata:IGNORED:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1:0:";
public static final @NotNull String DB_BADDATA = "baddatadb.users";
public static final @NotNull String DB_HEALTHY = "healthydb.users";
public static final @NotNull String HEALTHY_DB_LINE_1 = "nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:IGNORED:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999:2020:";
public static final @NotNull String HEALTHY_DB_LINE_1 = "nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:IGNORED:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999:2020:140:14:150:15:1111:2222:3333";
public static final @NotNull String HEALTHY_DB_LINE_ONE_UUID_STR = "588fe472-1c82-4c4e-9aa1-7eefccb277e3";
public static final String DB_MISSING_LAST_LOGIN = "missinglastlogin.users";
public static final String LINE_TWO_FROM_MISSING_DB = "nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:0:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999:";
@@ -52,16 +51,19 @@ class FlatFileDatabaseManagerTest {
int expectedLvlMining = 1, expectedLvlWoodcutting = 2, expectedLvlRepair = 3,
expectedLvlUnarmed = 4, expectedLvlHerbalism = 5, expectedLvlExcavation = 6,
expectedLvlArchery = 7, expectedLvlSwords = 8, expectedLvlAxes = 9, expectedLvlAcrobatics = 10,
expectedLvlTaming = 11, expectedLvlFishing = 12, expectedLvlAlchemy = 13;
expectedLvlTaming = 11, expectedLvlFishing = 12, expectedLvlAlchemy = 13, expectedLvlCrossbows = 14,
expectedLvlTridents = 15;
float expectedExpMining = 10, expectedExpWoodcutting = 20, expectedExpRepair = 30,
expectedExpUnarmed = 40, expectedExpHerbalism = 50, expectedExpExcavation = 60,
expectedExpArchery = 70, expectedExpSwords = 80, expectedExpAxes = 90, expectedExpAcrobatics = 100,
expectedExpTaming = 110, expectedExpFishing = 120, expectedExpAlchemy = 130;
expectedExpTaming = 110, expectedExpFishing = 120, expectedExpAlchemy = 130, expectedExpCrossbows = 140,
expectedExpTridents = 150;
long expectedBerserkCd = 111, expectedGigaDrillBreakerCd = 222, expectedTreeFellerCd = 333,
expectedGreenTerraCd = 444, expectedSerratedStrikesCd = 555, expectedSkullSplitterCd = 666,
expectedSuperBreakerCd = 777, expectedBlastMiningCd = 888, expectedChimaeraWingCd = 999;
expectedSuperBreakerCd = 777, expectedBlastMiningCd = 888, expectedChimaeraWingCd = 999,
expectedSuperShotgunCd = 1111, expectedTridentSuperCd = 2222, expectedExplosiveShotCd = 3333;
int expectedScoreboardTips = 1111;
Long expectedLastLogin = 2020L;
@@ -226,7 +228,6 @@ class FlatFileDatabaseManagerTest {
logger.info("File Path: "+healthyDB.getAbsolutePath());
assertArrayEquals(HEALTHY_DB_LINE_1.split(":"), dataFromFile.get(0));
assertEquals(dataFromFile.get(0)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR);
UUID healthDBEntryOneUUID = UUID.fromString(HEALTHY_DB_LINE_ONE_UUID_STR);
db = new FlatFileDatabaseManager(healthyDB, logger, PURGE_TIME, 0, true);
List<FlatFileDataFlag> flagsFound = db.checkFileHealthAndStructure();
@@ -451,14 +452,13 @@ class FlatFileDatabaseManagerTest {
if(SkillTools.isChildSkill(primarySkillType))
continue;
// logger.info("Checking expected values for: "+primarySkillType);
// logger.info("Profile Level Value: "+profile.getSkillLevel(primarySkillType));
// logger.info("Expected Lvl Value: "+getExpectedLevelHealthyDBEntryOne(primarySkillType));
// logger.info("Profile Exp Value: "+profile.getSkillXpLevelRaw(primarySkillType));
// logger.info("Expected Exp Value: "+getExpectedExperienceHealthyDBEntryOne(primarySkillType));
int expectedLevelHealthyDBEntryOne = getExpectedLevelHealthyDBEntryOne(primarySkillType);
int skillLevel = profile.getSkillLevel(primarySkillType);
assertEquals(expectedLevelHealthyDBEntryOne, skillLevel);
assertEquals(getExpectedLevelHealthyDBEntryOne(primarySkillType), profile.getSkillLevel(primarySkillType));
assertEquals(getExpectedExperienceHealthyDBEntryOne(primarySkillType), profile.getSkillXpLevelRaw(primarySkillType), 0);
float expectedExperienceHealthyDBEntryOne = getExpectedExperienceHealthyDBEntryOne(primarySkillType);
float skillXpLevelRaw = profile.getSkillXpLevelRaw(primarySkillType);
assertEquals(expectedExperienceHealthyDBEntryOne, skillXpLevelRaw, 0);
}
//Check the other things
@@ -472,29 +472,24 @@ class FlatFileDatabaseManagerTest {
}
private long getExpectedSuperAbilityDATS(@NotNull SuperAbilityType superAbilityType) {
switch(superAbilityType) {
case BERSERK:
return expectedBerserkCd;
case SUPER_BREAKER:
return expectedSuperBreakerCd;
case GIGA_DRILL_BREAKER:
return expectedGigaDrillBreakerCd;
case GREEN_TERRA:
return expectedGreenTerraCd;
case SKULL_SPLITTER:
return expectedSkullSplitterCd;
case TREE_FELLER:
return expectedTreeFellerCd;
case SERRATED_STRIKES:
return expectedSerratedStrikesCd;
case BLAST_MINING:
return expectedBlastMiningCd;
}
return switch (superAbilityType) {
case BERSERK -> expectedBerserkCd;
case SUPER_BREAKER -> expectedSuperBreakerCd;
case GIGA_DRILL_BREAKER -> expectedGigaDrillBreakerCd;
case GREEN_TERRA -> expectedGreenTerraCd;
case SKULL_SPLITTER -> expectedSkullSplitterCd;
case SUPER_SHOTGUN -> expectedSuperShotgunCd;
case TREE_FELLER -> expectedTreeFellerCd;
case SERRATED_STRIKES -> expectedSerratedStrikesCd;
case BLAST_MINING -> expectedBlastMiningCd;
case TRIDENTS_SUPER_ABILITY -> expectedTridentSuperCd;
case EXPLOSIVE_SHOT -> expectedExplosiveShotCd;
default -> throw new RuntimeException("Values not defined for super ability please add " +
"values for " + superAbilityType.toString() + " to the test");
};
return -1;
}
//TODO: Why is this stuff a float?
private float getExpectedExperienceHealthyDBEntryOne(@NotNull PrimarySkillType primarySkillType) {
switch(primarySkillType) {
case ACROBATICS:
@@ -505,6 +500,8 @@ class FlatFileDatabaseManagerTest {
return expectedExpArchery;
case AXES:
return expectedExpAxes;
case CROSSBOWS:
return expectedExpCrossbows;
case EXCAVATION:
return expectedExpExcavation;
case FISHING:
@@ -522,13 +519,15 @@ class FlatFileDatabaseManagerTest {
return expectedExpSwords;
case TAMING:
return expectedExpTaming;
case TRIDENTS:
return expectedExpTridents;
case UNARMED:
return expectedExpUnarmed;
case WOODCUTTING:
return expectedExpWoodcutting;
}
return -1;
throw new RuntimeException("Values for skill not defined, please add values for " + primarySkillType.toString() + " to the test");
}
private int getExpectedLevelHealthyDBEntryOne(@NotNull PrimarySkillType primarySkillType) {
@@ -541,6 +540,8 @@ class FlatFileDatabaseManagerTest {
return expectedLvlArchery;
case AXES:
return expectedLvlAxes;
case CROSSBOWS:
return expectedLvlCrossbows;
case EXCAVATION:
return expectedLvlExcavation;
case FISHING:
@@ -558,13 +559,15 @@ class FlatFileDatabaseManagerTest {
return expectedLvlSwords;
case TAMING:
return expectedLvlTaming;
case TRIDENTS:
return expectedLvlTridents;
case UNARMED:
return expectedLvlUnarmed;
case WOODCUTTING:
return expectedLvlWoodcutting;
}
return -1;
throw new RuntimeException("Values for skill not defined, please add values for " + primarySkillType.toString() + " to the test");
}
@Test

View File

@@ -0,0 +1,245 @@
package com.gmail.nossr50.database;
import com.gmail.nossr50.config.AdvancedConfig;
import com.gmail.nossr50.config.GeneralConfig;
import com.gmail.nossr50.datatypes.MobHealthbarType;
import com.gmail.nossr50.datatypes.player.PlayerProfile;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.compat.CompatibilityManager;
import com.gmail.nossr50.util.platform.MinecraftGameVersion;
import com.gmail.nossr50.util.skills.SkillTools;
import com.gmail.nossr50.util.upgrade.UpgradeManager;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.*;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import java.util.logging.Logger;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
class SQLDatabaseManagerTest {
private final static @NotNull Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
static MockedStatic<mcMMO> mockedMcMMO;
SQLDatabaseManager sqlDatabaseManager;
static GeneralConfig generalConfig;
static AdvancedConfig advancedConfig;
static UpgradeManager upgradeManager;
static CompatibilityManager compatibilityManager;
static SkillTools skillTools;
@BeforeAll
static void setUpAll() {
// stub mcMMO.p
mockedMcMMO = Mockito.mockStatic(mcMMO.class);
mcMMO.p = Mockito.mock(mcMMO.class);
when(mcMMO.p.getLogger()).thenReturn(logger);
// general config mock
mockGeneralConfig();
// advanced config mock
advancedConfig = Mockito.mock(AdvancedConfig.class);
when(mcMMO.p.getAdvancedConfig()).thenReturn(advancedConfig);
// starting level
when(mcMMO.p.getAdvancedConfig().getStartingLevel()).thenReturn(0);
// wire skill tools
skillTools = new SkillTools(mcMMO.p);
when(mcMMO.p.getSkillTools()).thenReturn(skillTools);
// compatibility manager mock
compatibilityManager = Mockito.mock(CompatibilityManager.class);
when(mcMMO.getCompatibilityManager()).thenReturn(compatibilityManager);
when(compatibilityManager.getMinecraftGameVersion()).thenReturn(new MinecraftGameVersion(1, 20, 4));
// upgrade manager mock
upgradeManager = Mockito.mock(UpgradeManager.class);
when(mcMMO.getUpgradeManager()).thenReturn(upgradeManager);
// don't trigger upgrades
when(mcMMO.getUpgradeManager().shouldUpgrade(any())).thenReturn(false);
}
private static void mockGeneralConfig() {
generalConfig = Mockito.mock(GeneralConfig.class);
when(generalConfig.getLocale()).thenReturn("en_US");
when(mcMMO.p.getGeneralConfig()).thenReturn(generalConfig);
// max pool size
when(mcMMO.p.getGeneralConfig().getMySQLMaxPoolSize(SQLDatabaseManager.PoolIdentifier.MISC))
.thenReturn(10);
when(mcMMO.p.getGeneralConfig().getMySQLMaxPoolSize(SQLDatabaseManager.PoolIdentifier.LOAD))
.thenReturn(20);
when(mcMMO.p.getGeneralConfig().getMySQLMaxPoolSize(SQLDatabaseManager.PoolIdentifier.SAVE))
.thenReturn(20);
// max connections
when(mcMMO.p.getGeneralConfig().getMySQLMaxConnections(SQLDatabaseManager.PoolIdentifier.MISC))
.thenReturn(30);
when(mcMMO.p.getGeneralConfig().getMySQLMaxConnections(SQLDatabaseManager.PoolIdentifier.LOAD))
.thenReturn(30);
when(mcMMO.p.getGeneralConfig().getMySQLMaxConnections(SQLDatabaseManager.PoolIdentifier.SAVE))
.thenReturn(30);
// table prefix
when(mcMMO.p.getGeneralConfig().getMySQLTablePrefix()).thenReturn("mcmmo_");
// public key retrieval
when(mcMMO.p.getGeneralConfig().getMySQLPublicKeyRetrieval()).thenReturn(true);
// debug
when(mcMMO.p.getGeneralConfig().getMySQLDebug()).thenReturn(true);
// use mysql
when(mcMMO.p.getGeneralConfig().getUseMySQL()).thenReturn(true);
// use ssl
when(mcMMO.p.getGeneralConfig().getMySQLSSL()).thenReturn(true);
// username
when(mcMMO.p.getGeneralConfig().getMySQLUserName()).thenReturn("sa");
// password
when(mcMMO.p.getGeneralConfig().getMySQLUserPassword()).thenReturn("");
// host
when(mcMMO.p.getGeneralConfig().getMySQLServerName()).thenReturn("localhost");
// unused mob health bar thingy
when(mcMMO.p.getGeneralConfig().getMobHealthbarDefault()).thenReturn(MobHealthbarType.HEARTS);
}
@BeforeEach
void setUp() {
assertNull(sqlDatabaseManager);
sqlDatabaseManager = new SQLDatabaseManager(logger, "org.h2.Driver", true);
}
@AfterEach
void tearDown() {
sqlDatabaseManager = null;
}
@AfterAll
static void tearDownAll() {
mockedMcMMO.close();
}
@Test
void testGetConnectionMisc() throws Exception {
assertNotNull(sqlDatabaseManager.getConnection(SQLDatabaseManager.PoolIdentifier.MISC));
}
@Test
void testGetConnectionLoad() throws Exception {
assertNotNull(sqlDatabaseManager.getConnection(SQLDatabaseManager.PoolIdentifier.LOAD));
}
@Test
void testGetConnectionSave() throws Exception {
assertNotNull(sqlDatabaseManager.getConnection(SQLDatabaseManager.PoolIdentifier.SAVE));
}
@Test
void testNewUser() {
Player player = Mockito.mock(Player.class);
when(player.getUniqueId()).thenReturn(java.util.UUID.randomUUID());
when(player.getName()).thenReturn("nossr50");
sqlDatabaseManager.newUser(player);
}
@Test
void testNewUserGetSkillLevel() {
Player player = Mockito.mock(Player.class);
when(player.getUniqueId()).thenReturn(java.util.UUID.randomUUID());
when(player.getName()).thenReturn("nossr50");
PlayerProfile playerProfile = sqlDatabaseManager.newUser(player);
for (PrimarySkillType primarySkillType : PrimarySkillType.values()) {
assertEquals(0, playerProfile.getSkillLevel(primarySkillType));
}
}
@Test
void testNewUserGetSkillXpLevel() {
Player player = Mockito.mock(Player.class);
when(player.getUniqueId()).thenReturn(java.util.UUID.randomUUID());
when(player.getName()).thenReturn("nossr50");
PlayerProfile playerProfile = sqlDatabaseManager.newUser(player);
for (PrimarySkillType primarySkillType : PrimarySkillType.values()) {
assertEquals(0, playerProfile.getSkillXpLevel(primarySkillType));
}
}
@Test
void testSaveSkillLevelValues() {
Player player = Mockito.mock(Player.class);
when(player.getUniqueId()).thenReturn(java.util.UUID.randomUUID());
when(player.getName()).thenReturn("nossr50");
PlayerProfile playerProfile = sqlDatabaseManager.newUser(player);
// Validate values are starting from zero
for (PrimarySkillType primarySkillType : PrimarySkillType.values()) {
assertEquals(0, playerProfile.getSkillXpLevel(primarySkillType));
}
// Change values
for (PrimarySkillType primarySkillType : PrimarySkillType.values()) {
playerProfile.modifySkill(primarySkillType, 1 + primarySkillType.ordinal());
}
boolean saveSuccess = sqlDatabaseManager.saveUser(playerProfile);
assertTrue(saveSuccess);
PlayerProfile retrievedUser = sqlDatabaseManager.loadPlayerProfile(player.getName());
// Check that values got saved
for (PrimarySkillType primarySkillType : PrimarySkillType.values()) {
if (primarySkillType == PrimarySkillType.SALVAGE || primarySkillType == PrimarySkillType.SMELTING) {
// Child skills are not saved, but calculated
continue;
}
assertEquals(1 + primarySkillType.ordinal(), retrievedUser.getSkillLevel(primarySkillType));
}
}
@Test
void testSaveSkillXpValues() {
Player player = Mockito.mock(Player.class);
when(player.getUniqueId()).thenReturn(java.util.UUID.randomUUID());
when(player.getName()).thenReturn("nossr50");
PlayerProfile playerProfile = sqlDatabaseManager.newUser(player);
// Validate values are starting from zero
for (PrimarySkillType primarySkillType : PrimarySkillType.values()) {
assertEquals(0, playerProfile.getSkillXpLevel(primarySkillType));
}
// Change values
for (PrimarySkillType primarySkillType : PrimarySkillType.values()) {
playerProfile.setSkillXpLevel(primarySkillType, 1 + primarySkillType.ordinal());
}
sqlDatabaseManager.saveUser(playerProfile);
PlayerProfile retrievedUser = sqlDatabaseManager.loadPlayerProfile(player.getName());
// Check that values got saved
for (PrimarySkillType primarySkillType : PrimarySkillType.values()) {
if (primarySkillType == PrimarySkillType.SALVAGE || primarySkillType == PrimarySkillType.SMELTING) {
// Child skills are not saved, but calculated
continue;
}
assertEquals(1 + primarySkillType.ordinal(), retrievedUser.getSkillXpLevel(primarySkillType));
}
}
}

View File

@@ -1,45 +1,46 @@
package com.gmail.nossr50.party;
import com.gmail.nossr50.MMOTestEnvironment;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import java.util.UUID;
import java.util.logging.Logger;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
class PartyManagerTest {
class PartyManagerTest extends MMOTestEnvironment {
private static final Logger logger = Logger.getLogger(PartyManagerTest.class.getName());
static mcMMO mockMcMMO;
@BeforeEach
public void setUp() {
mockBaseEnvironment(logger);
@BeforeAll
public static void setup() {
// create a static stub for LocaleLoader.class
mockStatic(LocaleLoader.class);
when(LocaleLoader.getString(anyString())).thenReturn("");
// currently unnecessary, but may be needed for future tests
Mockito.when(partyConfig.isPartyEnabled()).thenReturn(true);
}
mockMcMMO = mock(mcMMO.class);
final Server mockServer = mock(Server.class);
when(mockMcMMO.getServer()).thenReturn(mockServer);
when(mockServer.getPluginManager()).thenReturn(mock(PluginManager.class));
@AfterEach
public void tearDown() {
cleanupBaseEnvironment();
// TODO: Add cleanup for static mock
// disable parties in config for other tests
Mockito.when(partyConfig.isPartyEnabled()).thenReturn(false);
}
@Test
public void createPartyWithoutPasswordShouldSucceed() {
// Given
PartyManager partyManager = new PartyManager(mockMcMMO);
PartyManager partyManager = new PartyManager(mcMMO.p);
String partyName = "TestParty";
// TODO: Update this with utils from the other dev branches in the future
Player player = mock(Player.class);
McMMOPlayer mmoPlayer = mock(McMMOPlayer.class);
when(mmoPlayer.getPlayer()).thenReturn(player);
@@ -52,11 +53,10 @@ class PartyManagerTest {
@Test
public void createPartyWithPasswordShouldSucceed() {
// Given
PartyManager partyManager = new PartyManager(mockMcMMO);
PartyManager partyManager = new PartyManager(mcMMO.p);
String partyName = "TestParty";
String partyPassword = "somePassword";
// TODO: Update this with utils from the other dev branches in the future
Player player = mock(Player.class);
McMMOPlayer mmoPlayer = mock(McMMOPlayer.class);
when(mmoPlayer.getPlayer()).thenReturn(player);
@@ -69,10 +69,9 @@ class PartyManagerTest {
@Test
public void createPartyWithoutNameShouldFail() {
// Given
PartyManager partyManager = new PartyManager(mockMcMMO);
PartyManager partyManager = new PartyManager(mcMMO.p);
String partyPassword = "somePassword";
// TODO: Update this with utils from the other dev branches in the future
Player player = mock(Player.class);
McMMOPlayer mmoPlayer = mock(McMMOPlayer.class);
when(mmoPlayer.getPlayer()).thenReturn(player);
@@ -86,7 +85,7 @@ class PartyManagerTest {
@Test
public void createPartyWithoutPlayerShouldFail() {
// Given
PartyManager partyManager = new PartyManager(mockMcMMO);
PartyManager partyManager = new PartyManager(mcMMO.p);
String partyName = "TestParty";
String partyPassword = "somePassword";

View File

@@ -0,0 +1,120 @@
package com.gmail.nossr50.skills.excavation;
import com.gmail.nossr50.MMOTestEnvironment;
import com.gmail.nossr50.api.exceptions.InvalidSkillException;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.datatypes.treasure.ExcavationTreasure;
import com.gmail.nossr50.util.skills.RankUtils;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import java.util.ArrayList;
import java.util.List;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
class ExcavationTest extends MMOTestEnvironment {
private static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(ExcavationTest.class.getName());
@BeforeEach
void setUp() throws InvalidSkillException {
mockBaseEnvironment(logger);
when(rankConfig.getSubSkillUnlockLevel(SubSkillType.EXCAVATION_ARCHAEOLOGY, 1)).thenReturn(1);
when(rankConfig.getSubSkillUnlockLevel(SubSkillType.EXCAVATION_GIGA_DRILL_BREAKER, 1)).thenReturn(1);
// wire advanced config
when(RankUtils.getRankUnlockLevel(SubSkillType.EXCAVATION_ARCHAEOLOGY, 1)).thenReturn(1); // needed?
when(RankUtils.getRankUnlockLevel(SubSkillType.EXCAVATION_GIGA_DRILL_BREAKER, 1)).thenReturn(1); // needed?
when(RankUtils.hasReachedRank(eq(1), any(Player.class), eq(SubSkillType.EXCAVATION_ARCHAEOLOGY))).thenReturn(true);
when(RankUtils.hasReachedRank(eq(1), any(Player.class), eq(SubSkillType.EXCAVATION_GIGA_DRILL_BREAKER))).thenReturn(true);
// setup player and player related mocks after everything else
this.player = Mockito.mock(Player.class);
when(player.getUniqueId()).thenReturn(playerUUID);
// wire inventory
this.playerInventory = Mockito.mock(PlayerInventory.class);
this.itemInMainHand = new ItemStack(Material.DIAMOND_SHOVEL);
when(player.getInventory()).thenReturn(playerInventory);
when(playerInventory.getItemInMainHand()).thenReturn(itemInMainHand);
// Set up spy for Excavation Manager
}
@AfterEach
void tearDown() {
cleanupBaseEnvironment();
}
@Test
void excavationShouldHaveTreasureDrops() {
mmoPlayer.modifySkill(PrimarySkillType.EXCAVATION, 1000);
// Wire block
BlockState blockState = Mockito.mock(BlockState.class);
BlockData blockData = Mockito.mock(BlockData.class);
Block block = Mockito.mock(Block.class);
when(blockState.getBlockData()).thenReturn(blockData);
when(blockState.getType()).thenReturn(Material.SAND);
when(blockData.getMaterial()).thenReturn(Material.SAND);
when(blockState.getBlock()).thenReturn(block);
when(blockState.getBlock().getDrops(any())).thenReturn(null);
ExcavationManager excavationManager = Mockito.spy(new ExcavationManager(mmoPlayer));
doReturn(getGuaranteedTreasureDrops()).when(excavationManager).getTreasures(blockState);
excavationManager.excavationBlockCheck(blockState);
// verify ExcavationManager.processExcavationBonusesOnBlock was called
verify(excavationManager, atLeastOnce()).processExcavationBonusesOnBlock(any(BlockState.class), any(ExcavationTreasure.class), any(Location.class));
}
@Test
void excavationShouldNotDropTreasure() {
mmoPlayer.modifySkill(PrimarySkillType.EXCAVATION, 1000);
// Wire block
BlockState blockState = Mockito.mock(BlockState.class);
BlockData blockData = Mockito.mock(BlockData.class);
Block block = Mockito.mock(Block.class);
when(blockState.getBlockData()).thenReturn(blockData);
when(blockState.getType()).thenReturn(Material.SAND);
when(blockData.getMaterial()).thenReturn(Material.SAND);
when(blockState.getBlock()).thenReturn(block);
when(blockState.getBlock().getDrops(any())).thenReturn(null);
ExcavationManager excavationManager = Mockito.spy(new ExcavationManager(mmoPlayer));
doReturn(getImpossibleTreasureDrops()).when(excavationManager).getTreasures(blockState);
excavationManager.excavationBlockCheck(blockState);
// verify ExcavationManager.processExcavationBonusesOnBlock was called
verify(excavationManager, never()).processExcavationBonusesOnBlock(any(BlockState.class), any(ExcavationTreasure.class), any(Location.class));
}
private List<ExcavationTreasure> getGuaranteedTreasureDrops() {
List<ExcavationTreasure> treasures = new ArrayList<>();;
treasures.add(new ExcavationTreasure(new ItemStack(Material.CAKE), 1, 100, 1));
return treasures;
}
private List<ExcavationTreasure> getImpossibleTreasureDrops() {
List<ExcavationTreasure> treasures = new ArrayList<>();;
treasures.add(new ExcavationTreasure(new ItemStack(Material.CAKE), 1, 0, 1));
return treasures;
}
}

View File

@@ -0,0 +1,39 @@
package com.gmail.nossr50.skills.tridents;
import com.gmail.nossr50.MMOTestEnvironment;
import com.gmail.nossr50.api.exceptions.InvalidSkillException;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.mockito.Mockito;
class TridentsTest extends MMOTestEnvironment {
private static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(TridentsTest.class.getName());
TridentsManager tridentsManager;
ItemStack trident;
@BeforeEach
void setUp() throws InvalidSkillException {
mockBaseEnvironment(logger);
// setup player and player related mocks after everything else
this.player = Mockito.mock(Player.class);
Mockito.when(player.getUniqueId()).thenReturn(playerUUID);
// wire inventory
this.playerInventory = Mockito.mock(PlayerInventory.class);
this.trident = new ItemStack(Material.TRIDENT);
Mockito.when(playerInventory.getItemInMainHand()).thenReturn(trident);
// Set up spy for manager
tridentsManager = Mockito.spy(new TridentsManager(mmoPlayer));
}
@AfterEach
void tearDown() {
cleanupBaseEnvironment();
}
}

View File

@@ -0,0 +1,108 @@
package com.gmail.nossr50.skills.woodcutting;
import com.gmail.nossr50.MMOTestEnvironment;
import com.gmail.nossr50.api.exceptions.InvalidSkillException;
import com.gmail.nossr50.config.experience.ExperienceConfig;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.util.skills.RankUtils;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
class WoodcuttingTest extends MMOTestEnvironment {
private static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(WoodcuttingTest.class.getName());
WoodcuttingManager woodcuttingManager;
@BeforeEach
void setUp() throws InvalidSkillException {
mockBaseEnvironment(logger);
Mockito.when(rankConfig.getSubSkillUnlockLevel(SubSkillType.WOODCUTTING_HARVEST_LUMBER, 1)).thenReturn(1);
// wire advanced config
Mockito.when(advancedConfig.getMaximumProbability(SubSkillType.WOODCUTTING_HARVEST_LUMBER)).thenReturn(100D);
Mockito.when(advancedConfig.getMaximumProbability(SubSkillType.WOODCUTTING_CLEAN_CUTS)).thenReturn(10D);
Mockito.when(advancedConfig.getMaxBonusLevel(SubSkillType.WOODCUTTING_HARVEST_LUMBER)).thenReturn(1000);
Mockito.when(advancedConfig.getMaxBonusLevel(SubSkillType.WOODCUTTING_CLEAN_CUTS)).thenReturn(10000);
Mockito.when(RankUtils.getRankUnlockLevel(SubSkillType.WOODCUTTING_HARVEST_LUMBER, 1)).thenReturn(1); // needed?
Mockito.when(RankUtils.getRankUnlockLevel(SubSkillType.WOODCUTTING_CLEAN_CUTS, 1)).thenReturn(1000); // needed?
Mockito.when(RankUtils.hasReachedRank(eq(1), any(Player.class), eq(SubSkillType.WOODCUTTING_HARVEST_LUMBER))).thenReturn(true);
Mockito.when(RankUtils.hasReachedRank(eq(1), any(Player.class), eq(SubSkillType.WOODCUTTING_CLEAN_CUTS))).thenReturn(true);
// setup player and player related mocks after everything else
this.player = Mockito.mock(Player.class);
Mockito.when(player.getUniqueId()).thenReturn(playerUUID);
// wire inventory
this.playerInventory = Mockito.mock(PlayerInventory.class);
this.itemInMainHand = new ItemStack(Material.DIAMOND_AXE);
Mockito.when(player.getInventory()).thenReturn(playerInventory);
Mockito.when(playerInventory.getItemInMainHand()).thenReturn(itemInMainHand);
// Set up spy for WoodcuttingManager
woodcuttingManager = Mockito.spy(new WoodcuttingManager(mmoPlayer));
}
@AfterEach
void tearDown() {
cleanupBaseEnvironment();
}
@Test
void harvestLumberShouldDoubleDrop() {
mmoPlayer.modifySkill(PrimarySkillType.WOODCUTTING, 1000);
BlockState blockState = Mockito.mock(BlockState.class);
Block block = Mockito.mock(Block.class);
// wire block
Mockito.when(blockState.getBlock()).thenReturn(block);
Mockito.when(blockState.getBlock().getDrops(any())).thenReturn(null);
Mockito.when(blockState.getType()).thenReturn(Material.OAK_LOG);
woodcuttingManager.processBonusDropCheck(blockState);
// verify bonus drops were spawned
// TODO: Can fail if triple drops happen, need to update test
Mockito.verify(woodcuttingManager, Mockito.times(1)).spawnHarvestLumberBonusDrops(blockState);
}
@Test
void harvestLumberShouldNotDoubleDrop() {
mmoPlayer.modifySkill(PrimarySkillType.WOODCUTTING, 0);
BlockState blockState = Mockito.mock(BlockState.class);
Block block = Mockito.mock(Block.class);
// wire block
Mockito.when(blockState.getBlock()).thenReturn(block);
Mockito.when(blockState.getBlock().getDrops(any())).thenReturn(null);
Mockito.when(blockState.getType()).thenReturn(Material.OAK_LOG);
woodcuttingManager.processBonusDropCheck(blockState);
// verify bonus drops were not spawned
Mockito.verify(woodcuttingManager, Mockito.times(0)).spawnHarvestLumberBonusDrops(blockState);
}
@Test
void testProcessWoodcuttingBlockXP() {
BlockState targetBlock = Mockito.mock(BlockState.class);
Mockito.when(targetBlock.getType()).thenReturn(Material.OAK_LOG);
// wire XP
Mockito.when(ExperienceConfig.getInstance().getXp(PrimarySkillType.WOODCUTTING, Material.OAK_LOG)).thenReturn(5);
// Verify XP increased by 5 when processing XP
woodcuttingManager.processWoodcuttingBlockXP(targetBlock);
Mockito.verify(mmoPlayer, Mockito.times(1)).beginXpGain(eq(PrimarySkillType.WOODCUTTING), eq(5F), any(), any());
}
}

View File

@@ -0,0 +1,105 @@
package com.gmail.nossr50.util.random;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.*;
class ProbabilityTest {
private static Stream<Arguments> provideProbabilitiesForWithinExpectations() {
return Stream.of(
// static probability, % of time for success
Arguments.of(new ProbabilityImpl(5), 5),
Arguments.of(new ProbabilityImpl(10), 10),
Arguments.of(new ProbabilityImpl(15), 15),
Arguments.of(new ProbabilityImpl(20), 20),
Arguments.of(new ProbabilityImpl(25), 25),
Arguments.of(new ProbabilityImpl(50), 50),
Arguments.of(new ProbabilityImpl(75), 75),
Arguments.of(new ProbabilityImpl(90), 90),
Arguments.of(new ProbabilityImpl(99.9), 99.9),
Arguments.of(new ProbabilityImpl(0.05), 0.05),
Arguments.of(new ProbabilityImpl(0.1), 0.1),
Arguments.of(new ProbabilityImpl(500), 100),
Arguments.of(new ProbabilityImpl(1000), 100)
);
}
private static Stream<Arguments> provideOfPercentageProbabilitiesForWithinExpectations() {
return Stream.of(
// static probability, % of time for success
Arguments.of(Probability.ofPercent(5), 5),
Arguments.of(Probability.ofPercent(10), 10),
Arguments.of(Probability.ofPercent(15), 15),
Arguments.of(Probability.ofPercent(20), 20),
Arguments.of(Probability.ofPercent(25), 25),
Arguments.of(Probability.ofPercent(50), 50),
Arguments.of(Probability.ofPercent(75), 75),
Arguments.of(Probability.ofPercent(90), 90),
Arguments.of(Probability.ofPercent(99.9), 99.9),
Arguments.of(Probability.ofPercent(0.05), 0.05),
Arguments.of(Probability.ofPercent(0.1), 0.1),
Arguments.of(Probability.ofPercent(500), 100),
Arguments.of(Probability.ofPercent(1000), 100)
);
}
@Test
void testAlwaysWinConstructor() {
for (int i = 0; i < 100000; i++) {
assertTrue(new ProbabilityImpl(100).evaluate());
}
}
@Test
void testAlwaysLoseConstructor() {
for (int i = 0; i < 100000; i++) {
assertFalse(new ProbabilityImpl(0).evaluate());
}
}
@Test
void testAlwaysWinOfPercent() {
for (int i = 0; i < 100000; i++) {
assertTrue(Probability.ofPercent(100).evaluate());
}
}
@Test
void testAlwaysLoseOfPercent() {
for (int i = 0; i < 100000; i++) {
assertFalse(Probability.ofPercent(0).evaluate());
}
}
@ParameterizedTest
@MethodSource("provideProbabilitiesForWithinExpectations")
void testOddsExpectationsConstructor(Probability probability, double expectedWinPercent) {
assertExpectations(probability, expectedWinPercent);
}
@ParameterizedTest
@MethodSource("provideOfPercentageProbabilitiesForWithinExpectations")
void testOddsExpectationsOfPercent(Probability probability, double expectedWinPercent) {
assertExpectations(probability, expectedWinPercent);
}
private static void assertExpectations(Probability probability, double expectedWinPercent) {
double iterations = 2.0e7;
double winCount = 0;
for (int i = 0; i < iterations; i++) {
if(probability.evaluate()) {
winCount++;
}
}
double successPercent = (winCount / iterations) * 100;
System.out.println(successPercent + ", " + expectedWinPercent);
assertEquals(expectedWinPercent, successPercent, 0.05D);
}
}

View File

@@ -0,0 +1,66 @@
package com.gmail.nossr50.util.random;
import com.gmail.nossr50.config.AdvancedConfig;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.mcMMO;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
import static com.gmail.nossr50.datatypes.skills.SubSkillType.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
class ProbabilityUtilTest {
mcMMO mmoInstance;
AdvancedConfig advancedConfig;
final static double impactChance = 11D;
final static double greaterImpactChance = 0.007D;
final static double fastFoodChance = 45.5D;
@BeforeEach
public void setupMocks() throws NoSuchFieldException, IllegalAccessException {
this.mmoInstance = mock(mcMMO.class);
mcMMO.class.getField("p").set(null, mmoInstance);
this.advancedConfig = mock(AdvancedConfig.class);
when(mmoInstance.getAdvancedConfig()).thenReturn(advancedConfig);
when(advancedConfig.getImpactChance()).thenReturn(impactChance);
when(advancedConfig.getGreaterImpactChance()).thenReturn(greaterImpactChance);
when(advancedConfig.getFastFoodChance()).thenReturn(fastFoodChance);
}
private static Stream<Arguments> staticChanceSkills() {
return Stream.of(
// static probability, % of time for success
Arguments.of(AXES_ARMOR_IMPACT, impactChance),
Arguments.of(AXES_GREATER_IMPACT, greaterImpactChance),
Arguments.of(TAMING_FAST_FOOD_SERVICE, fastFoodChance)
);
}
@ParameterizedTest
@MethodSource("staticChanceSkills")
void testStaticChanceSkills(SubSkillType subSkillType, double expectedWinPercent) throws InvalidStaticChance {
Probability staticRandomChance = ProbabilityUtil.getStaticRandomChance(subSkillType);
assertProbabilityExpectations(expectedWinPercent, staticRandomChance);
}
private static void assertProbabilityExpectations(double expectedWinPercent, Probability probability) {
double iterations = 2.0e7;
double winCount = 0;
for (int i = 0; i < iterations; i++) {
if(probability.evaluate()) {
winCount++;
}
}
double successPercent = (winCount / iterations) * 100;
System.out.println(successPercent + ", " + expectedWinPercent);
assertEquals(expectedWinPercent, successPercent, 0.05D);
}
}

View File

@@ -1,116 +0,0 @@
//package com.gmail.nossr50.util.random;
//
//import com.gmail.nossr50.datatypes.player.McMMOPlayer;
//import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
//import com.gmail.nossr50.datatypes.skills.SubSkillType;
//import com.gmail.nossr50.util.Permissions;
//import com.gmail.nossr50.util.player.UserManager;
//import org.bukkit.entity.Player;
//import org.jetbrains.annotations.NotNull;
//import org.junit.Assert;
//import org.junit.Before;
//import org.junit.Test;
//import org.junit.runner.RunWith;
//import org.mockito.Mockito;
//import org.powermock.api.mockito.PowerMockito;
//import org.powermock.core.classloader.annotations.PrepareForTest;
//import org.powermock.modules.junit4.PowerMockRunner;
//
//import static org.mockito.Mockito.mock;
//
////TODO: Rewrite the entire com.gmail.nossr50.util.random package, it was written in haste and it disgusts me
////TODO: Add more tests for the other types of random dice rolls
//@RunWith(PowerMockRunner.class)
//@PrepareForTest({RandomChanceUtil.class, UserManager.class})
//public class RandomChanceTest {
//
// private Player luckyPlayer;
// private McMMOPlayer mmoPlayerLucky;
//
// private Player normalPlayer;
// private McMMOPlayer mmoPlayerNormal;
//
// private SubSkillType subSkillType;
// private PrimarySkillType primarySkillType;
//
// private final String testASCIIHeader = "---- mcMMO Tests ----";
//
// @Before
// public void setUpMock() {
// primarySkillType = PrimarySkillType.HERBALISM;
// subSkillType = SubSkillType.HERBALISM_GREEN_THUMB;
//
// //TODO: Likely needs to be changed per skill if more tests were added
// PowerMockito.stub(PowerMockito.method(RandomChanceUtil.class, "getMaximumProbability", subSkillType.getClass())).toReturn(100D);
// PowerMockito.stub(PowerMockito.method(RandomChanceUtil.class, "getMaxBonusLevelCap", subSkillType.getClass())).toReturn(1000D);
//
// normalPlayer = mock(Player.class);
// luckyPlayer = mock(Player.class);
//
// mmoPlayerNormal = mock(McMMOPlayer.class);
// mmoPlayerLucky = mock(McMMOPlayer.class);
//
// PowerMockito.mockStatic(UserManager.class);
// Mockito.when(UserManager.getPlayer(normalPlayer)).thenReturn(mmoPlayerNormal);
// Mockito.when(UserManager.getPlayer(luckyPlayer)).thenReturn(mmoPlayerLucky);
//
// Mockito.when(mmoPlayerNormal.getPlayer()).thenReturn(normalPlayer);
// Mockito.when(mmoPlayerLucky.getPlayer()).thenReturn(luckyPlayer);
//
// //Lucky player has the lucky permission
// //Normal player doesn't have any lucky permission
// Mockito.when(Permissions.lucky(luckyPlayer, primarySkillType)).thenReturn(true);
// Mockito.when(Permissions.lucky(normalPlayer, primarySkillType)).thenReturn(false);
//
// Mockito.when(mmoPlayerNormal.getSkillLevel(primarySkillType)).thenReturn(800);
// Mockito.when(mmoPlayerLucky.getSkillLevel(primarySkillType)).thenReturn(800);
// }
//
// @Test
// public void testLuckyChance() {
// System.out.println(testASCIIHeader);
// System.out.println("Testing success odds to fall within expected values...");
// assertEquals(80D, getSuccessChance(mmoPlayerNormal),0D);
// assertEquals(80D * RandomChanceUtil.LUCKY_MODIFIER, getSuccessChance(mmoPlayerLucky),0D);
// }
//
// @Test
// public void testNeverFailsSuccessLuckyPlayer() {
// System.out.println(testASCIIHeader);
// System.out.println("Test - Lucky Player with 80% base success should never fail (10,000 iterations)");
// for(int x = 0; x < 10000; x++) {
// Assert.assertTrue(RandomChanceUtil.checkRandomChanceExecutionSuccess(luckyPlayer, SubSkillType.HERBALISM_GREEN_THUMB, true));
// if(x == 10000-1)
// System.out.println("They never failed!");
// }
// }
//
// @Test
// public void testFailsAboutExpected() {
// System.out.println(testASCIIHeader);
// System.out.println("Test - Player with 800 skill should fail about 20% of the time (100,000 iterations)");
// double ratioDivisor = 1000; //1000 because we run the test 100,000 times
// double expectedFailRate = 20D;
//
// double win = 0, loss = 0;
// for(int x = 0; x < 100000; x++) {
// if(RandomChanceUtil.checkRandomChanceExecutionSuccess(normalPlayer, SubSkillType.HERBALISM_GREEN_THUMB, true)) {
// win++;
// } else {
// loss++;
// }
// }
//
// double lossRatio = (loss / ratioDivisor);
// Assert.assertEquals(lossRatio, expectedFailRate, 1D);
// }
//
// private double getSuccessChance(@NotNull McMMOPlayer mmoPlayer) {
// RandomChanceSkill randomChanceSkill = new RandomChanceSkill(mmoPlayer.getPlayer(), subSkillType, true);
// return RandomChanceUtil.calculateChanceOfSuccess(randomChanceSkill);
// }
//
// private void assertEquals(double expected, double actual, double delta) {
// Assert.assertEquals(expected, actual, delta);
// }
//}

View File

@@ -1,16 +0,0 @@
//package com.gmail.nossr50.util.skills;
//
//import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
//import com.google.common.collect.ImmutableList;
//import org.junit.Before;
//import org.junit.Test;
//import org.junit.runner.RunWith;
//import org.powermock.core.classloader.annotations.PrepareForTest;
//import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor;
//import org.powermock.modules.junit4.PowerMockRunner;
//
//@RunWith(PowerMockRunner.class)
//@PrepareForTest(SkillTools.class)
//public class SkillToolsTest {
//
//}

View File

@@ -7,7 +7,7 @@ import org.junit.jupiter.api.Test;
/**
* This Unit Test checks if Adventure was set up correctly and works as expected.
* Normally we can rely on this to be the case. However sometimes our dependencies
* Normally, we can rely on this to be the case. However sometimes our dependencies
* lack so far behind that things stop working correctly.
* This test ensures that basic functionality is guaranteed to work as we would expect.
*