From eda227006f9b4760a0fd19451a467d9110f4c18f Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 4 Feb 2021 14:56:06 -0800 Subject: [PATCH 01/75] endgame progression WIP --- Changelog.txt | 14 ++++++++ .../nossr50/commands/CommandManager.java | 34 ++++++++++++++++++- .../commands/skills/PowerLevelCommand.java | 31 +++++++++++++++++ .../java/com/gmail/nossr50/config/Config.java | 1 + .../datatypes/skills/SubSkillType.java | 17 +++++++++- src/main/resources/config.yml | 3 ++ src/main/resources/plugin.yml | 5 +++ 7 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java diff --git a/Changelog.txt b/Changelog.txt index 80ebd177f6..b771abfc49 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,4 +1,18 @@ Version 2.1.175 + Added a new mastery sub-skill to each skill (see notes) + Added /mmopower command (aliases /mmopowerlevel /powerlevel) + Added 'mcmmo.commands.mmopower' permission node + Added 'General.PowerLevel.Skill_Mastery.Enabled' to config.yml which is used to enable or disable the mastery skills (will also disable the new power level command) + + NOTES: + Most skills have a mastery sub-skill, this mastery subskill provides a small benefit that scales to level 10,000 (or 1,000 for standard) and does not have ranks (other than the initial rank to unlock it) + Mastery skills unlock at level 1000 for RetroMode (the default setting), and 100 for Standard + Mastery skills are meant to provide an "end-game" to skills, a reason to continue leveling a skill past its "max". + This system is brand new, it is entirely possible I will completely change, remove, or add more mastery skills in the future. + + New Power Level Command + This power level command gives you a view of all your current masteries, it also provides a summary of your power level. + Version 2.1.174 Some legacy color codes in our locale file were swapped to &-code equivalents (thanks ViaSnake) diff --git a/src/main/java/com/gmail/nossr50/commands/CommandManager.java b/src/main/java/com/gmail/nossr50/commands/CommandManager.java index ea72fc2f9f..b1bb5abf4a 100644 --- a/src/main/java/com/gmail/nossr50/commands/CommandManager.java +++ b/src/main/java/com/gmail/nossr50/commands/CommandManager.java @@ -5,7 +5,9 @@ import co.aikar.commands.ConditionFailedException; import com.gmail.nossr50.commands.chat.AdminChatCommand; import com.gmail.nossr50.commands.chat.PartyChatCommand; +import com.gmail.nossr50.commands.skills.PowerLevelCommand; import com.gmail.nossr50.config.ChatConfig; +import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.chat.ChatChannel; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; @@ -20,9 +22,14 @@ * For now this class will only handle ACF converted commands, all other commands will be handled elsewhere */ public class CommandManager { + public static final @NotNull String MMO_DATA_LOADED = "mmoDataLoaded"; + + //CHAT public static final @NotNull String ADMIN_CONDITION = "adminCondition"; public static final @NotNull String PARTY_CONDITION = "partyCondition"; - public static final @NotNull String MMO_DATA_LOADED = "mmoDataLoaded"; + + //SKILLS + public static final @NotNull String POWER_LEVEL_CONDITION = "powerLevelCondition"; private final @NotNull mcMMO pluginRef; private final @NotNull BukkitCommandManager bukkitCommandManager; @@ -36,9 +43,16 @@ public CommandManager(@NotNull mcMMO pluginRef) { } private void registerCommands() { + registerSkillCommands(); //TODO: Implement other skills not just power level registerChatCommands(); } + private void registerSkillCommands() { + if(Config.getInstance().isMasterySystemEnabled()) { + bukkitCommandManager.registerCommand(new PowerLevelCommand(pluginRef)); + } + } + /** * Registers chat commands if the chat system is enabled */ @@ -54,6 +68,23 @@ private void registerChatCommands() { } public void registerConditions() { + registerChatCommandConditions(); //Chat Commands + registerSkillConditions(); + } + + private void registerSkillConditions() { + bukkitCommandManager.getCommandConditions().addCondition(POWER_LEVEL_CONDITION, (context) -> { + BukkitCommandIssuer issuer = context.getIssuer(); + + if(issuer.getIssuer() instanceof Player) { + validateLoadedData(issuer.getPlayer()); + } else { + throw new ConditionFailedException(LocaleLoader.getString("Commands.NoConsole")); + } + }); + } + + private void registerChatCommandConditions() { // Method or Class based - Can only be used on methods bukkitCommandManager.getCommandConditions().addCondition(ADMIN_CONDITION, (context) -> { BukkitCommandIssuer issuer = context.getIssuer(); @@ -78,6 +109,7 @@ public void registerConditions() { if(bukkitCommandIssuer.getIssuer() instanceof Player) { validateLoadedData(bukkitCommandIssuer.getPlayer()); validatePlayerParty(bukkitCommandIssuer.getPlayer()); + //TODO: Is there even a point in validating permission? look into this later validatePermission("mcmmo.chat.partychat", bukkitCommandIssuer.getPlayer()); } }); diff --git a/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java new file mode 100644 index 0000000000..a418b4b09e --- /dev/null +++ b/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java @@ -0,0 +1,31 @@ +package com.gmail.nossr50.commands.skills; + +import co.aikar.commands.BaseCommand; +import co.aikar.commands.BukkitCommandIssuer; +import co.aikar.commands.annotation.CommandAlias; +import co.aikar.commands.annotation.CommandPermission; +import co.aikar.commands.annotation.Conditions; +import co.aikar.commands.annotation.Default; +import com.gmail.nossr50.commands.CommandManager; +import com.gmail.nossr50.mcMMO; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +@CommandPermission("mcmmo.commands.mmopower") +@CommandAlias("mmopowerlevel|powerlevel") //Kept for historical reasons +public class PowerLevelCommand extends BaseCommand { + private final @NotNull mcMMO pluginRef; + + public PowerLevelCommand(@NotNull mcMMO pluginRef) { + this.pluginRef = pluginRef; + } + + @Default + @Conditions(CommandManager.ADMIN_CONDITION) + public void processCommand(String[] args) { + BukkitCommandIssuer bukkitCommandIssuer = (BukkitCommandIssuer) getCurrentCommandIssuer(); + Player player = bukkitCommandIssuer.getPlayer(); + + //TODO: impl + } +} \ No newline at end of file diff --git a/src/main/java/com/gmail/nossr50/config/Config.java b/src/main/java/com/gmail/nossr50/config/Config.java index cc8549303c..a59a0e81ff 100644 --- a/src/main/java/com/gmail/nossr50/config/Config.java +++ b/src/main/java/com/gmail/nossr50/config/Config.java @@ -597,4 +597,5 @@ public int getLevelCap(PrimarySkillType skill) { public int getPowerLevelUpBroadcastRadius() { return config.getInt("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Broadcast_Targets.Distance_Restrictions.Restricted_Radius", 100); } public int getPowerLevelUpBroadcastInterval() { return config.getInt("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Milestone_Interval", 100); } + public boolean isMasterySystemEnabled() { return config.getBoolean( "General.PowerLevel.Skill_Mastery.Enabled"); } } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java index 059df8db94..823f6b6644 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java @@ -11,16 +11,19 @@ public enum SubSkillType { /* ACROBATICS */ ACROBATICS_DODGE(1), ACROBATICS_ROLL, + ACROBATICS_MASTERY(1), /* ALCHEMY */ ALCHEMY_CATALYSIS(1), ALCHEMY_CONCOCTIONS(8), + ALCHEMY_MASTERY(1), /* ARCHERY */ ARCHERY_ARROW_RETRIEVAL(1), ARCHERY_DAZE, ARCHERY_SKILL_SHOT(20), ARCHERY_ARCHERY_LIMIT_BREAK(10), + ARCHERY_MASTERY(1), /* Axes */ AXES_ARMOR_IMPACT(20), @@ -29,10 +32,12 @@ public enum SubSkillType { AXES_CRITICAL_STRIKES(1), AXES_GREATER_IMPACT(1), AXES_SKULL_SPLITTER(1), + AXES_MASTERY(1), /* Excavation */ EXCAVATION_ARCHAEOLOGY(8), EXCAVATION_GIGA_DRILL_BREAKER(1), + EXCAVATION_MASTERY(1), /* Fishing */ FISHING_FISHERMANS_DIET(5), @@ -41,6 +46,7 @@ public enum SubSkillType { FISHING_MASTER_ANGLER(8), FISHING_TREASURE_HUNTER(8), FISHING_SHAKE(1), + FISHING_MASTERY(1), /* Herbalism */ HERBALISM_DOUBLE_DROPS(1), @@ -49,6 +55,7 @@ public enum SubSkillType { HERBALISM_GREEN_THUMB(4), HERBALISM_HYLIAN_LUCK, HERBALISM_SHROOM_THUMB, + HERBALISM_MASTERY(1), /* Mining */ MINING_BIGGER_BOMBS(1), @@ -56,11 +63,13 @@ public enum SubSkillType { MINING_DEMOLITIONS_EXPERTISE(1), MINING_DOUBLE_DROPS(1), MINING_SUPER_BREAKER(1), + MINING_MASTERY(1), /* Repair */ REPAIR_ARCANE_FORGING(8), REPAIR_REPAIR_MASTERY(1), REPAIR_SUPER_REPAIR(1), + REPAIR_MASTERY(1), /* Salvage */ SALVAGE_SCRAP_COLLECTOR(8), @@ -77,6 +86,7 @@ public enum SubSkillType { SWORDS_SERRATED_STRIKES(1), SWORDS_STAB(2), SWORDS_SWORDS_LIMIT_BREAK(10), + SWORDS_MASTERY(1), /* Taming */ TAMING_BEAST_LORE(1), @@ -89,6 +99,7 @@ public enum SubSkillType { TAMING_SHARPENED_CLAWS(1), TAMING_SHOCK_PROOF(1), TAMING_THICK_FUR(1), + TAMING_MASTERY(1), /* Unarmed */ UNARMED_ARROW_DEFLECT(1), @@ -98,6 +109,7 @@ public enum SubSkillType { UNARMED_STEEL_ARM_STYLE(20), UNARMED_IRON_GRIP(1), UNARMED_UNARMED_LIMIT_BREAK(10), + UNARMED_MASTERY(1), /* Woodcutting */ /* WOODCUTTING_BARK_SURGEON(3),*/ @@ -106,7 +118,10 @@ public enum SubSkillType { WOODCUTTING_LEAF_BLOWER(1), /* WOODCUTTING_NATURES_BOUNTY(3), WOODCUTTING_SPLINTER(3),*/ - WOODCUTTING_TREE_FELLER(1); + WOODCUTTING_TREE_FELLER(1), + WOODCUTTING_MASTERY(1), + + POWER_LEVEL_MASTERY(1); private final int numRanks; //TODO: SuperAbilityType should also contain flags for active by default? Not sure if it should work that way. diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index ad1a09e695..10b9dd5729 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -49,6 +49,9 @@ General: RetroMode: Enabled: true Locale: en_US + PowerLevel: + Skill_Mastery: + Enabled: true AprilFoolsEvent: true MOTD_Enabled: true EventBroadcasts: true diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 70499738e8..a63be2f846 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -149,6 +149,10 @@ commands: salvage: description: Detailed mcMMO skill info permission: mcmmo.commands.salvage + mmopower: + description: Shows skill mastery and power level info + permission: mcmmo.commands.mmopower + aliases: [mmopowerlevel, powerlevel] adminchat: aliases: [ac, a] description: Toggle Admin chat or send admin chat messages @@ -825,6 +829,7 @@ permissions: mcmmo.commands.taming: true mcmmo.commands.unarmed: true mcmmo.commands.woodcutting: true + mcmmo.commands.mmopower: true mcmmo.commands.defaultsop: description: Implies all default op mcmmo.commands permissions. children: From ce09a8bcdc85150a1da02887d4a61c0bc244c216 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 5 Feb 2021 16:26:46 -0800 Subject: [PATCH 02/75] get mmopower working --- Changelog.txt | 3 +- .../commands/skills/PowerLevelCommand.java | 8 +- .../datatypes/skills/PrimarySkillType.java | 26 +++---- .../datatypes/skills/SubSkillType.java | 4 +- src/main/resources/skillranks.yml | 75 +++++++++++++++++++ 5 files changed, 96 insertions(+), 20 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index b771abfc49..185aaea358 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -6,14 +6,13 @@ Version 2.1.175 NOTES: Most skills have a mastery sub-skill, this mastery subskill provides a small benefit that scales to level 10,000 (or 1,000 for standard) and does not have ranks (other than the initial rank to unlock it) - Mastery skills unlock at level 1000 for RetroMode (the default setting), and 100 for Standard + Mastery skills unlock at level 1000 for RetroMode (the default setting), and 100 for Standard, you can edit this via skillranks.yml Mastery skills are meant to provide an "end-game" to skills, a reason to continue leveling a skill past its "max". This system is brand new, it is entirely possible I will completely change, remove, or add more mastery skills in the future. New Power Level Command This power level command gives you a view of all your current masteries, it also provides a summary of your power level. - Version 2.1.174 Some legacy color codes in our locale file were swapped to &-code equivalents (thanks ViaSnake) Updated hu_HU locale (thanks andris155) diff --git a/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java index a418b4b09e..d15dd364a4 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java @@ -7,12 +7,14 @@ import co.aikar.commands.annotation.Conditions; import co.aikar.commands.annotation.Default; import com.gmail.nossr50.commands.CommandManager; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.player.UserManager; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @CommandPermission("mcmmo.commands.mmopower") -@CommandAlias("mmopowerlevel|powerlevel") //Kept for historical reasons +@CommandAlias("mmopower|mmopowerlevel|powerlevel") public class PowerLevelCommand extends BaseCommand { private final @NotNull mcMMO pluginRef; @@ -25,7 +27,9 @@ public PowerLevelCommand(@NotNull mcMMO pluginRef) { public void processCommand(String[] args) { BukkitCommandIssuer bukkitCommandIssuer = (BukkitCommandIssuer) getCurrentCommandIssuer(); Player player = bukkitCommandIssuer.getPlayer(); + McMMOPlayer mmoPlayer = UserManager.getPlayer(player); //Should never be null at this point because its caught in an ACF validation //TODO: impl + mmoPlayer.getPlayer().sendMessage("Your power level is: "+mmoPlayer.getPowerLevel()); //This is not gonna stay, just to show that the command executes in debug } -} \ No newline at end of file +} diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java index 0673db147f..07135cc9b8 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java @@ -35,35 +35,35 @@ public enum PrimarySkillType { ACROBATICS(AcrobaticsManager.class, Color.WHITE, - ImmutableList.of(SubSkillType.ACROBATICS_DODGE, SubSkillType.ACROBATICS_ROLL)), + ImmutableList.of(SubSkillType.ACROBATICS_MASTERY, SubSkillType.ACROBATICS_DODGE, SubSkillType.ACROBATICS_ROLL)), ALCHEMY(AlchemyManager.class, Color.FUCHSIA, - ImmutableList.of(SubSkillType.ALCHEMY_CATALYSIS, SubSkillType.ALCHEMY_CONCOCTIONS)), + ImmutableList.of(SubSkillType.ALCHEMY_MASTERY, SubSkillType.ALCHEMY_CATALYSIS, SubSkillType.ALCHEMY_CONCOCTIONS)), ARCHERY(ArcheryManager.class, Color.MAROON, - ImmutableList.of(SubSkillType.ARCHERY_DAZE, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK, SubSkillType.ARCHERY_ARROW_RETRIEVAL, SubSkillType.ARCHERY_SKILL_SHOT)), + ImmutableList.of(SubSkillType.ARCHERY_MASTERY, SubSkillType.ARCHERY_DAZE, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK, SubSkillType.ARCHERY_ARROW_RETRIEVAL, SubSkillType.ARCHERY_SKILL_SHOT)), AXES(AxesManager.class, Color.AQUA, SuperAbilityType.SKULL_SPLITTER, ToolType.AXE, - ImmutableList.of(SubSkillType.AXES_SKULL_SPLITTER, SubSkillType.AXES_AXES_LIMIT_BREAK, SubSkillType.AXES_ARMOR_IMPACT, SubSkillType.AXES_AXE_MASTERY, SubSkillType.AXES_CRITICAL_STRIKES, SubSkillType.AXES_GREATER_IMPACT)), + ImmutableList.of(SubSkillType.AXES_MASTERY, SubSkillType.AXES_SKULL_SPLITTER, SubSkillType.AXES_AXES_LIMIT_BREAK, SubSkillType.AXES_ARMOR_IMPACT, SubSkillType.AXES_AXE_MASTERY, SubSkillType.AXES_CRITICAL_STRIKES, SubSkillType.AXES_GREATER_IMPACT)), EXCAVATION(ExcavationManager.class, Color.fromRGB(139, 69, 19), SuperAbilityType.GIGA_DRILL_BREAKER, ToolType.SHOVEL, - ImmutableList.of(SubSkillType.EXCAVATION_GIGA_DRILL_BREAKER, SubSkillType.EXCAVATION_ARCHAEOLOGY)), + ImmutableList.of(SubSkillType.EXCAVATION_MASTERY, SubSkillType.EXCAVATION_GIGA_DRILL_BREAKER, SubSkillType.EXCAVATION_ARCHAEOLOGY)), FISHING(FishingManager.class, Color.NAVY, - ImmutableList.of(SubSkillType.FISHING_FISHERMANS_DIET, SubSkillType.FISHING_TREASURE_HUNTER, SubSkillType.FISHING_ICE_FISHING, SubSkillType.FISHING_MAGIC_HUNTER, SubSkillType.FISHING_MASTER_ANGLER, SubSkillType.FISHING_SHAKE)), + ImmutableList.of(SubSkillType.FISHING_MASTERY, SubSkillType.FISHING_FISHERMANS_DIET, SubSkillType.FISHING_TREASURE_HUNTER, SubSkillType.FISHING_ICE_FISHING, SubSkillType.FISHING_MAGIC_HUNTER, SubSkillType.FISHING_MASTER_ANGLER, SubSkillType.FISHING_SHAKE)), HERBALISM(HerbalismManager.class, Color.GREEN, SuperAbilityType.GREEN_TERRA, ToolType.HOE, - ImmutableList.of(SubSkillType.HERBALISM_GREEN_TERRA, SubSkillType.HERBALISM_FARMERS_DIET, SubSkillType.HERBALISM_GREEN_THUMB, SubSkillType.HERBALISM_DOUBLE_DROPS, SubSkillType.HERBALISM_HYLIAN_LUCK, SubSkillType.HERBALISM_SHROOM_THUMB)), + ImmutableList.of(SubSkillType.HERBALISM_MASTERY, SubSkillType.HERBALISM_GREEN_TERRA, SubSkillType.HERBALISM_FARMERS_DIET, SubSkillType.HERBALISM_GREEN_THUMB, SubSkillType.HERBALISM_DOUBLE_DROPS, SubSkillType.HERBALISM_HYLIAN_LUCK, SubSkillType.HERBALISM_SHROOM_THUMB)), MINING(MiningManager.class, Color.GRAY, SuperAbilityType.SUPER_BREAKER, ToolType.PICKAXE, - ImmutableList.of(SubSkillType.MINING_SUPER_BREAKER, SubSkillType.MINING_DEMOLITIONS_EXPERTISE, SubSkillType.MINING_BIGGER_BOMBS, SubSkillType.MINING_BLAST_MINING, SubSkillType.MINING_DOUBLE_DROPS)), + ImmutableList.of(SubSkillType.MINING_MASTERY, SubSkillType.MINING_SUPER_BREAKER, SubSkillType.MINING_DEMOLITIONS_EXPERTISE, SubSkillType.MINING_BIGGER_BOMBS, SubSkillType.MINING_BLAST_MINING, SubSkillType.MINING_DOUBLE_DROPS)), REPAIR(RepairManager.class, Color.SILVER, - ImmutableList.of(SubSkillType.REPAIR_ARCANE_FORGING, SubSkillType.REPAIR_REPAIR_MASTERY, SubSkillType.REPAIR_SUPER_REPAIR)), + ImmutableList.of(SubSkillType.REPAIR_MASTERY, SubSkillType.REPAIR_ARCANE_FORGING, SubSkillType.REPAIR_REPAIR_MASTERY, SubSkillType.REPAIR_SUPER_REPAIR)), SALVAGE(SalvageManager.class, Color.ORANGE, ImmutableList.of(SubSkillType.SALVAGE_SCRAP_COLLECTOR, SubSkillType.SALVAGE_ARCANE_SALVAGE)), SMELTING(SmeltingManager.class, Color.YELLOW, ImmutableList.of(SubSkillType.SMELTING_UNDERSTANDING_THE_ART, /*SubSkillType.SMELTING_FLUX_MINING,*/ SubSkillType.SMELTING_FUEL_EFFICIENCY, SubSkillType.SMELTING_SECOND_SMELT)), SWORDS(SwordsManager.class, Color.fromRGB(178, 34, 34), SuperAbilityType.SERRATED_STRIKES, ToolType.SWORD, - ImmutableList.of(SubSkillType.SWORDS_SERRATED_STRIKES, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK, SubSkillType.SWORDS_STAB, SubSkillType.SWORDS_RUPTURE, SubSkillType.SWORDS_COUNTER_ATTACK)), + ImmutableList.of(SubSkillType.SWORDS_MASTERY, SubSkillType.SWORDS_SERRATED_STRIKES, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK, SubSkillType.SWORDS_STAB, SubSkillType.SWORDS_RUPTURE, SubSkillType.SWORDS_COUNTER_ATTACK)), TAMING(TamingManager.class, Color.PURPLE, - ImmutableList.of(SubSkillType.TAMING_BEAST_LORE, SubSkillType.TAMING_CALL_OF_THE_WILD, SubSkillType.TAMING_ENVIRONMENTALLY_AWARE, SubSkillType.TAMING_FAST_FOOD_SERVICE, SubSkillType.TAMING_GORE, SubSkillType.TAMING_HOLY_HOUND, SubSkillType.TAMING_SHARPENED_CLAWS, SubSkillType.TAMING_SHOCK_PROOF, SubSkillType.TAMING_THICK_FUR, SubSkillType.TAMING_PUMMEL)), + ImmutableList.of(SubSkillType.TAMING_MASTERY, SubSkillType.TAMING_BEAST_LORE, SubSkillType.TAMING_CALL_OF_THE_WILD, SubSkillType.TAMING_ENVIRONMENTALLY_AWARE, SubSkillType.TAMING_FAST_FOOD_SERVICE, SubSkillType.TAMING_GORE, SubSkillType.TAMING_HOLY_HOUND, SubSkillType.TAMING_SHARPENED_CLAWS, SubSkillType.TAMING_SHOCK_PROOF, SubSkillType.TAMING_THICK_FUR, SubSkillType.TAMING_PUMMEL)), UNARMED(UnarmedManager.class, Color.BLACK, SuperAbilityType.BERSERK, ToolType.FISTS, - ImmutableList.of(SubSkillType.UNARMED_BERSERK, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK, SubSkillType.UNARMED_BLOCK_CRACKER, SubSkillType.UNARMED_ARROW_DEFLECT, SubSkillType.UNARMED_DISARM, SubSkillType.UNARMED_STEEL_ARM_STYLE, SubSkillType.UNARMED_IRON_GRIP)), + ImmutableList.of(SubSkillType.UNARMED_MASTERY, SubSkillType.UNARMED_BERSERK, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK, SubSkillType.UNARMED_BLOCK_CRACKER, SubSkillType.UNARMED_ARROW_DEFLECT, SubSkillType.UNARMED_DISARM, SubSkillType.UNARMED_STEEL_ARM_STYLE, SubSkillType.UNARMED_IRON_GRIP)), WOODCUTTING(WoodcuttingManager.class, Color.OLIVE, SuperAbilityType.TREE_FELLER, ToolType.AXE, - ImmutableList.of(SubSkillType.WOODCUTTING_LEAF_BLOWER, SubSkillType.WOODCUTTING_TREE_FELLER, SubSkillType.WOODCUTTING_HARVEST_LUMBER, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)); + ImmutableList.of(SubSkillType.WOODCUTTING_MASTERY, SubSkillType.WOODCUTTING_LEAF_BLOWER, SubSkillType.WOODCUTTING_TREE_FELLER, SubSkillType.WOODCUTTING_HARVEST_LUMBER, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)); private final Class managerClass; private final Color skillColor; diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java index 823f6b6644..41b66a478c 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java @@ -119,9 +119,7 @@ public enum SubSkillType { /* WOODCUTTING_NATURES_BOUNTY(3), WOODCUTTING_SPLINTER(3),*/ WOODCUTTING_TREE_FELLER(1), - WOODCUTTING_MASTERY(1), - - POWER_LEVEL_MASTERY(1); + WOODCUTTING_MASTERY(1); private final int numRanks; //TODO: SuperAbilityType should also contain flags for active by default? Not sure if it should work that way. diff --git a/src/main/resources/skillranks.yml b/src/main/resources/skillranks.yml index 6e68929a04..d07377fa1d 100644 --- a/src/main/resources/skillranks.yml +++ b/src/main/resources/skillranks.yml @@ -6,6 +6,11 @@ # Retro Mode has 10x faster leveling and 10x higher skill requirements, if you do the math you can see its the same as Standard and only cosmetic!. ### Alchemy: + Mastery: + Standard: + Rank_1: 100 + RetroMode: + Rank_1: 1000 Catalysis: Standard: Rank_1: 0 @@ -31,6 +36,11 @@ Alchemy: Rank_7: 900 Rank_8: 1000 Archery: + Mastery: + Standard: + Rank_1: 100 + RetroMode: + Rank_1: 1000 ArcheryLimitBreak: Standard: Rank_1: 10 @@ -103,12 +113,22 @@ Archery: Rank_19: 950 Rank_20: 1000 Acrobatics: + Mastery: + Standard: + Rank_1: 100 + RetroMode: + Rank_1: 1000 Dodge: Standard: Rank_1: 1 RetroMode: Rank_1: 1 Axes: + Mastery: + Standard: + Rank_1: 100 + RetroMode: + Rank_1: 1000 AxesLimitBreak: Standard: Rank_1: 10 @@ -202,6 +222,11 @@ Axes: Rank_3: 150 Rank_4: 200 Taming: + Mastery: + Standard: + Rank_1: 100 + RetroMode: + Rank_1: 1000 BeastLore: Standard: Rank_1: 1 @@ -253,6 +278,11 @@ Taming: RetroMode: Rank_1: 750 Smelting: + Mastery: + Standard: + Rank_1: 100 + RetroMode: + Rank_1: 1000 FuelEfficiency: Standard: Rank_1: 10 @@ -282,6 +312,11 @@ Smelting: Rank_7: 850 Rank_8: 1000 Salvage: + Mastery: + Standard: + Rank_1: 100 + RetroMode: + Rank_1: 1000 ScrapCollector: Standard: Rank_1: 1 @@ -321,6 +356,11 @@ Salvage: Rank_7: 850 Rank_8: 1000 Mining: + Mastery: + Standard: + Rank_1: 100 + RetroMode: + Rank_1: 1000 DoubleDrops: Standard: Rank_1: 1 @@ -363,6 +403,11 @@ Mining: Rank_7: 850 Rank_8: 1000 Herbalism: + Mastery: + Standard: + Rank_1: 100 + RetroMode: + Rank_1: 1000 DoubleDrops: Standard: Rank_1: 1 @@ -398,6 +443,11 @@ Herbalism: Rank_4: 800 Rank_5: 1000 Fishing: + Mastery: + Standard: + Rank_1: 100 + RetroMode: + Rank_1: 1000 MagicHunter: Standard: Rank_1: 20 @@ -465,6 +515,11 @@ Fishing: Rank_7: 850 Rank_8: 1000 Swords: + Mastery: + Standard: + Rank_1: 100 + RetroMode: + Rank_1: 1000 SwordsLimitBreak: Standard: Rank_1: 10 @@ -517,6 +572,11 @@ Swords: RetroMode: Rank_1: 50 Unarmed: + Mastery: + Standard: + Rank_1: 100 + RetroMode: + Rank_1: 1000 UnarmedLimitBreak: Standard: Rank_1: 10 @@ -605,6 +665,11 @@ Unarmed: Rank_20: 1000 Woodcutting: + Mastery: + Standard: + Rank_1: 100 + RetroMode: + Rank_1: 1000 TreeFeller: Standard: Rank_1: 5 @@ -640,6 +705,11 @@ Woodcutting: Rank_2: 350 Rank_3: 650 Excavation: + Mastery: + Standard: + Rank_1: 100 + RetroMode: + Rank_1: 1000 GigaDrillBreaker: Standard: Rank_1: 5 @@ -665,6 +735,11 @@ Excavation: Rank_7: 850 Rank_8: 1000 Repair: + Mastery: + Standard: + Rank_1: 100 + RetroMode: + Rank_1: 1000 RepairMastery: Standard: Rank_1: 1 From 9303d441b1d567d83d27af7b2f12abd24e22afb1 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 5 Feb 2021 16:35:12 -0800 Subject: [PATCH 03/75] Change condition on power level command --- .../nossr50/commands/skills/PowerLevelCommand.java | 14 ++++++++++++-- .../nossr50/commands/skills/SkillCommand.java | 10 +++++----- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java index d15dd364a4..67e725cdc1 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java @@ -7,6 +7,7 @@ import co.aikar.commands.annotation.Conditions; import co.aikar.commands.annotation.Default; import com.gmail.nossr50.commands.CommandManager; +import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.player.UserManager; @@ -23,13 +24,22 @@ public PowerLevelCommand(@NotNull mcMMO pluginRef) { } @Default - @Conditions(CommandManager.ADMIN_CONDITION) + @Conditions(CommandManager.POWER_LEVEL_CONDITION) public void processCommand(String[] args) { BukkitCommandIssuer bukkitCommandIssuer = (BukkitCommandIssuer) getCurrentCommandIssuer(); Player player = bukkitCommandIssuer.getPlayer(); McMMOPlayer mmoPlayer = UserManager.getPlayer(player); //Should never be null at this point because its caught in an ACF validation + int powerLevel = mmoPlayer.getPowerLevel(); //TODO: impl - mmoPlayer.getPlayer().sendMessage("Your power level is: "+mmoPlayer.getPowerLevel()); //This is not gonna stay, just to show that the command executes in debug + mmoPlayer.getPlayer().sendMessage("Your power level is: "+powerLevel); //This is not gonna stay, just to show that the command executes in debug + + //Send the players a few blank lines to make finding the top of the skill command easier + if (AdvancedConfig.getInstance().doesSkillCommandSendBlankLines()) { + for (int i = 0; i < 2; i++) { + player.sendMessage(""); + } + } + } } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java index e550913fa1..00a4b52e5c 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java @@ -74,10 +74,11 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command float skillValue = mcMMOPlayer.getSkillLevel(skill); //Send the players a few blank lines to make finding the top of the skill command easier - if (AdvancedConfig.getInstance().doesSkillCommandSendBlankLines()) + if (AdvancedConfig.getInstance().doesSkillCommandSendBlankLines()) { for (int i = 0; i < 2; i++) { player.sendMessage(""); } + } permissionsCheck(player); dataCalculations(player, skillValue); @@ -136,10 +137,9 @@ private void getStatMessages(Player player, boolean isLucky, boolean hasEnduranc } private void sendSkillCommandHeader(Player player, McMMOPlayer mcMMOPlayer, int skillValue) { - ChatColor hd1 = ChatColor.DARK_AQUA; - ChatColor c1 = ChatColor.GOLD; - ChatColor c2 = ChatColor.RED; - +// ChatColor hd1 = ChatColor.DARK_AQUA; +// ChatColor c1 = ChatColor.GOLD; +// ChatColor c2 = ChatColor.RED; player.sendMessage(LocaleLoader.getString("Skills.Overhaul.Header", skillName)); From 39a6c318942a0cb71a66b9ddea9344e0a96bf7bb Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 8 Feb 2021 11:02:12 -0800 Subject: [PATCH 04/75] Add permission nodes for mastery subskills --- Changelog.txt | 17 +++++++++++++ src/main/resources/plugin.yml | 45 +++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/Changelog.txt b/Changelog.txt index 185aaea358..9a226ab709 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -2,6 +2,23 @@ Version 2.1.175 Added a new mastery sub-skill to each skill (see notes) Added /mmopower command (aliases /mmopowerlevel /powerlevel) Added 'mcmmo.commands.mmopower' permission node + Added 'mcmmo.ability.acrobatics.mastery' permission node + Added 'mcmmo.ability.alchemy.mastery' permission node + Added 'mcmmo.ability.archery.mastery' permission node + Added 'mcmmo.ability.axes.mastery' permission node + Added 'mcmmo.ability.excavation.mastery' permission node + Added 'mcmmo.ability.fishing.mastery' permission node + Added 'mcmmo.ability.herbalism.mastery' permission node + Added 'mcmmo.ability.mining.mastery' permission node + Added 'mcmmo.ability.repair.mastery' permission node + Added 'mcmmo.ability.salvage.mastery' permission node + Added 'mcmmo.ability.smelting.mastery' permission node + Added 'mcmmo.ability.salvage.mastery' permission node + Added 'mcmmo.ability.swords.mastery' permission node + Added 'mcmmo.ability.taming.mastery' permission node + Added 'mcmmo.ability.unarmed.mastery' permission node + Added 'mcmmo.ability.woodcutting.mastery' permission node + Added 'General.PowerLevel.Skill_Mastery.Enabled' to config.yml which is used to enable or disable the mastery skills (will also disable the new power level command) NOTES: diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index a63be2f846..50be749db8 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -260,6 +260,9 @@ permissions: children: mcmmo.ability.acrobatics.dodge: true mcmmo.ability.acrobatics.roll: true + mcmmo.ability.acrobatics.mastery: true + mcmmo.ability.acrobatics.mastery: + description: Allows access to end game progression for Acrobatics mcmmo.ability.acrobatics.dodge: description: Allows access to the Dodge ability mcmmo.ability.acrobatics.roll: @@ -274,6 +277,9 @@ permissions: children: mcmmo.ability.alchemy.catalysis: true mcmmo.ability.alchemy.concoctions: true + mcmmo.ability.alchemy.mastery: true + mcmmo.ability.alchemy.mastery: + description: Allows access to end game progression for Alchemy mcmmo.ability.alchemy.catalysis: description: Allows access to the Catalysis ability mcmmo.ability.alchemy.concoctions: @@ -290,6 +296,9 @@ permissions: mcmmo.ability.archery.daze: true mcmmo.ability.archery.arrowretrieval: true mcmmo.ability.archery.archerylimitbreak: true + mcmmo.ability.archery.mastery: true + mcmmo.ability.archery.mastery: + description: Allows access to end game progression for Archery mcmmo.ability.archery.archerylimitbreak: description: Adds damage to bows and crossbows mcmmo.ability.archery.skillshot: @@ -312,6 +321,9 @@ permissions: mcmmo.ability.axes.armorimpact: true mcmmo.ability.axes.skullsplitter: true mcmmo.ability.axes.axeslimitbreak: true + mcmmo.ability.axes.mastery: true + mcmmo.ability.axes.mastery: + description: Allows access to end game progression for Axes mcmmo.ability.axes.axeslimitbreak: description: Adds damage to axes mcmmo.ability.axes.axemastery: @@ -334,6 +346,9 @@ permissions: children: mcmmo.ability.excavation.gigadrillbreaker: true mcmmo.ability.excavation.archaeology: true + mcmmo.ability.excavation.mastery: true + mcmmo.ability.excavation.mastery: + description: Allows access to end game progression for Excavation mcmmo.ability.excavation.gigadrillbreaker: description: Allows access to the Giga Drill Breaker ability mcmmo.ability.excavation.archaeology: @@ -353,6 +368,9 @@ permissions: mcmmo.ability.fishing.shake: true mcmmo.ability.fishing.treasurehunter: true mcmmo.ability.fishing.vanillaxpboost: true + mcmmo.ability.fishing.mastery: true + mcmmo.ability.fishing.mastery: + description: Allows access to end game progression for Fishing mcmmo.ability.fishing.fishermansdiet: description: Allows access to the Fishermans's Diet ability mcmmo.ability.fishing.icefishing: @@ -381,6 +399,9 @@ permissions: mcmmo.ability.herbalism.greenthumb.all: true mcmmo.ability.herbalism.hylianluck: true mcmmo.ability.herbalism.shroomthumb: true + mcmmo.ability.herbalism.mastery: true + mcmmo.ability.herbalism.mastery: + description: Allows access to end game progression for Herbalism mcmmo.ability.herbalism.doubledrops: description: Allows double drop chance from Herbalism mcmmo.ability.herbalism.farmersdiet: @@ -461,6 +482,7 @@ permissions: mcmmo.ability.mining.blastmining.all: true mcmmo.ability.mining.doubledrops: true mcmmo.ability.mining.superbreaker: true + mcmmo.ability.mining.mastery: true mcmmo.ability.mining.blastmining.*: default: false description: Allows access to all Blast Mining abilities @@ -478,6 +500,8 @@ permissions: description: Allows access to the Demolitions Expertise ability mcmmo.ability.mining.blastmining.detonate: description: Allows for remote TNT detonation + mcmmo.ability.mining.mastery: + description: Allows access to end game progression for Mining mcmmo.ability.mining.doubledrops: description: Allows double drop chance when mining mcmmo.ability.mining.superbreaker: @@ -506,6 +530,9 @@ permissions: mcmmo.ability.repair.stringrepair: true mcmmo.ability.repair.toolrepair: true mcmmo.ability.repair.woodrepair: true + mcmmo.ability.repair.mastery: true + mcmmo.ability.repair.mastery: + description: Allows access to end game progression for Repair mcmmo.ability.repair.arcaneforging: description: Allows access to the Arcane Forging ability mcmmo.ability.repair.armorrepair: @@ -558,6 +585,9 @@ permissions: mcmmo.ability.salvage.stringsalvage: true mcmmo.ability.salvage.toolsalvage: true mcmmo.ability.salvage.woodsalvage: true + mcmmo.ability.salvage.mastery: true + mcmmo.ability.salvage.mastery: + description: Allows access to end game progression for Salvage mcmmo.ability.salvage.scrapcollector: description: Allows access to the Scrap Collector ability mcmmo.ability.salvage.arcanesalvage: @@ -598,6 +628,9 @@ permissions: mcmmo.ability.smelting.fluxmining: true mcmmo.ability.smelting.fuelefficiency: true mcmmo.ability.smelting.vanillaxpboost: true + mcmmo.ability.smelting.mastery: true + mcmmo.ability.smelting.mastery: + description: Allows access to end game progression for Smelting mcmmo.ability.smelting.fluxmining: description: Allows access to the Flux Mining ability mcmmo.ability.smelting.fuelefficiency: @@ -619,6 +652,9 @@ permissions: mcmmo.ability.swords.counterattack: true mcmmo.ability.swords.serratedstrikes: true mcmmo.ability.swords.swordslimitbreak: true + mcmmo.ability.swords.mastery: true + mcmmo.ability.swords.mastery: + description: Allows access to end game progression for Swords mcmmo.ability.swords.stab: description: Adds damage to swords mcmmo.ability.swords.swordslimitbreak: @@ -647,6 +683,9 @@ permissions: mcmmo.ability.taming.shockproof: true mcmmo.ability.taming.thickfur: true mcmmo.ability.taming.pummel: true + mcmmo.ability.taming.mastery: true + mcmmo.ability.taming.mastery: + description: Allows access to end game progression for Taming mcmmo.ability.taming.beastlore: description: Allows access to the Beast Lore ability mcmmo.ability.taming.callofthewild.*: @@ -697,6 +736,9 @@ permissions: mcmmo.ability.unarmed.disarm: true mcmmo.ability.unarmed.irongrip: true mcmmo.ability.unarmed.unarmedlimitbreak: true + mcmmo.ability.unarmed.mastery: true + mcmmo.ability.unarmed.mastery: + description: Allows access to end game progression for Unarmed mcmmo.ability.unarmed.unarmedlimitbreak: description: Adds damage to unarmed attacks mcmmo.ability.unarmed.berserk: @@ -726,6 +768,9 @@ permissions: mcmmo.ability.woodcutting.knockonwood: true mcmmo.ability.woodcutting.leafblower: true mcmmo.ability.woodcutting.treefeller: true + mcmmo.ability.woodcutting.mastery: true + mcmmo.ability.woodcutting.mastery: + description: Allows access to end game progression for Woodcutting mcmmo.ability.woodcutting.knockonwood: description: Allows access to Knock on Wood subskill mcmmo.ability.woodcutting.splinter: From 1ff2c0dcfc7d1a19c5df2621fb58243f35b31643 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 8 Feb 2021 11:57:43 -0800 Subject: [PATCH 05/75] Add Mother Lode mastery subskill to Mining --- Changelog.txt | 18 +++++++++++- .../commands/skills/AcrobaticsCommand.java | 5 ++-- .../commands/skills/AlchemyCommand.java | 4 +-- .../commands/skills/ArcheryCommand.java | 9 +++--- .../nossr50/commands/skills/AxesCommand.java | 10 +++---- .../commands/skills/ExcavationCommand.java | 4 +-- .../commands/skills/FishingCommand.java | 13 +++++---- .../commands/skills/HerbalismCommand.java | 8 ++--- .../commands/skills/MiningCommand.java | 17 ++++++++++- .../commands/skills/RepairCommand.java | 6 ++-- .../commands/skills/SalvageCommand.java | 5 ++-- .../nossr50/commands/skills/SkillCommand.java | 11 ------- .../commands/skills/SmeltingCommand.java | 4 +-- .../commands/skills/SwordsCommand.java | 8 ++--- .../commands/skills/TamingCommand.java | 16 +++++----- .../commands/skills/UnarmedCommand.java | 10 +++---- .../commands/skills/WoodcuttingCommand.java | 6 ++-- .../nossr50/skills/mining/MiningManager.java | 29 +++++++++++++++++++ .../com/gmail/nossr50/util/BlockUtils.java | 5 ++-- .../com/gmail/nossr50/util/Permissions.java | 14 +++++++++ src/main/resources/advanced.yml | 5 ++++ .../resources/locale/locale_en_US.properties | 8 ++++- 22 files changed, 147 insertions(+), 68 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 9a226ab709..73a9721b37 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,7 @@ Version 2.1.175 - Added a new mastery sub-skill to each skill (see notes) + Added a set of "mastery" subskills meant for end game progression + Added the mastery subskill 'Mother Lode' to Mining + Added the mastery subskill 'Clean Cuts' to Woodcutting Added /mmopower command (aliases /mmopowerlevel /powerlevel) Added 'mcmmo.commands.mmopower' permission node Added 'mcmmo.ability.acrobatics.mastery' permission node @@ -18,15 +20,29 @@ Version 2.1.175 Added 'mcmmo.ability.taming.mastery' permission node Added 'mcmmo.ability.unarmed.mastery' permission node Added 'mcmmo.ability.woodcutting.mastery' permission node + Added 'Mining.SubSkill.Mastery.Name' to locale + Added 'Mining.SubSkill.Mastery.Stat' to locale + Added 'Mining.SubSkill.Mastery.Description' to locale + Added 'Woodcutting.SubSkill.Mastery.Name' to locale + Added 'Woodcutting.SubSkill.Mastery.Stat' to locale + Added 'Woodcutting.SubSkill.Mastery.Description' to locale Added 'General.PowerLevel.Skill_Mastery.Enabled' to config.yml which is used to enable or disable the mastery skills (will also disable the new power level command) NOTES: + The goal of this update is to provide a small benefit to each skill and a reason to grind past the "maximum", ideally for a long while. Most skills have a mastery sub-skill, this mastery subskill provides a small benefit that scales to level 10,000 (or 1,000 for standard) and does not have ranks (other than the initial rank to unlock it) Mastery skills unlock at level 1000 for RetroMode (the default setting), and 100 for Standard, you can edit this via skillranks.yml Mastery skills are meant to provide an "end-game" to skills, a reason to continue leveling a skill past its "max". This system is brand new, it is entirely possible I will completely change, remove, or add more mastery skills in the future. + The section below assumes RetroMode, if you are using Standard mode (1-100) just divide level examples by 10. + + Mastery Skills + Mining (Mastery Triple Drops): With default settings, when players hit level 1,000 they will unlock this sub-skill, it will add a 1% chance to get triple drops while mining (this can be edited in advanced.yml), this skill maxes out at 10.0% chance at level 10,000. + This skill respects double drop settings from the config files. + Double Drops only occur if the Triple Drops fail, these two skills do not stack. + New Power Level Command This power level command gives you a view of all your current masteries, it also provides a summary of your power level. diff --git a/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java index 9b6e8ea2f9..46ba32b288 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java @@ -5,6 +5,7 @@ import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.listeners.InteractionManager; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.random.RandomChanceSkill; import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.SkillActivationType; @@ -38,8 +39,8 @@ protected void dataCalculations(Player player, float skillValue) { @Override protected void permissionsCheck(Player player) { - canDodge = canUseSubskill(player, SubSkillType.ACROBATICS_DODGE); - canRoll = canUseSubskill(player, SubSkillType.ACROBATICS_ROLL); + canDodge = Permissions.canUseSubSkill(player, SubSkillType.ACROBATICS_DODGE); + canRoll = Permissions.canUseSubSkill(player, SubSkillType.ACROBATICS_ROLL); } @Override diff --git a/src/main/java/com/gmail/nossr50/commands/skills/AlchemyCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/AlchemyCommand.java index a8d5fcc8be..be34ebe2f4 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/AlchemyCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/AlchemyCommand.java @@ -68,8 +68,8 @@ protected void dataCalculations(Player player, float skillValue) { @Override protected void permissionsCheck(Player player) { - canCatalysis = canUseSubskill(player, SubSkillType.ALCHEMY_CATALYSIS); - canConcoctions = canUseSubskill(player, SubSkillType.ALCHEMY_CONCOCTIONS); + canCatalysis = Permissions.canUseSubSkill(player, SubSkillType.ALCHEMY_CATALYSIS); + canConcoctions = Permissions.canUseSubSkill(player, SubSkillType.ALCHEMY_CONCOCTIONS); } @Override diff --git a/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java index 59decaf9f8..ec5c630085 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java @@ -4,6 +4,7 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.skills.archery.Archery; +import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.text.TextComponentFactory; @@ -52,9 +53,9 @@ protected void dataCalculations(Player player, float skillValue) { @Override protected void permissionsCheck(Player player) { - canSkillShot = canUseSubskill(player, SubSkillType.ARCHERY_SKILL_SHOT); - canDaze = canUseSubskill(player, SubSkillType.ARCHERY_DAZE); - canRetrieve = canUseSubskill(player, SubSkillType.ARCHERY_ARROW_RETRIEVAL); + canSkillShot = Permissions.canUseSubSkill(player, SubSkillType.ARCHERY_SKILL_SHOT); + canDaze = Permissions.canUseSubSkill(player, SubSkillType.ARCHERY_DAZE); + canRetrieve = Permissions.canUseSubSkill(player, SubSkillType.ARCHERY_ARROW_RETRIEVAL); } @Override @@ -75,7 +76,7 @@ protected List statsDisplay(Player player, float skillValue, boolean has messages.add(getStatMessage(SubSkillType.ARCHERY_SKILL_SHOT, skillShotBonus)); } - if(canUseSubskill(player, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK)) { + if(Permissions.canUseSubSkill(player, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK)) { messages.add(getStatMessage(SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK, String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK, 1000)))); } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java index d6b5c029a2..2e61db48e0 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java @@ -64,10 +64,10 @@ protected void dataCalculations(Player player, float skillValue) { @Override protected void permissionsCheck(Player player) { canSkullSplitter = Permissions.skullSplitter(player) && RankUtils.hasUnlockedSubskill(player, SubSkillType.AXES_SKULL_SPLITTER); - canCritical = canUseSubskill(player, SubSkillType.AXES_CRITICAL_STRIKES); - canAxeMastery = canUseSubskill(player, SubSkillType.AXES_AXE_MASTERY); - canImpact = canUseSubskill(player, SubSkillType.AXES_ARMOR_IMPACT); - canGreaterImpact = canUseSubskill(player, SubSkillType.AXES_GREATER_IMPACT); + canCritical = Permissions.canUseSubSkill(player, SubSkillType.AXES_CRITICAL_STRIKES); + canAxeMastery = Permissions.canUseSubSkill(player, SubSkillType.AXES_AXE_MASTERY); + canImpact = Permissions.canUseSubSkill(player, SubSkillType.AXES_ARMOR_IMPACT); + canGreaterImpact = Permissions.canUseSubSkill(player, SubSkillType.AXES_GREATER_IMPACT); } @Override @@ -96,7 +96,7 @@ protected List statsDisplay(Player player, float skillValue, boolean has + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", skullSplitterLengthEndurance) : "")); } - if(canUseSubskill(player, SubSkillType.AXES_AXES_LIMIT_BREAK)) { + if(Permissions.canUseSubSkill(player, SubSkillType.AXES_AXES_LIMIT_BREAK)) { messages.add(getStatMessage(SubSkillType.AXES_AXES_LIMIT_BREAK, String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, SubSkillType.AXES_AXES_LIMIT_BREAK, 1000)))); } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/ExcavationCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/ExcavationCommand.java index de7341e936..952766b151 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/ExcavationCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/ExcavationCommand.java @@ -38,7 +38,7 @@ protected void dataCalculations(Player player, float skillValue) { @Override protected void permissionsCheck(Player player) { canGigaDrill = Permissions.gigaDrillBreaker(player) && RankUtils.hasUnlockedSubskill(player, SubSkillType.EXCAVATION_GIGA_DRILL_BREAKER); - canTreasureHunt = canUseSubskill(player, SubSkillType.EXCAVATION_ARCHAEOLOGY); + canTreasureHunt = Permissions.canUseSubSkill(player, SubSkillType.EXCAVATION_ARCHAEOLOGY); } @Override @@ -54,7 +54,7 @@ protected List statsDisplay(Player player, float skillValue, boolean has //messages.add(LocaleLoader.getString("Excavation.Effect.Length", gigaDrillBreakerLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", gigaDrillBreakerLengthEndurance) : "")); } - if(canUseSubskill(player, SubSkillType.EXCAVATION_ARCHAEOLOGY)) { + if(Permissions.canUseSubSkill(player, SubSkillType.EXCAVATION_ARCHAEOLOGY)) { messages.add(getStatMessage(false, false, SubSkillType.EXCAVATION_ARCHAEOLOGY, percent.format(excavationManager.getArchaelogyExperienceOrbChance() / 100.0D))); messages.add(getStatMessage(true, false, SubSkillType.EXCAVATION_ARCHAEOLOGY, diff --git a/src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java index f22f8399e3..4d3409a232 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java @@ -7,6 +7,7 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.fishing.FishingManager; +import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.RankUtils; @@ -98,12 +99,12 @@ protected void dataCalculations(Player player, float skillValue) { @Override protected void permissionsCheck(Player player) { - canTreasureHunt = canUseSubskill(player, SubSkillType.FISHING_TREASURE_HUNTER); - canMagicHunt = canUseSubskill(player, SubSkillType.FISHING_MAGIC_HUNTER) && canUseSubskill(player, SubSkillType.FISHING_TREASURE_HUNTER); - canShake = canUseSubskill(player, SubSkillType.FISHING_SHAKE); - canFishermansDiet = canUseSubskill(player, SubSkillType.FISHING_FISHERMANS_DIET); - canMasterAngler = mcMMO.getCompatibilityManager().getMasterAnglerCompatibilityLayer() != null && canUseSubskill(player, SubSkillType.FISHING_MASTER_ANGLER); - canIceFish = canUseSubskill(player, SubSkillType.FISHING_ICE_FISHING); + canTreasureHunt = Permissions.canUseSubSkill(player, SubSkillType.FISHING_TREASURE_HUNTER); + canMagicHunt = Permissions.canUseSubSkill(player, SubSkillType.FISHING_MAGIC_HUNTER) && Permissions.canUseSubSkill(player, SubSkillType.FISHING_TREASURE_HUNTER); + canShake = Permissions.canUseSubSkill(player, SubSkillType.FISHING_SHAKE); + canFishermansDiet = Permissions.canUseSubSkill(player, SubSkillType.FISHING_FISHERMANS_DIET); + canMasterAngler = mcMMO.getCompatibilityManager().getMasterAnglerCompatibilityLayer() != null && Permissions.canUseSubSkill(player, SubSkillType.FISHING_MASTER_ANGLER); + canIceFish = Permissions.canUseSubSkill(player, SubSkillType.FISHING_ICE_FISHING); } @Override diff --git a/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java index 3d4693b77d..ecba231d1d 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java @@ -88,13 +88,13 @@ protected void dataCalculations(Player player, float skillValue) { @Override protected void permissionsCheck(Player player) { - hasHylianLuck = canUseSubskill(player, SubSkillType.HERBALISM_HYLIAN_LUCK); + hasHylianLuck = Permissions.canUseSubSkill(player, SubSkillType.HERBALISM_HYLIAN_LUCK); canGreenTerra = Permissions.greenTerra(player); canGreenThumbPlants = RankUtils.hasUnlockedSubskill(player, SubSkillType.HERBALISM_GREEN_THUMB) && (Permissions.greenThumbPlant(player, Material.WHEAT) || Permissions.greenThumbPlant(player, Material.CARROT) || Permissions.greenThumbPlant(player, Material.POTATO) || Permissions.greenThumbPlant(player, Material.BEETROOT) || Permissions.greenThumbPlant(player, Material.NETHER_WART) || Permissions.greenThumbPlant(player, Material.COCOA)); canGreenThumbBlocks = RankUtils.hasUnlockedSubskill(player, SubSkillType.HERBALISM_GREEN_THUMB) && (Permissions.greenThumbBlock(player, Material.DIRT) || Permissions.greenThumbBlock(player, Material.COBBLESTONE) || Permissions.greenThumbBlock(player, Material.COBBLESTONE_WALL) || Permissions.greenThumbBlock(player, Material.STONE_BRICKS)); - canFarmersDiet = canUseSubskill(player, SubSkillType.HERBALISM_FARMERS_DIET); - canDoubleDrop = canUseSubskill(player, SubSkillType.HERBALISM_DOUBLE_DROPS) && !skill.getDoubleDropsDisabled(); - canShroomThumb = canUseSubskill(player, SubSkillType.HERBALISM_SHROOM_THUMB); + canFarmersDiet = Permissions.canUseSubSkill(player, SubSkillType.HERBALISM_FARMERS_DIET); + canDoubleDrop = Permissions.canUseSubSkill(player, SubSkillType.HERBALISM_DOUBLE_DROPS) && !skill.getDoubleDropsDisabled(); + canShroomThumb = Permissions.canUseSubSkill(player, SubSkillType.HERBALISM_SHROOM_THUMB); } @Override diff --git a/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java index 5e7a14a7aa..1836423a21 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java @@ -18,6 +18,8 @@ public class MiningCommand extends SkillCommand { private String doubleDropChance; private String doubleDropChanceLucky; + private String masteryTripleDropChance; + private String masteryTripleDropChanceLucky; private String superBreakerLength; private String superBreakerLengthEndurance; @@ -51,6 +53,14 @@ protected void dataCalculations(Player player, float skillValue) { blastDamageDecrease = percent.format(miningManager.getBlastDamageModifier() / 100.0D); blastRadiusIncrease = miningManager.getBlastRadiusModifier(); } + + // Mastery TRIPLE DROPS + if (Permissions.canUseSubSkill(player, SubSkillType.MINING_MASTERY)) { + String[] masteryTripleDropStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.MINING_MASTERY); + masteryTripleDropChance = masteryTripleDropStrings[0]; + masteryTripleDropChanceLucky = masteryTripleDropStrings[1]; + } + // DOUBLE DROPS if (canDoubleDrop) { @@ -72,7 +82,7 @@ protected void permissionsCheck(Player player) { canBiggerBombs = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_BIGGER_BOMBS) && Permissions.biggerBombs(player); canBlast = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_BLAST_MINING) && Permissions.remoteDetonation(player); canDemoExpert = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_DEMOLITIONS_EXPERTISE) && Permissions.demolitionsExpertise(player); - canDoubleDrop = canUseSubskill(player, SubSkillType.MINING_DOUBLE_DROPS); + canDoubleDrop = Permissions.canUseSubSkill(player, SubSkillType.MINING_DOUBLE_DROPS); canSuperBreaker = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_SUPER_BREAKER) && Permissions.superBreaker(player); } @@ -94,6 +104,11 @@ protected List statsDisplay(Player player, float skillValue, boolean has messages.add(getStatMessage(SubSkillType.MINING_DEMOLITIONS_EXPERTISE, blastDamageDecrease)); //messages.add(LocaleLoader.getString("Mining.Effect.Decrease", blastDamageDecrease)); } + + if(Permissions.canUseSubSkill(player, SubSkillType.MINING_MASTERY)) { + messages.add(getStatMessage(SubSkillType.MINING_MASTERY, masteryTripleDropChance) + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", masteryTripleDropChanceLucky) : "")); + } if (canDoubleDrop) { messages.add(getStatMessage(SubSkillType.MINING_DOUBLE_DROPS, doubleDropChance) diff --git a/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java index 1941357d09..8cb9b52fec 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java @@ -76,9 +76,9 @@ protected void dataCalculations(Player player, float skillValue) { @Override protected void permissionsCheck(Player player) { - canSuperRepair = canUseSubskill(player, SubSkillType.REPAIR_SUPER_REPAIR); - canMasterRepair = canUseSubskill(player, SubSkillType.REPAIR_REPAIR_MASTERY); - canArcaneForge = canUseSubskill(player, SubSkillType.REPAIR_ARCANE_FORGING); + canSuperRepair = Permissions.canUseSubSkill(player, SubSkillType.REPAIR_SUPER_REPAIR); + canMasterRepair = Permissions.canUseSubSkill(player, SubSkillType.REPAIR_REPAIR_MASTERY); + canArcaneForge = Permissions.canUseSubSkill(player, SubSkillType.REPAIR_ARCANE_FORGING); canRepairDiamond = Permissions.repairMaterialType(player, MaterialType.DIAMOND); canRepairGold = Permissions.repairMaterialType(player, MaterialType.GOLD); canRepairIron = Permissions.repairMaterialType(player, MaterialType.IRON); diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SalvageCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SalvageCommand.java index 770299951c..93a748023c 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SalvageCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SalvageCommand.java @@ -5,6 +5,7 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.skills.salvage.Salvage; import com.gmail.nossr50.skills.salvage.SalvageManager; +import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.text.TextComponentFactory; @@ -30,8 +31,8 @@ protected void dataCalculations(Player player, float skillValue) { @Override protected void permissionsCheck(Player player) { - canScrapCollector = canUseSubskill(player, SubSkillType.SALVAGE_SCRAP_COLLECTOR); - canArcaneSalvage = canUseSubskill(player, SubSkillType.SALVAGE_ARCANE_SALVAGE); + canScrapCollector = Permissions.canUseSubSkill(player, SubSkillType.SALVAGE_SCRAP_COLLECTOR); + canArcaneSalvage = Permissions.canUseSubSkill(player, SubSkillType.SALVAGE_ARCANE_SALVAGE); } @Override diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java index 00a4b52e5c..ee1ecb2027 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java @@ -14,7 +14,6 @@ import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.gmail.nossr50.util.skills.PerksUtils; -import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.text.StringUtils; import com.gmail.nossr50.util.text.TextComponentFactory; @@ -285,14 +284,4 @@ protected String getLimitBreakDescriptionParameter() { protected abstract List getTextComponents(Player player); - /** - * Checks if a player can use a skill - * @param player target player - * @param subSkillType target subskill - * @return true if the player has permission and has the skill unlocked - */ - protected boolean canUseSubskill(Player player, SubSkillType subSkillType) - { - return Permissions.isSubSkillEnabled(player, subSkillType) && RankUtils.hasUnlockedSubskill(player, subSkillType); - } } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java index 55544acc29..7b039ea7ed 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java @@ -54,8 +54,8 @@ protected void dataCalculations(Player player, float skillValue) { @Override protected void permissionsCheck(Player player) { - canFuelEfficiency = canUseSubskill(player, SubSkillType.SMELTING_FUEL_EFFICIENCY); - canSecondSmelt = canUseSubskill(player, SubSkillType.SMELTING_SECOND_SMELT); + canFuelEfficiency = Permissions.canUseSubSkill(player, SubSkillType.SMELTING_FUEL_EFFICIENCY); + canSecondSmelt = Permissions.canUseSubSkill(player, SubSkillType.SMELTING_SECOND_SMELT); //canFluxMine = canUseSubskill(player, SubSkillType.SMELTING_FLUX_MINING); canUnderstandTheArt = Permissions.vanillaXpBoost(player, skill) && RankUtils.hasUnlockedSubskill(player, SubSkillType.SMELTING_UNDERSTANDING_THE_ART); } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java index 1e6bf1d72f..7655ce680a 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java @@ -61,8 +61,8 @@ protected void dataCalculations(Player player, float skillValue) { @Override protected void permissionsCheck(Player player) { - canBleed = canUseSubskill(player, SubSkillType.SWORDS_RUPTURE); - canCounter = canUseSubskill(player, SubSkillType.SWORDS_COUNTER_ATTACK); + canBleed = Permissions.canUseSubSkill(player, SubSkillType.SWORDS_RUPTURE); + canCounter = Permissions.canUseSubSkill(player, SubSkillType.SWORDS_COUNTER_ATTACK); canSerratedStrike = RankUtils.hasUnlockedSubskill(player, SubSkillType.SWORDS_SERRATED_STRIKES) && Permissions.serratedStrikes(player); } @@ -95,13 +95,13 @@ protected List statsDisplay(Player player, float skillValue, boolean has + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", serratedStrikesLengthEndurance) : "")); } - if(canUseSubskill(player, SubSkillType.SWORDS_STAB)) + if(Permissions.canUseSubSkill(player, SubSkillType.SWORDS_STAB)) { messages.add(getStatMessage(SubSkillType.SWORDS_STAB, String.valueOf(UserManager.getPlayer(player).getSwordsManager().getStabDamage()))); } - if(canUseSubskill(player, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK)) { + if(Permissions.canUseSubSkill(player, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK)) { messages.add(getStatMessage(SubSkillType.SWORDS_SWORDS_LIMIT_BREAK, String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK, 1000)))); } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java index 35f04f5bc6..e007799dbc 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java @@ -43,15 +43,15 @@ protected void dataCalculations(Player player, float skillValue) { @Override protected void permissionsCheck(Player player) { - canBeastLore = canUseSubskill(player, SubSkillType.TAMING_BEAST_LORE); + canBeastLore = Permissions.canUseSubSkill(player, SubSkillType.TAMING_BEAST_LORE); canCallWild = Permissions.callOfTheWild(player, EntityType.HORSE) || Permissions.callOfTheWild(player, EntityType.WOLF) || Permissions.callOfTheWild(player, EntityType.OCELOT); - canEnvironmentallyAware = canUseSubskill(player, SubSkillType.TAMING_ENVIRONMENTALLY_AWARE); - canFastFood = canUseSubskill(player, SubSkillType.TAMING_FAST_FOOD_SERVICE); - canGore = canUseSubskill(player, SubSkillType.TAMING_GORE); - canSharpenedClaws = canUseSubskill(player, SubSkillType.TAMING_SHARPENED_CLAWS); - canShockProof = canUseSubskill(player, SubSkillType.TAMING_SHOCK_PROOF); - canThickFur = canUseSubskill(player, SubSkillType.TAMING_THICK_FUR); - canHolyHound = canUseSubskill(player, SubSkillType.TAMING_HOLY_HOUND); + canEnvironmentallyAware = Permissions.canUseSubSkill(player, SubSkillType.TAMING_ENVIRONMENTALLY_AWARE); + canFastFood = Permissions.canUseSubSkill(player, SubSkillType.TAMING_FAST_FOOD_SERVICE); + canGore = Permissions.canUseSubSkill(player, SubSkillType.TAMING_GORE); + canSharpenedClaws = Permissions.canUseSubSkill(player, SubSkillType.TAMING_SHARPENED_CLAWS); + canShockProof = Permissions.canUseSubSkill(player, SubSkillType.TAMING_SHOCK_PROOF); + canThickFur = Permissions.canUseSubSkill(player, SubSkillType.TAMING_THICK_FUR); + canHolyHound = Permissions.canUseSubSkill(player, SubSkillType.TAMING_HOLY_HOUND); } @Override diff --git a/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java index 5f9784be71..ee52401e6e 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java @@ -75,10 +75,10 @@ protected void dataCalculations(Player player, float skillValue) { @Override protected void permissionsCheck(Player player) { canBerserk = RankUtils.hasUnlockedSubskill(player, SubSkillType.UNARMED_BERSERK) && Permissions.berserk(player); - canIronArm = canUseSubskill(player, SubSkillType.UNARMED_STEEL_ARM_STYLE); - canDeflect = canUseSubskill(player, SubSkillType.UNARMED_ARROW_DEFLECT); - canDisarm = canUseSubskill(player, SubSkillType.UNARMED_DISARM); - canIronGrip = canUseSubskill(player, SubSkillType.UNARMED_IRON_GRIP); + canIronArm = Permissions.canUseSubSkill(player, SubSkillType.UNARMED_STEEL_ARM_STYLE); + canDeflect = Permissions.canUseSubSkill(player, SubSkillType.UNARMED_ARROW_DEFLECT); + canDisarm = Permissions.canUseSubSkill(player, SubSkillType.UNARMED_DISARM); + canIronGrip = Permissions.canUseSubSkill(player, SubSkillType.UNARMED_IRON_GRIP); // TODO: Apparently we forgot about block cracker? } @@ -114,7 +114,7 @@ protected List statsDisplay(Player player, float skillValue, boolean has //messages.add(LocaleLoader.getString("Unarmed.Ability.Chance.IronGrip", ironGripChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", ironGripChanceLucky) : "")); } - if(canUseSubskill(player, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK)) { + if(Permissions.canUseSubSkill(player, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK)) { messages.add(getStatMessage(SubSkillType.UNARMED_UNARMED_LIMIT_BREAK, String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK, 1000)))); } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java index a817a312dd..75c3e74e25 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java @@ -55,9 +55,9 @@ private void setDoubleDropClassicChanceStrings(Player player) { @Override protected void permissionsCheck(Player player) { canTreeFell = RankUtils.hasUnlockedSubskill(player, SubSkillType.WOODCUTTING_TREE_FELLER) && Permissions.treeFeller(player); - canDoubleDrop = canUseSubskill(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) && !skill.getDoubleDropsDisabled() && RankUtils.getRank(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) >= 1; - canLeafBlow = canUseSubskill(player, SubSkillType.WOODCUTTING_LEAF_BLOWER); - canKnockOnWood = canTreeFell && canUseSubskill(player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD); + canDoubleDrop = Permissions.canUseSubSkill(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) && !skill.getDoubleDropsDisabled() && RankUtils.getRank(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) >= 1; + canLeafBlow = Permissions.canUseSubSkill(player, SubSkillType.WOODCUTTING_LEAF_BLOWER); + canKnockOnWood = canTreeFell && Permissions.canUseSubSkill(player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD); /*canSplinter = canUseSubskill(player, SubSkillType.WOODCUTTING_SPLINTER); canBarkSurgeon = canUseSubskill(player, SubSkillType.WOODCUTTING_BARK_SURGEON); canNaturesBounty = canUseSubskill(player, SubSkillType.WOODCUTTING_NATURES_BOUNTY);*/ diff --git a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java index 868cdaad1b..d574477a72 100644 --- a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java +++ b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java @@ -28,6 +28,7 @@ import org.bukkit.entity.TNTPrimed; import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; @@ -68,6 +69,11 @@ public boolean canDoubleDrop() { return RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS) && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS); } + public boolean canMiningMastery() { + return Permissions.canUseSubSkill(getPlayer(), SubSkillType.MINING_MASTERY); + } + + /** * Process double drops & XP gain for Mining. * @@ -94,6 +100,29 @@ public void miningBlockCheck(BlockState blockState) { if(silkTouch && !AdvancedConfig.getInstance().getDoubleDropSilkTouchEnabled()) return; + //Mining mastery allows for a chance of triple drops + if(canMiningMastery()) { + //Triple Drops failed so do a normal double drops check + if(!processTripleDrops(blockState)) { + processDoubleDrops(blockState); + } + } else { + //If the user has no mastery, proceed with normal double drop routine + processDoubleDrops(blockState); + } + } + + private boolean processTripleDrops(@NotNull BlockState blockState) { + //TODO: Make this readable + if (RandomChanceUtil.checkRandomChanceExecutionSuccess(getPlayer(), SubSkillType.MINING_MASTERY, true)) { + BlockUtils.markDropsAsBonus(blockState, 2); + return true; + } else { + return false; + } + } + + private void processDoubleDrops(@NotNull BlockState blockState) { //TODO: Make this readable if (RandomChanceUtil.checkRandomChanceExecutionSuccess(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS, true)) { boolean useTriple = mmoPlayer.getAbilityMode(skill.getAbility()) && AdvancedConfig.getInstance().getAllowMiningTripleDrops(); diff --git a/src/main/java/com/gmail/nossr50/util/BlockUtils.java b/src/main/java/com/gmail/nossr50/util/BlockUtils.java index 8a443c119c..80c5a3ca15 100644 --- a/src/main/java/com/gmail/nossr50/util/BlockUtils.java +++ b/src/main/java/com/gmail/nossr50/util/BlockUtils.java @@ -16,6 +16,7 @@ import org.bukkit.block.data.Ageable; import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; import java.util.HashSet; @@ -30,7 +31,7 @@ private BlockUtils() { * @param blockState target blockstate * @param triple marks the block to give triple drops */ - public static void markDropsAsBonus(BlockState blockState, boolean triple) { + public static void markDropsAsBonus(@NotNull BlockState blockState, boolean triple) { if (triple) blockState.setMetadata(mcMMO.BONUS_DROPS_METAKEY, new BonusDropMeta(2, mcMMO.p)); else @@ -42,7 +43,7 @@ public static void markDropsAsBonus(BlockState blockState, boolean triple) { * @param blockState target blockstate * @param amount amount of extra items to drop */ - public static void markDropsAsBonus(BlockState blockState, int amount) { + public static void markDropsAsBonus(@NotNull BlockState blockState, int amount) { blockState.setMetadata(mcMMO.BONUS_DROPS_METAKEY, new BonusDropMeta(amount, mcMMO.p)); } diff --git a/src/main/java/com/gmail/nossr50/util/Permissions.java b/src/main/java/com/gmail/nossr50/util/Permissions.java index c72b048b94..22f8c8a9b4 100644 --- a/src/main/java/com/gmail/nossr50/util/Permissions.java +++ b/src/main/java/com/gmail/nossr50/util/Permissions.java @@ -7,14 +7,17 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.skills.RankUtils; import org.bukkit.Material; import org.bukkit.Server; import org.bukkit.World; import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; import org.bukkit.permissions.Permissible; import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionDefault; import org.bukkit.plugin.PluginManager; +import org.jetbrains.annotations.NotNull; import java.util.Locale; @@ -234,4 +237,15 @@ private static void addDynamicPermission(String permissionName, PermissionDefaul permission.setDefault(permissionDefault); pluginManager.addPermission(permission); } + + /** + * Checks if a player can use a skill + * + * @param player target player + * @param subSkillType target subskill + * @return true if the player has permission and has the skill unlocked + */ + public static boolean canUseSubSkill(@NotNull Player player, @NotNull SubSkillType subSkillType) { + return isSubSkillEnabled(player, subSkillType) && RankUtils.hasUnlockedSubskill(player, subSkillType); + } } diff --git a/src/main/resources/advanced.yml b/src/main/resources/advanced.yml index e9979909c6..2c83539097 100644 --- a/src/main/resources/advanced.yml +++ b/src/main/resources/advanced.yml @@ -281,6 +281,11 @@ Skills: # Settings for Mining ### Mining: + Mastery: + MaxBonusLevel: + Standard: 1000 + RetroMode: 10000 + ChanceMax: 10.0 SuperBreaker: AllowTripleDrops: true DoubleDrops: diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 5a41eb4248..0b1c2517bf 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -312,6 +312,9 @@ Mining.SubSkill.SuperBreaker.Stat=Super Breaker Length Mining.SubSkill.DoubleDrops.Name=Double Drops Mining.SubSkill.DoubleDrops.Description=Double the normal loot Mining.SubSkill.DoubleDrops.Stat=Double Drop Chance +Mining.SubSkill.Mastery.Name=Mother Lode +Mining.SubSkill.Mastery.Description=Triple the normal loot +Mining.SubSkill.Mastery.Stat=Mother Lode Chance Mining.SubSkill.BlastMining.Name=Blast Mining Mining.SubSkill.BlastMining.Description=Bonuses to mining with TNT Mining.SubSkill.BlastMining.Stat=Blast Mining:&a Rank {0}/{1} &7({2}) @@ -539,8 +542,11 @@ Woodcutting.SubSkill.KnockOnWood.Stat=Knock on Wood Woodcutting.SubSkill.KnockOnWood.Loot.Normal=Standard loot from trees Woodcutting.SubSkill.KnockOnWood.Loot.Rank2=Standard loot from trees and experience orbs Woodcutting.SubSkill.HarvestLumber.Name=Harvest Lumber -Woodcutting.SubSkill.HarvestLumber.Description=Skillfully extract more Lumber +Woodcutting.SubSkill.HarvestLumber.Description=Skillfully extract up to double the Lumber Woodcutting.SubSkill.HarvestLumber.Stat=Double Drop Chance +Woodcutting.SubSkill.Mastery.Name=Clean Cuts +Woodcutting.SubSkill.Mastery.Description=Masterfully extract up to triple the Lumber +Woodcutting.SubSkill.Mastery.Stat=Triple Drop Chance Woodcutting.SubSkill.Splinter.Name=Splinter Woodcutting.SubSkill.Splinter.Description=Cut down trees more efficiently. Woodcutting.SubSkill.BarkSurgeon.Name=Bark Surgeon From 73e36b11b32f37db1532196b9ab6c46e1b401a27 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 8 Feb 2021 12:02:27 -0800 Subject: [PATCH 06/75] rename references to mining mastery -> mother lode --- .../com/gmail/nossr50/commands/skills/MiningCommand.java | 8 ++++---- .../gmail/nossr50/datatypes/skills/PrimarySkillType.java | 2 +- .../com/gmail/nossr50/datatypes/skills/SubSkillType.java | 2 +- .../com/gmail/nossr50/skills/mining/MiningManager.java | 8 ++++---- src/main/resources/advanced.yml | 2 +- src/main/resources/plugin.yml | 6 +++--- src/main/resources/skillranks.yml | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java index 1836423a21..9466141720 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java @@ -55,8 +55,8 @@ protected void dataCalculations(Player player, float skillValue) { } // Mastery TRIPLE DROPS - if (Permissions.canUseSubSkill(player, SubSkillType.MINING_MASTERY)) { - String[] masteryTripleDropStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.MINING_MASTERY); + if (Permissions.canUseSubSkill(player, SubSkillType.MINING_MOTHER_LODE)) { + String[] masteryTripleDropStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.MINING_MOTHER_LODE); masteryTripleDropChance = masteryTripleDropStrings[0]; masteryTripleDropChanceLucky = masteryTripleDropStrings[1]; } @@ -105,8 +105,8 @@ protected List statsDisplay(Player player, float skillValue, boolean has //messages.add(LocaleLoader.getString("Mining.Effect.Decrease", blastDamageDecrease)); } - if(Permissions.canUseSubSkill(player, SubSkillType.MINING_MASTERY)) { - messages.add(getStatMessage(SubSkillType.MINING_MASTERY, masteryTripleDropChance) + if(Permissions.canUseSubSkill(player, SubSkillType.MINING_MOTHER_LODE)) { + messages.add(getStatMessage(SubSkillType.MINING_MOTHER_LODE, masteryTripleDropChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", masteryTripleDropChanceLucky) : "")); } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java index 07135cc9b8..ec8ace8912 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java @@ -49,7 +49,7 @@ public enum PrimarySkillType { HERBALISM(HerbalismManager.class, Color.GREEN, SuperAbilityType.GREEN_TERRA, ToolType.HOE, ImmutableList.of(SubSkillType.HERBALISM_MASTERY, SubSkillType.HERBALISM_GREEN_TERRA, SubSkillType.HERBALISM_FARMERS_DIET, SubSkillType.HERBALISM_GREEN_THUMB, SubSkillType.HERBALISM_DOUBLE_DROPS, SubSkillType.HERBALISM_HYLIAN_LUCK, SubSkillType.HERBALISM_SHROOM_THUMB)), MINING(MiningManager.class, Color.GRAY, SuperAbilityType.SUPER_BREAKER, ToolType.PICKAXE, - ImmutableList.of(SubSkillType.MINING_MASTERY, SubSkillType.MINING_SUPER_BREAKER, SubSkillType.MINING_DEMOLITIONS_EXPERTISE, SubSkillType.MINING_BIGGER_BOMBS, SubSkillType.MINING_BLAST_MINING, SubSkillType.MINING_DOUBLE_DROPS)), + ImmutableList.of(SubSkillType.MINING_MOTHER_LODE, SubSkillType.MINING_SUPER_BREAKER, SubSkillType.MINING_DEMOLITIONS_EXPERTISE, SubSkillType.MINING_BIGGER_BOMBS, SubSkillType.MINING_BLAST_MINING, SubSkillType.MINING_DOUBLE_DROPS)), REPAIR(RepairManager.class, Color.SILVER, ImmutableList.of(SubSkillType.REPAIR_MASTERY, SubSkillType.REPAIR_ARCANE_FORGING, SubSkillType.REPAIR_REPAIR_MASTERY, SubSkillType.REPAIR_SUPER_REPAIR)), SALVAGE(SalvageManager.class, Color.ORANGE, diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java index 41b66a478c..d2d908136c 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java @@ -63,7 +63,7 @@ public enum SubSkillType { MINING_DEMOLITIONS_EXPERTISE(1), MINING_DOUBLE_DROPS(1), MINING_SUPER_BREAKER(1), - MINING_MASTERY(1), + MINING_MOTHER_LODE(1), /* Repair */ REPAIR_ARCANE_FORGING(8), diff --git a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java index d574477a72..186746fadf 100644 --- a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java +++ b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java @@ -69,8 +69,8 @@ public boolean canDoubleDrop() { return RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS) && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS); } - public boolean canMiningMastery() { - return Permissions.canUseSubSkill(getPlayer(), SubSkillType.MINING_MASTERY); + public boolean canMotherLode() { + return Permissions.canUseSubSkill(getPlayer(), SubSkillType.MINING_MOTHER_LODE); } @@ -101,7 +101,7 @@ public void miningBlockCheck(BlockState blockState) { return; //Mining mastery allows for a chance of triple drops - if(canMiningMastery()) { + if(canMotherLode()) { //Triple Drops failed so do a normal double drops check if(!processTripleDrops(blockState)) { processDoubleDrops(blockState); @@ -114,7 +114,7 @@ public void miningBlockCheck(BlockState blockState) { private boolean processTripleDrops(@NotNull BlockState blockState) { //TODO: Make this readable - if (RandomChanceUtil.checkRandomChanceExecutionSuccess(getPlayer(), SubSkillType.MINING_MASTERY, true)) { + if (RandomChanceUtil.checkRandomChanceExecutionSuccess(getPlayer(), SubSkillType.MINING_MOTHER_LODE, true)) { BlockUtils.markDropsAsBonus(blockState, 2); return true; } else { diff --git a/src/main/resources/advanced.yml b/src/main/resources/advanced.yml index 2c83539097..c07ff45c96 100644 --- a/src/main/resources/advanced.yml +++ b/src/main/resources/advanced.yml @@ -281,7 +281,7 @@ Skills: # Settings for Mining ### Mining: - Mastery: + MotherLode: MaxBonusLevel: Standard: 1000 RetroMode: 10000 diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 50be749db8..4317ac6ce1 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -482,7 +482,7 @@ permissions: mcmmo.ability.mining.blastmining.all: true mcmmo.ability.mining.doubledrops: true mcmmo.ability.mining.superbreaker: true - mcmmo.ability.mining.mastery: true + mcmmo.ability.mining.motherlode: true mcmmo.ability.mining.blastmining.*: default: false description: Allows access to all Blast Mining abilities @@ -500,8 +500,8 @@ permissions: description: Allows access to the Demolitions Expertise ability mcmmo.ability.mining.blastmining.detonate: description: Allows for remote TNT detonation - mcmmo.ability.mining.mastery: - description: Allows access to end game progression for Mining + mcmmo.ability.mining.motherlode: + description: Allows access to mother lode subskill mcmmo.ability.mining.doubledrops: description: Allows double drop chance when mining mcmmo.ability.mining.superbreaker: diff --git a/src/main/resources/skillranks.yml b/src/main/resources/skillranks.yml index d07377fa1d..df742e81a2 100644 --- a/src/main/resources/skillranks.yml +++ b/src/main/resources/skillranks.yml @@ -356,7 +356,7 @@ Salvage: Rank_7: 850 Rank_8: 1000 Mining: - Mastery: + MotherLode: Standard: Rank_1: 100 RetroMode: From 32b41b3fd3e2977e3196c642230068c6b10ea2d0 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 8 Feb 2021 12:13:53 -0800 Subject: [PATCH 07/75] Update references to mastery in en_us for Mining to Mother Lode --- Changelog.txt | 6 +++--- src/main/resources/locale/locale_en_US.properties | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 73a9721b37..7fb7515021 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -20,9 +20,9 @@ Version 2.1.175 Added 'mcmmo.ability.taming.mastery' permission node Added 'mcmmo.ability.unarmed.mastery' permission node Added 'mcmmo.ability.woodcutting.mastery' permission node - Added 'Mining.SubSkill.Mastery.Name' to locale - Added 'Mining.SubSkill.Mastery.Stat' to locale - Added 'Mining.SubSkill.Mastery.Description' to locale + Added 'Mining.SubSkill.MotherLode.Name' to locale + Added 'Mining.SubSkill.MotherLode.Stat' to locale + Added 'Mining.SubSkill.MotherLode.Description' to locale Added 'Woodcutting.SubSkill.Mastery.Name' to locale Added 'Woodcutting.SubSkill.Mastery.Stat' to locale Added 'Woodcutting.SubSkill.Mastery.Description' to locale diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 0b1c2517bf..9ec46044a3 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -312,9 +312,9 @@ Mining.SubSkill.SuperBreaker.Stat=Super Breaker Length Mining.SubSkill.DoubleDrops.Name=Double Drops Mining.SubSkill.DoubleDrops.Description=Double the normal loot Mining.SubSkill.DoubleDrops.Stat=Double Drop Chance -Mining.SubSkill.Mastery.Name=Mother Lode -Mining.SubSkill.Mastery.Description=Triple the normal loot -Mining.SubSkill.Mastery.Stat=Mother Lode Chance +Mining.SubSkill.MotherLode.Name=Mother Lode +Mining.SubSkill.MotherLode.Description=Triple the normal loot +Mining.SubSkill.MotherLode.Stat=Mother Lode Chance Mining.SubSkill.BlastMining.Name=Blast Mining Mining.SubSkill.BlastMining.Description=Bonuses to mining with TNT Mining.SubSkill.BlastMining.Stat=Blast Mining:&a Rank {0}/{1} &7({2}) From addf9b0431372aa9b061f0f1264b228d414bf269 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 8 Feb 2021 14:54:16 -0800 Subject: [PATCH 08/75] Add Clean Cuts to Woodcutting --- Changelog.txt | 16 +++++--- .../commands/skills/MiningCommand.java | 23 ++++++----- .../commands/skills/WoodcuttingCommand.java | 25 ++++++++++-- .../datatypes/skills/PrimarySkillType.java | 2 +- .../datatypes/skills/SubSkillType.java | 2 +- .../nossr50/listeners/BlockListener.java | 2 +- .../woodcutting/WoodcuttingManager.java | 40 ++++++++++++++----- .../nossr50/util/random/RandomChanceUtil.java | 12 ------ src/main/resources/advanced.yml | 9 ++++- .../resources/locale/locale_en_US.properties | 8 ++-- src/main/resources/plugin.yml | 4 +- 11 files changed, 91 insertions(+), 52 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 7fb7515021..97bff3199f 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -11,7 +11,7 @@ Version 2.1.175 Added 'mcmmo.ability.excavation.mastery' permission node Added 'mcmmo.ability.fishing.mastery' permission node Added 'mcmmo.ability.herbalism.mastery' permission node - Added 'mcmmo.ability.mining.mastery' permission node + Added 'mcmmo.ability.mining.motherlode' permission node Added 'mcmmo.ability.repair.mastery' permission node Added 'mcmmo.ability.salvage.mastery' permission node Added 'mcmmo.ability.smelting.mastery' permission node @@ -19,13 +19,13 @@ Version 2.1.175 Added 'mcmmo.ability.swords.mastery' permission node Added 'mcmmo.ability.taming.mastery' permission node Added 'mcmmo.ability.unarmed.mastery' permission node - Added 'mcmmo.ability.woodcutting.mastery' permission node + Added 'mcmmo.ability.woodcutting.cleancuts' permission node Added 'Mining.SubSkill.MotherLode.Name' to locale Added 'Mining.SubSkill.MotherLode.Stat' to locale Added 'Mining.SubSkill.MotherLode.Description' to locale - Added 'Woodcutting.SubSkill.Mastery.Name' to locale - Added 'Woodcutting.SubSkill.Mastery.Stat' to locale - Added 'Woodcutting.SubSkill.Mastery.Description' to locale + Added 'Woodcutting.SubSkill.CleanCuts.Name' to locale + Added 'Woodcutting.SubSkill.CleanCuts.Stat' to locale + Added 'Woodcutting.SubSkill.CleanCuts.Description' to locale Added 'General.PowerLevel.Skill_Mastery.Enabled' to config.yml which is used to enable or disable the mastery skills (will also disable the new power level command) @@ -39,10 +39,14 @@ Version 2.1.175 The section below assumes RetroMode, if you are using Standard mode (1-100) just divide level examples by 10. Mastery Skills - Mining (Mastery Triple Drops): With default settings, when players hit level 1,000 they will unlock this sub-skill, it will add a 1% chance to get triple drops while mining (this can be edited in advanced.yml), this skill maxes out at 10.0% chance at level 10,000. + Mining / Mother Lode: With default settings, when players hit level 1,000 they will unlock this sub-skill, it will add a 1% chance to get triple drops while mining (this can be edited in advanced.yml), this skill maxes out at 10.0% chance at level 10,000. This skill respects double drop settings from the config files. Double Drops only occur if the Triple Drops fail, these two skills do not stack. + Woodcutting / Clean Cuts: With default settings, when players hit level 1,000 they will unlock this sub-skill, it will add a 1% chance to get triple drops while woodcutting or using Tree Feller (this can be edited in advanced.yml), this skill maxes out at 10.0% chance at level 10,000. + This skill respects double drop settings from the config files. + Double Drops (Harvest Lumber) will only get checked if the Triple Drops fail for players that have Clean Cuts unlocked, these two skills do not stack. + New Power Level Command This power level command gives you a view of all your current masteries, it also provides a summary of your power level. diff --git a/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java index 9466141720..975e569f4d 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java @@ -18,8 +18,8 @@ public class MiningCommand extends SkillCommand { private String doubleDropChance; private String doubleDropChanceLucky; - private String masteryTripleDropChance; - private String masteryTripleDropChanceLucky; + private String tripleDropChance; + private String tripleDropChanceLucky; private String superBreakerLength; private String superBreakerLengthEndurance; @@ -32,6 +32,7 @@ public class MiningCommand extends SkillCommand { private boolean canSuperBreaker; private boolean canDoubleDrop; + private boolean canTripleDrop; private boolean canBlast; private boolean canBiggerBombs; private boolean canDemoExpert; @@ -55,10 +56,10 @@ protected void dataCalculations(Player player, float skillValue) { } // Mastery TRIPLE DROPS - if (Permissions.canUseSubSkill(player, SubSkillType.MINING_MOTHER_LODE)) { + if (canTripleDrop) { String[] masteryTripleDropStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.MINING_MOTHER_LODE); - masteryTripleDropChance = masteryTripleDropStrings[0]; - masteryTripleDropChanceLucky = masteryTripleDropStrings[1]; + tripleDropChance = masteryTripleDropStrings[0]; + tripleDropChanceLucky = masteryTripleDropStrings[1]; } @@ -83,6 +84,7 @@ protected void permissionsCheck(Player player) { canBlast = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_BLAST_MINING) && Permissions.remoteDetonation(player); canDemoExpert = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_DEMOLITIONS_EXPERTISE) && Permissions.demolitionsExpertise(player); canDoubleDrop = Permissions.canUseSubSkill(player, SubSkillType.MINING_DOUBLE_DROPS); + canTripleDrop = Permissions.canUseSubSkill(player, SubSkillType.MINING_MOTHER_LODE); canSuperBreaker = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_SUPER_BREAKER) && Permissions.superBreaker(player); } @@ -105,17 +107,18 @@ protected List statsDisplay(Player player, float skillValue, boolean has //messages.add(LocaleLoader.getString("Mining.Effect.Decrease", blastDamageDecrease)); } - if(Permissions.canUseSubSkill(player, SubSkillType.MINING_MOTHER_LODE)) { - messages.add(getStatMessage(SubSkillType.MINING_MOTHER_LODE, masteryTripleDropChance) - + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", masteryTripleDropChanceLucky) : "")); - } - if (canDoubleDrop) { messages.add(getStatMessage(SubSkillType.MINING_DOUBLE_DROPS, doubleDropChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", doubleDropChanceLucky) : "")); //messages.add(LocaleLoader.getString("Mining.Effect.DropChance", doubleDropChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", doubleDropChanceLucky) : "")); } + if(canTripleDrop) { + messages.add(getStatMessage(SubSkillType.MINING_MOTHER_LODE, tripleDropChance) + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", tripleDropChanceLucky) : "")); + } + + if (canSuperBreaker) { messages.add(getStatMessage(SubSkillType.MINING_SUPER_BREAKER, superBreakerLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", superBreakerLengthEndurance) : "")); diff --git a/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java index 75c3e74e25..a6f763f131 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java @@ -17,15 +17,18 @@ public class WoodcuttingCommand extends SkillCommand { private String treeFellerLength; private String treeFellerLengthEndurance; private String doubleDropChance; + private String tripleDropChance; private String doubleDropChanceLucky; + private String tripleDropChanceLucky; private boolean canTreeFell; private boolean canLeafBlow; private boolean canDoubleDrop; + private boolean canTripleDrop; private boolean canKnockOnWood; - private boolean canSplinter; - private boolean canBarkSurgeon; - private boolean canNaturesBounty; +// private boolean canSplinter; +// private boolean canBarkSurgeon; +// private boolean canNaturesBounty; public WoodcuttingCommand() { super(PrimarySkillType.WOODCUTTING); @@ -37,6 +40,13 @@ protected void dataCalculations(Player player, float skillValue) { if (canDoubleDrop) { setDoubleDropClassicChanceStrings(player); } + + //Clean Cuts + if(canTripleDrop) { + String[] tripleDropStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.WOODCUTTING_CLEAN_CUTS); + tripleDropChance = tripleDropStrings[0]; + tripleDropChanceLucky = tripleDropStrings[1]; + } // TREE FELLER if (canTreeFell) { @@ -55,7 +65,8 @@ private void setDoubleDropClassicChanceStrings(Player player) { @Override protected void permissionsCheck(Player player) { canTreeFell = RankUtils.hasUnlockedSubskill(player, SubSkillType.WOODCUTTING_TREE_FELLER) && Permissions.treeFeller(player); - canDoubleDrop = Permissions.canUseSubSkill(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) && !skill.getDoubleDropsDisabled() && RankUtils.getRank(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) >= 1; + canDoubleDrop = Permissions.canUseSubSkill(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) && !skill.getDoubleDropsDisabled(); + canTripleDrop = Permissions.canUseSubSkill(player, SubSkillType.WOODCUTTING_CLEAN_CUTS) && !skill.getDoubleDropsDisabled(); canLeafBlow = Permissions.canUseSubSkill(player, SubSkillType.WOODCUTTING_LEAF_BLOWER); canKnockOnWood = canTreeFell && Permissions.canUseSubSkill(player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD); /*canSplinter = canUseSubskill(player, SubSkillType.WOODCUTTING_SPLINTER); @@ -72,6 +83,12 @@ protected List statsDisplay(Player player, float skillValue, boolean has + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", doubleDropChanceLucky) : "")); } + if(canTripleDrop) { + messages.add(getStatMessage(SubSkillType.WOODCUTTING_CLEAN_CUTS, tripleDropChance) + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", tripleDropChanceLucky) : "")); + } + + if (canKnockOnWood) { String lootNote; diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java index ec8ace8912..8a7df7ac07 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java @@ -63,7 +63,7 @@ public enum PrimarySkillType { UNARMED(UnarmedManager.class, Color.BLACK, SuperAbilityType.BERSERK, ToolType.FISTS, ImmutableList.of(SubSkillType.UNARMED_MASTERY, SubSkillType.UNARMED_BERSERK, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK, SubSkillType.UNARMED_BLOCK_CRACKER, SubSkillType.UNARMED_ARROW_DEFLECT, SubSkillType.UNARMED_DISARM, SubSkillType.UNARMED_STEEL_ARM_STYLE, SubSkillType.UNARMED_IRON_GRIP)), WOODCUTTING(WoodcuttingManager.class, Color.OLIVE, SuperAbilityType.TREE_FELLER, ToolType.AXE, - ImmutableList.of(SubSkillType.WOODCUTTING_MASTERY, SubSkillType.WOODCUTTING_LEAF_BLOWER, SubSkillType.WOODCUTTING_TREE_FELLER, SubSkillType.WOODCUTTING_HARVEST_LUMBER, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)); + ImmutableList.of(SubSkillType.WOODCUTTING_CLEAN_CUTS, SubSkillType.WOODCUTTING_LEAF_BLOWER, SubSkillType.WOODCUTTING_TREE_FELLER, SubSkillType.WOODCUTTING_HARVEST_LUMBER, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)); private final Class managerClass; private final Color skillColor; diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java index d2d908136c..db0ec48e20 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java @@ -119,7 +119,7 @@ public enum SubSkillType { /* WOODCUTTING_NATURES_BOUNTY(3), WOODCUTTING_SPLINTER(3),*/ WOODCUTTING_TREE_FELLER(1), - WOODCUTTING_MASTERY(1); + WOODCUTTING_CLEAN_CUTS(1); private final int numRanks; //TODO: SuperAbilityType should also contain flags for active by default? Not sure if it should work that way. diff --git a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java index a6d8e7900a..70b4fc6496 100644 --- a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java @@ -358,7 +358,7 @@ else if (BlockUtils.hasWoodcuttingXP(blockState) && ItemUtils.isAxe(heldItem) && woodcuttingManager.processWoodcuttingBlockXP(blockState); //Check for bonus drops - woodcuttingManager.processHarvestLumber(blockState); + woodcuttingManager.processBonusDropCheck(blockState); } } diff --git a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java index a2bb237907..4aa7cb4783 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java @@ -36,6 +36,7 @@ import java.util.List; import java.util.Set; +//TODO: Seems to not be using the item drop event for bonus drops, may want to change that.. or may not be able to be changed? public class WoodcuttingManager extends SkillManager { private boolean treeFellerReachedThreshold = false; private static int treeFellerThreshold; //TODO: Shared setting, will be removed in 2.2 @@ -68,21 +69,40 @@ public boolean canUseTreeFeller(ItemStack heldItem) { && ItemUtils.isAxe(heldItem); } - private boolean checkHarvestLumberActivation(@NotNull Material material) { - return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER) - && RankUtils.hasReachedRank(1, getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER) - && RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.WOODCUTTING_HARVEST_LUMBER, getPlayer()) - && Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, material); + private boolean checkHarvestLumberActivation() { + return RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.WOODCUTTING_HARVEST_LUMBER, getPlayer()); + } + + private boolean checkCleanCutsActivation() { + return RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.WOODCUTTING_CLEAN_CUTS, getPlayer()); } /** - * Begins Woodcutting + * Processes bonus drops for a block * * @param blockState Block being broken */ - public void processHarvestLumber(@NotNull BlockState blockState) { - if (checkHarvestLumberActivation(blockState.getType())) { - spawnHarvestLumberBonusDrops(blockState); + public void processBonusDropCheck(@NotNull BlockState blockState) { + //TODO: Why isn't this using the item drop event? Potentially because of Tree Feller? This should be adjusted either way. + if(Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, blockState.getType())) { + //Mastery enabled for player + if(Permissions.canUseSubSkill(getPlayer(), SubSkillType.WOODCUTTING_CLEAN_CUTS)) { + if(checkCleanCutsActivation()) { + //Triple drops + spawnHarvestLumberBonusDrops(blockState); + spawnHarvestLumberBonusDrops(blockState); + } else { + //Harvest Lumber Check + if(checkHarvestLumberActivation()) { + spawnHarvestLumberBonusDrops(blockState); + } + } + //No Mastery (no Clean Cuts) + } else if (Permissions.canUseSubSkill(getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER)) { + if(checkHarvestLumberActivation()) { + spawnHarvestLumberBonusDrops(blockState); + } + } } } @@ -299,7 +319,7 @@ private void dropTreeFellerLootFromBlocks(@NotNull Set treeFellerBlo Misc.spawnItemsFromCollection(Misc.getBlockCenter(blockState), block.getDrops(), ItemSpawnReason.TREE_FELLER_DISPLACED_BLOCK); //Bonus Drops / Harvest lumber checks - processHarvestLumber(blockState); + processBonusDropCheck(blockState); } else if (BlockUtils.isNonWoodPartOfTree(blockState)) { //Drop displaced non-woodcutting XP blocks diff --git a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java index a59cd28613..200893fa7f 100644 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java +++ b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java @@ -112,13 +112,6 @@ public static boolean checkRandomChanceExecutionSuccess(@NotNull RandomChanceSki return rollDice(chanceOfSuccess, 100); } - - /*public static double getRandomChanceExecutionChance(RandomChanceSkill randomChance) - { - double chanceOfSuccess = calculateChanceOfSuccess(randomChance); - return chanceOfSuccess; - }*/ - /** * Gets the Static Chance for something to activate * @@ -141,11 +134,6 @@ public static double getRandomChanceExecutionChance(@NotNull RandomChanceStatic return chanceOfSuccess; } - /*private static double calculateChanceOfSuccess(RandomChanceStatic randomChance) { - double chanceOfSuccess = getChanceOfSuccess(randomChance.getXPos(), randomChance.getProbabilityCap()); - return chanceOfSuccess; - }*/ - public static double calculateChanceOfSuccess(@NotNull RandomChanceSkill randomChance) { double skillLevel = randomChance.getSkillLevel(); double maximumProbability = randomChance.getProbabilityCap(); diff --git a/src/main/resources/advanced.yml b/src/main/resources/advanced.yml index c07ff45c96..99e46767fa 100644 --- a/src/main/resources/advanced.yml +++ b/src/main/resources/advanced.yml @@ -590,9 +590,16 @@ Skills: Knock_On_Wood: Add_XP_Orbs_To_Drops: true + # Triple Drops + CleanCuts: + # ChanceMax: Maximum chance of receiving double drops (100 = 100%) + # MaxBonusLevel: Level when the maximum chance of receiving double drops is reached + ChanceMax: 10.0 + MaxBonusLevel: + Standard: 1000 + RetroMode: 10000 # Double Drops HarvestLumber: - # ChanceMax & MaxBonusLevel are only used for Classic, I'll make that more clear in the future. # ChanceMax: Maximum chance of receiving double drops (100 = 100%) # MaxBonusLevel: Level when the maximum chance of receiving double drops is reached ChanceMax: 100.0 diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 9ec46044a3..3e096690b3 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -314,7 +314,7 @@ Mining.SubSkill.DoubleDrops.Description=Double the normal loot Mining.SubSkill.DoubleDrops.Stat=Double Drop Chance Mining.SubSkill.MotherLode.Name=Mother Lode Mining.SubSkill.MotherLode.Description=Triple the normal loot -Mining.SubSkill.MotherLode.Stat=Mother Lode Chance +Mining.SubSkill.MotherLode.Stat=Triple Drop Chance Mining.SubSkill.BlastMining.Name=Blast Mining Mining.SubSkill.BlastMining.Description=Bonuses to mining with TNT Mining.SubSkill.BlastMining.Stat=Blast Mining:&a Rank {0}/{1} &7({2}) @@ -544,9 +544,9 @@ Woodcutting.SubSkill.KnockOnWood.Loot.Rank2=Standard loot from trees and experie Woodcutting.SubSkill.HarvestLumber.Name=Harvest Lumber Woodcutting.SubSkill.HarvestLumber.Description=Skillfully extract up to double the Lumber Woodcutting.SubSkill.HarvestLumber.Stat=Double Drop Chance -Woodcutting.SubSkill.Mastery.Name=Clean Cuts -Woodcutting.SubSkill.Mastery.Description=Masterfully extract up to triple the Lumber -Woodcutting.SubSkill.Mastery.Stat=Triple Drop Chance +Woodcutting.SubSkill.CleanCuts.Name=Clean Cuts +Woodcutting.SubSkill.CleanCuts.Description=Masterfully extract up to triple the Lumber +Woodcutting.SubSkill.CleanCuts.Stat=Triple Drop Chance Woodcutting.SubSkill.Splinter.Name=Splinter Woodcutting.SubSkill.Splinter.Description=Cut down trees more efficiently. Woodcutting.SubSkill.BarkSurgeon.Name=Bark Surgeon diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 4317ac6ce1..a4b4470737 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -768,8 +768,8 @@ permissions: mcmmo.ability.woodcutting.knockonwood: true mcmmo.ability.woodcutting.leafblower: true mcmmo.ability.woodcutting.treefeller: true - mcmmo.ability.woodcutting.mastery: true - mcmmo.ability.woodcutting.mastery: + mcmmo.ability.woodcutting.cleancuts: true + mcmmo.ability.woodcutting.cleancuts: description: Allows access to end game progression for Woodcutting mcmmo.ability.woodcutting.knockonwood: description: Allows access to Knock on Wood subskill From 1bde79cd6f0f3a21ac08ad2316be37a8e23143b3 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 10 Feb 2021 10:05:42 -0800 Subject: [PATCH 09/75] add toggle for sending chat messages to console Fixes #4415 --- Changelog.txt | 1 + .../java/com/gmail/nossr50/chat/mailer/AdminChatMailer.java | 3 ++- .../com/gmail/nossr50/chat/message/PartyChatMessage.java | 4 +++- src/main/java/com/gmail/nossr50/config/ChatConfig.java | 6 ++++++ src/main/resources/chat.yml | 2 ++ 5 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 97bff3199f..23ac1bb42e 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,4 +1,5 @@ Version 2.1.175 + Added a setting to chat.yml to toggle sending party or admin chat messages to console Added a set of "mastery" subskills meant for end game progression Added the mastery subskill 'Mother Lode' to Mining Added the mastery subskill 'Clean Cuts' to Woodcutting diff --git a/src/main/java/com/gmail/nossr50/chat/mailer/AdminChatMailer.java b/src/main/java/com/gmail/nossr50/chat/mailer/AdminChatMailer.java index de922e56af..8498e518f3 100644 --- a/src/main/java/com/gmail/nossr50/chat/mailer/AdminChatMailer.java +++ b/src/main/java/com/gmail/nossr50/chat/mailer/AdminChatMailer.java @@ -3,6 +3,7 @@ import com.gmail.nossr50.chat.author.Author; import com.gmail.nossr50.chat.message.AdminChatMessage; import com.gmail.nossr50.chat.message.ChatMessage; +import com.gmail.nossr50.config.ChatConfig; import com.gmail.nossr50.datatypes.chat.ChatChannel; import com.gmail.nossr50.events.chat.McMMOAdminChatEvent; import com.gmail.nossr50.events.chat.McMMOChatEvent; @@ -44,7 +45,7 @@ public AdminChatMailer(Plugin pluginRef) { public @NotNull Predicate predicate() { return (commandSender) -> commandSender.isOp() || commandSender.hasPermission(MCMMO_CHAT_ADMINCHAT_PERMISSION) - || commandSender instanceof ConsoleCommandSender; + || (ChatConfig.getInstance().isConsoleIncludedInAudience(ChatChannel.ADMIN) && commandSender instanceof ConsoleCommandSender); } /** diff --git a/src/main/java/com/gmail/nossr50/chat/message/PartyChatMessage.java b/src/main/java/com/gmail/nossr50/chat/message/PartyChatMessage.java index 4c143ec697..756c3d4570 100644 --- a/src/main/java/com/gmail/nossr50/chat/message/PartyChatMessage.java +++ b/src/main/java/com/gmail/nossr50/chat/message/PartyChatMessage.java @@ -1,6 +1,7 @@ package com.gmail.nossr50.chat.message; import com.gmail.nossr50.chat.author.Author; +import com.gmail.nossr50.config.ChatConfig; import com.gmail.nossr50.datatypes.chat.ChatChannel; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.player.McMMOPlayer; @@ -51,7 +52,8 @@ public void sendMessage() { messagePartyChatSpies(spyMessage); //Console message - mcMMO.p.getChatManager().sendConsoleMessage(author, spyMessage); + if(ChatConfig.getInstance().isConsoleIncludedInAudience(ChatChannel.PARTY)) + mcMMO.p.getChatManager().sendConsoleMessage(author, spyMessage); } /** diff --git a/src/main/java/com/gmail/nossr50/config/ChatConfig.java b/src/main/java/com/gmail/nossr50/config/ChatConfig.java index 1440194fcf..884ca47213 100644 --- a/src/main/java/com/gmail/nossr50/config/ChatConfig.java +++ b/src/main/java/com/gmail/nossr50/config/ChatConfig.java @@ -49,6 +49,12 @@ public boolean useDisplayNames(@NotNull ChatChannel chatChannel) { return config.getBoolean(key, true); } + public boolean isConsoleIncludedInAudience(@NotNull ChatChannel chatChannel) { + String key = "Chat.Channels." + StringUtils.getCapitalized(chatChannel.toString()) + ".Send_To_Console"; + return config.getBoolean(key, true); + } + + public boolean isSpyingAutomatic() { return config.getBoolean("Chat.Channels.Party.Spies.Automatically_Enable_Spying", false); } diff --git a/src/main/resources/chat.yml b/src/main/resources/chat.yml index 6fa5ecf88b..ab93387b79 100644 --- a/src/main/resources/chat.yml +++ b/src/main/resources/chat.yml @@ -8,10 +8,12 @@ Chat: Enable: true # Whether or not to use the current display name of a player Use_Display_Names: true + Send_To_Console: true Spies: # Whether or not players with the chat spy permission join the server with chat spying toggled on Automatically_Enable_Spying: false Admin: + Send_To_Console: true # Enable or disable admin chat Enable: true # Whether or not to use the current display name of a player From f7640938df8c0f8e9706c6fc366a606424fc53e6 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 17 Feb 2021 15:28:27 -0800 Subject: [PATCH 10/75] RandomChanceUtil refactor part 1 --- Changelog.txt | 1 + .../exceptions/ValueOutOfBoundsException.java | 9 + .../commands/skills/AcrobaticsCommand.java | 12 +- .../commands/skills/ArcheryCommand.java | 5 +- .../nossr50/commands/skills/AxesCommand.java | 3 +- .../commands/skills/HerbalismCommand.java | 9 +- .../commands/skills/MiningCommand.java | 14 +- .../commands/skills/RepairCommand.java | 3 +- .../nossr50/commands/skills/SkillCommand.java | 2 +- .../commands/skills/SmeltingCommand.java | 5 +- .../commands/skills/SwordsCommand.java | 5 +- .../commands/skills/TamingCommand.java | 3 +- .../commands/skills/UnarmedCommand.java | 7 +- .../commands/skills/WoodcuttingCommand.java | 5 +- .../skills/subskills/acrobatics/Roll.java | 33 +- .../nossr50/datatypes/treasure/Treasure.java | 44 ++- .../nossr50/listeners/EntityListener.java | 5 +- .../skills/acrobatics/AcrobaticsManager.java | 4 +- .../skills/archery/ArcheryManager.java | 6 +- .../nossr50/skills/axes/AxesManager.java | 10 +- .../skills/excavation/ExcavationManager.java | 2 +- .../skills/fishing/FishingManager.java | 13 +- .../skills/herbalism/HerbalismManager.java | 10 +- .../nossr50/skills/repair/RepairManager.java | 8 +- .../skills/salvage/SalvageManager.java | 7 +- .../skills/smelting/SmeltingManager.java | 5 +- .../nossr50/skills/swords/SwordsManager.java | 7 +- .../nossr50/skills/taming/TamingManager.java | 9 +- .../skills/unarmed/UnarmedManager.java | 12 +- .../woodcutting/WoodcuttingManager.java | 7 +- .../com/gmail/nossr50/util/BlockUtils.java | 3 +- .../java/com/gmail/nossr50/util/Misc.java | 22 ++ .../nossr50/util/random/Probability.java | 14 + .../util/random/ProbabilityFactory.java | 77 +++++ .../nossr50/util/random/ProbabilityImpl.java | 63 ++++ .../util/random/RandomChanceExecution.java | 18 - .../util/random/RandomChanceSkill.java | 176 ---------- .../util/random/RandomChanceSkillStatic.java | 61 ---- .../util/random/RandomChanceStatic.java | 38 --- .../nossr50/util/random/RandomChanceUtil.java | 321 ++---------------- .../util/random/SkillProbabilityType.java | 6 + .../gmail/nossr50/util/skills/SkillUtils.java | 90 +++++ .../nossr50/util/random/RandomChanceTest.java | 44 +-- 43 files changed, 475 insertions(+), 723 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/api/exceptions/ValueOutOfBoundsException.java create mode 100644 src/main/java/com/gmail/nossr50/util/random/Probability.java create mode 100644 src/main/java/com/gmail/nossr50/util/random/ProbabilityFactory.java create mode 100644 src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java delete mode 100644 src/main/java/com/gmail/nossr50/util/random/RandomChanceExecution.java delete mode 100644 src/main/java/com/gmail/nossr50/util/random/RandomChanceSkill.java delete mode 100644 src/main/java/com/gmail/nossr50/util/random/RandomChanceSkillStatic.java delete mode 100644 src/main/java/com/gmail/nossr50/util/random/RandomChanceStatic.java create mode 100644 src/main/java/com/gmail/nossr50/util/random/SkillProbabilityType.java diff --git a/Changelog.txt b/Changelog.txt index 23ac1bb42e..96529da12b 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -27,6 +27,7 @@ Version 2.1.175 Added 'Woodcutting.SubSkill.CleanCuts.Name' to locale Added 'Woodcutting.SubSkill.CleanCuts.Stat' to locale Added 'Woodcutting.SubSkill.CleanCuts.Description' to locale + (Codebase) Major refactoring for how random chance was handled in the code Added 'General.PowerLevel.Skill_Mastery.Enabled' to config.yml which is used to enable or disable the mastery skills (will also disable the new power level command) diff --git a/src/main/java/com/gmail/nossr50/api/exceptions/ValueOutOfBoundsException.java b/src/main/java/com/gmail/nossr50/api/exceptions/ValueOutOfBoundsException.java new file mode 100644 index 0000000000..4fc4a7a6f5 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/api/exceptions/ValueOutOfBoundsException.java @@ -0,0 +1,9 @@ +package com.gmail.nossr50.api.exceptions; + +import org.jetbrains.annotations.NotNull; + +public class ValueOutOfBoundsException extends RuntimeException { + public ValueOutOfBoundsException(@NotNull String message) { + super(message); + } +} diff --git a/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java index 46ba32b288..bcb5368b5b 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java @@ -6,9 +6,7 @@ import com.gmail.nossr50.listeners.InteractionManager; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.util.Permissions; -import com.gmail.nossr50.util.random.RandomChanceSkill; import com.gmail.nossr50.util.random.RandomChanceUtil; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -31,7 +29,7 @@ public AcrobaticsCommand() { protected void dataCalculations(Player player, float skillValue) { // ACROBATICS_DODGE if (canDodge) { - String[] dodgeStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.ACROBATICS_DODGE); + String[] dodgeStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.ACROBATICS_DODGE); dodgeChance = dodgeStrings[0]; dodgeChanceLucky = dodgeStrings[1]; } @@ -61,18 +59,18 @@ protected List statsDisplay(Player player, float skillValue, boolean has double rollChance, graceChance; //Chance to roll at half - RandomChanceSkill roll_rcs = new RandomChanceSkill(player, SubSkillType.ACROBATICS_ROLL); + SkillProbabilityWrapper roll_rcs = new SkillProbabilityWrapper(player, SubSkillType.ACROBATICS_ROLL); //Chance to graceful roll - RandomChanceSkill grace_rcs = new RandomChanceSkill(player, SubSkillType.ACROBATICS_ROLL); - grace_rcs.setSkillLevel(grace_rcs.getSkillLevel() * 2); //Double Odds + SkillProbabilityWrapper grace_rcs = new SkillProbabilityWrapper(player, SubSkillType.ACROBATICS_ROLL); + grace_rcs.setxPos(grace_rcs.getxPos() * 2); //Double Odds //Chance Stat Calculations rollChance = RandomChanceUtil.getRandomChanceExecutionChance(roll_rcs); graceChance = RandomChanceUtil.getRandomChanceExecutionChance(grace_rcs); //damageThreshold = AdvancedConfig.getInstance().getRollDamageThreshold(); - String[] rollStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.ACROBATICS_ROLL); + String[] rollStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.ACROBATICS_ROLL); //Format double rollChanceLucky = rollChance * 1.333D; diff --git a/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java index ec5c630085..31500493c0 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java @@ -6,7 +6,6 @@ import com.gmail.nossr50.skills.archery.Archery; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.skills.CombatUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -33,14 +32,14 @@ public ArcheryCommand() { protected void dataCalculations(Player player, float skillValue) { // ARCHERY_ARROW_RETRIEVAL if (canRetrieve) { - String[] retrieveStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.ARCHERY_ARROW_RETRIEVAL); + String[] retrieveStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.ARCHERY_ARROW_RETRIEVAL); retrieveChance = retrieveStrings[0]; retrieveChanceLucky = retrieveStrings[1]; } // ARCHERY_DAZE if (canDaze) { - String[] dazeStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.ARCHERY_DAZE); + String[] dazeStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.ARCHERY_DAZE); dazeChance = dazeStrings[0]; dazeChanceLucky = dazeStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java index 2e61db48e0..1a0e74e18c 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java @@ -8,7 +8,6 @@ import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -48,7 +47,7 @@ protected void dataCalculations(Player player, float skillValue) { // CRITICAL HIT if (canCritical) { - String[] criticalHitStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.AXES_CRITICAL_STRIKES); + String[] criticalHitStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.AXES_CRITICAL_STRIKES); critChance = criticalHitStrings[0]; critChanceLucky = criticalHitStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java index ecba231d1d..8d8d13b6f7 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java @@ -5,7 +5,6 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.Material; @@ -45,7 +44,7 @@ protected void dataCalculations(Player player, float skillValue) { // DOUBLE DROPS if (canDoubleDrop) { - String[] doubleDropStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.HERBALISM_DOUBLE_DROPS); + String[] doubleDropStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.HERBALISM_DOUBLE_DROPS); doubleDropChance = doubleDropStrings[0]; doubleDropChanceLucky = doubleDropStrings[1]; } @@ -66,21 +65,21 @@ protected void dataCalculations(Player player, float skillValue) { if (canGreenThumbBlocks || canGreenThumbPlants) { greenThumbStage = RankUtils.getRank(player, SubSkillType.HERBALISM_GREEN_THUMB); - String[] greenThumbStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.HERBALISM_GREEN_THUMB); + String[] greenThumbStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.HERBALISM_GREEN_THUMB); greenThumbChance = greenThumbStrings[0]; greenThumbChanceLucky = greenThumbStrings[1]; } // HYLIAN LUCK if (hasHylianLuck) { - String[] hylianLuckStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.HERBALISM_HYLIAN_LUCK); + String[] hylianLuckStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.HERBALISM_HYLIAN_LUCK); hylianLuckChance = hylianLuckStrings[0]; hylianLuckChanceLucky = hylianLuckStrings[1]; } // SHROOM THUMB if (canShroomThumb) { - String[] shroomThumbStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.HERBALISM_SHROOM_THUMB); + String[] shroomThumbStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.HERBALISM_SHROOM_THUMB); shroomThumbChance = shroomThumbStrings[0]; shroomThumbChanceLucky = shroomThumbStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java index 975e569f4d..b94ad33fd4 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java @@ -7,7 +7,6 @@ import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -32,7 +31,7 @@ public class MiningCommand extends SkillCommand { private boolean canSuperBreaker; private boolean canDoubleDrop; - private boolean canTripleDrop; + private boolean canMotherLode; private boolean canBlast; private boolean canBiggerBombs; private boolean canDemoExpert; @@ -56,16 +55,15 @@ protected void dataCalculations(Player player, float skillValue) { } // Mastery TRIPLE DROPS - if (canTripleDrop) { - String[] masteryTripleDropStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.MINING_MOTHER_LODE); + if (canMotherLode) { + String[] masteryTripleDropStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.MINING_MOTHER_LODE); tripleDropChance = masteryTripleDropStrings[0]; tripleDropChanceLucky = masteryTripleDropStrings[1]; } - // DOUBLE DROPS if (canDoubleDrop) { - String[] doubleDropStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.MINING_DOUBLE_DROPS); + String[] doubleDropStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.MINING_DOUBLE_DROPS); doubleDropChance = doubleDropStrings[0]; doubleDropChanceLucky = doubleDropStrings[1]; } @@ -84,7 +82,7 @@ protected void permissionsCheck(Player player) { canBlast = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_BLAST_MINING) && Permissions.remoteDetonation(player); canDemoExpert = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_DEMOLITIONS_EXPERTISE) && Permissions.demolitionsExpertise(player); canDoubleDrop = Permissions.canUseSubSkill(player, SubSkillType.MINING_DOUBLE_DROPS); - canTripleDrop = Permissions.canUseSubSkill(player, SubSkillType.MINING_MOTHER_LODE); + canMotherLode = Permissions.canUseSubSkill(player, SubSkillType.MINING_MOTHER_LODE); canSuperBreaker = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_SUPER_BREAKER) && Permissions.superBreaker(player); } @@ -113,7 +111,7 @@ protected List statsDisplay(Player player, float skillValue, boolean has //messages.add(LocaleLoader.getString("Mining.Effect.DropChance", doubleDropChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", doubleDropChanceLucky) : "")); } - if(canTripleDrop) { + if(canMotherLode) { messages.add(getStatMessage(SubSkillType.MINING_MOTHER_LODE, tripleDropChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", tripleDropChanceLucky) : "")); } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java index 8cb9b52fec..c6687a5c4d 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java @@ -12,7 +12,6 @@ import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.Material; @@ -68,7 +67,7 @@ protected void dataCalculations(Player player, float skillValue) { // SUPER REPAIR if (canSuperRepair) { - String[] superRepairStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.REPAIR_SUPER_REPAIR); + String[] superRepairStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.REPAIR_SUPER_REPAIR); superRepairChance = superRepairStrings[0]; superRepairChanceLucky = superRepairStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java index ee1ecb2027..48e4faf376 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java @@ -219,7 +219,7 @@ protected int calculateRank(float skillValue, int maxLevel, int rankChangeLevel) return Math.min((int) skillValue, maxLevel) / rankChangeLevel; } - protected String[] getAbilityDisplayValues(SkillActivationType skillActivationType, Player player, SubSkillType subSkill) { + protected static String[] getAbilityDisplayValues(SkillActivationType skillActivationType, Player player, SubSkillType subSkill) { return RandomChanceUtil.calculateAbilityDisplayValues(skillActivationType, player, subSkill); } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java index 7b039ea7ed..3c251b1296 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java @@ -6,7 +6,6 @@ import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -39,14 +38,14 @@ protected void dataCalculations(Player player, float skillValue) { // FLUX MINING /*if (canFluxMine) { - String[] fluxMiningStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.SMELTING_FLUX_MINING); + String[] fluxMiningStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.SMELTING_FLUX_MINING); str_fluxMiningChance = fluxMiningStrings[0]; str_fluxMiningChanceLucky = fluxMiningStrings[1]; }*/ // SECOND SMELT if (canSecondSmelt) { - String[] secondSmeltStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.SMELTING_SECOND_SMELT); + String[] secondSmeltStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.SMELTING_SECOND_SMELT); str_secondSmeltChance = secondSmeltStrings[0]; str_secondSmeltChanceLucky = secondSmeltStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java index 7655ce680a..967cd1a22e 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java @@ -8,7 +8,6 @@ import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -37,7 +36,7 @@ public SwordsCommand() { protected void dataCalculations(Player player, float skillValue) { // SWORDS_COUNTER_ATTACK if (canCounter) { - String[] counterStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.SWORDS_COUNTER_ATTACK); + String[] counterStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.SWORDS_COUNTER_ATTACK); counterChance = counterStrings[0]; counterChanceLucky = counterStrings[1]; } @@ -46,7 +45,7 @@ protected void dataCalculations(Player player, float skillValue) { if (canBleed) { bleedLength = UserManager.getPlayer(player).getSwordsManager().getRuptureBleedTicks(); - String[] bleedStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.SWORDS_RUPTURE); + String[] bleedStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.SWORDS_RUPTURE); bleedChance = bleedStrings[0]; bleedChanceLucky = bleedStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java index e007799dbc..639de87c14 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java @@ -5,7 +5,6 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.skills.taming.Taming; import com.gmail.nossr50.util.Permissions; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.EntityType; @@ -35,7 +34,7 @@ public TamingCommand() { @Override protected void dataCalculations(Player player, float skillValue) { if (canGore) { - String[] goreStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.TAMING_GORE); + String[] goreStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.TAMING_GORE); goreChance = goreStrings[0]; goreChanceLucky = goreStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java index ee52401e6e..f93e948cb6 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java @@ -7,7 +7,6 @@ import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -40,7 +39,7 @@ public UnarmedCommand() { protected void dataCalculations(Player player, float skillValue) { // UNARMED_ARROW_DEFLECT if (canDeflect) { - String[] deflectStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.UNARMED_ARROW_DEFLECT); + String[] deflectStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.UNARMED_ARROW_DEFLECT); deflectChance = deflectStrings[0]; deflectChanceLucky = deflectStrings[1]; } @@ -54,7 +53,7 @@ protected void dataCalculations(Player player, float skillValue) { // UNARMED_DISARM if (canDisarm) { - String[] disarmStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.UNARMED_DISARM); + String[] disarmStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.UNARMED_DISARM); disarmChance = disarmStrings[0]; disarmChanceLucky = disarmStrings[1]; } @@ -66,7 +65,7 @@ protected void dataCalculations(Player player, float skillValue) { // IRON GRIP if (canIronGrip) { - String[] ironGripStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.UNARMED_IRON_GRIP); + String[] ironGripStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.UNARMED_IRON_GRIP); ironGripChance = ironGripStrings[0]; ironGripChanceLucky = ironGripStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java index a6f763f131..4b282629cf 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java @@ -5,7 +5,6 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -43,7 +42,7 @@ protected void dataCalculations(Player player, float skillValue) { //Clean Cuts if(canTripleDrop) { - String[] tripleDropStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.WOODCUTTING_CLEAN_CUTS); + String[] tripleDropStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.WOODCUTTING_CLEAN_CUTS); tripleDropChance = tripleDropStrings[0]; tripleDropChanceLucky = tripleDropStrings[1]; } @@ -57,7 +56,7 @@ protected void dataCalculations(Player player, float skillValue) { } private void setDoubleDropClassicChanceStrings(Player player) { - String[] doubleDropStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.WOODCUTTING_HARVEST_LUMBER); + String[] doubleDropStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.WOODCUTTING_HARVEST_LUMBER); doubleDropChance = doubleDropStrings[0]; doubleDropChanceLucky = doubleDropStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java index 4ea8ad1562..4e9fc852a7 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java @@ -14,11 +14,10 @@ import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; -import com.gmail.nossr50.util.random.RandomChanceSkill; import com.gmail.nossr50.util.random.RandomChanceUtil; +import com.gmail.nossr50.util.random.SkillProbabilityType; import com.gmail.nossr50.util.skills.PerksUtils; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; @@ -125,14 +124,14 @@ public void addStats(TextComponent.Builder componentBuilder, Player player) { float skillValue = playerProfile.getSkillLevel(getPrimarySkill()); boolean isLucky = Permissions.lucky(player, getPrimarySkill()); - String[] rollStrings = RandomChanceUtil.calculateAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.ACROBATICS_ROLL); + String[] rollStrings = RandomChanceUtil.calculateAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.ACROBATICS_ROLL); rollChance = rollStrings[0]; rollChanceLucky = rollStrings[1]; /* * Graceful is double the odds of a normal roll */ - String[] gracefulRollStrings = RandomChanceUtil.calculateAbilityDisplayValuesCustom(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.ACROBATICS_ROLL, 2.0D); + String[] gracefulRollStrings = RandomChanceUtil.calculateAbilityDisplayValuesCustom(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.ACROBATICS_ROLL, 2.0D); gracefulRollChance = gracefulRollStrings[0]; gracefulRollChanceLucky = gracefulRollStrings[1]; @@ -199,7 +198,7 @@ private double rollCheck(Player player, McMMOPlayer mcMMOPlayer, double damage) double modifiedDamage = calculateModifiedRollDamage(damage, AdvancedConfig.getInstance().getRollDamageThreshold()); if (!isFatal(player, modifiedDamage) - && RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.ACROBATICS_ROLL, player)) { + && SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.ACROBATICS_ROLL, player)) { NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Acrobatics.Roll.Text"); SoundManager.sendCategorizedSound(player, player.getLocation(), SoundType.ROLL_ACTIVATED, SoundCategory.PLAYERS); //player.sendMessage(LocaleLoader.getString("Acrobatics.Roll.Text")); @@ -236,11 +235,11 @@ private int getActivationChance(McMMOPlayer mcMMOPlayer) { private double gracefulRollCheck(Player player, McMMOPlayer mcMMOPlayer, double damage, int skillLevel) { double modifiedDamage = calculateModifiedRollDamage(damage, AdvancedConfig.getInstance().getRollDamageThreshold() * 2); - RandomChanceSkill rcs = new RandomChanceSkill(player, subSkillType); - rcs.setSkillLevel(rcs.getSkillLevel() * 2); //Double the effective odds + SkillProbabilityWrapper rcs = new SkillProbabilityWrapper(player, subSkillType); + rcs.setxPos(rcs.getxPos() * 2); //Double the effective odds if (!isFatal(player, modifiedDamage) - && RandomChanceUtil.checkRandomChanceExecutionSuccess(rcs)) + && RandomChanceUtil.processProbabilityResults(rcs)) { NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Acrobatics.Ability.Proc"); SoundManager.sendCategorizedSound(player, player.getLocation(), SoundType.ROLL_ACTIVATED, SoundCategory.PLAYERS,0.5F); @@ -373,17 +372,17 @@ public String getMechanics() { double rollChanceHalfMax, graceChanceHalfMax, damageThreshold, chancePerLevel; //Chance to roll at half max skill - RandomChanceSkill rollHalfMaxSkill = new RandomChanceSkill(null, subSkillType); + SkillProbabilityWrapper rollHalfMaxSkill = new SkillProbabilityWrapper(null, subSkillType); int halfMaxSkillValue = AdvancedConfig.getInstance().getMaxBonusLevel(SubSkillType.ACROBATICS_ROLL)/2; - rollHalfMaxSkill.setSkillLevel(halfMaxSkillValue); + rollHalfMaxSkill.setxPos(halfMaxSkillValue); //Chance to graceful roll at full skill - RandomChanceSkill rollGraceHalfMaxSkill = new RandomChanceSkill(null, subSkillType); - rollGraceHalfMaxSkill.setSkillLevel(halfMaxSkillValue * 2); //Double the effective odds + SkillProbabilityWrapper rollGraceHalfMaxSkill = new SkillProbabilityWrapper(null, subSkillType); + rollGraceHalfMaxSkill.setxPos(halfMaxSkillValue * 2); //Double the effective odds //Chance to roll per level - RandomChanceSkill rollOneSkillLevel = new RandomChanceSkill(null, subSkillType); - rollGraceHalfMaxSkill.setSkillLevel(1); //Level 1 skill + SkillProbabilityWrapper rollOneSkillLevel = new SkillProbabilityWrapper(null, subSkillType); + rollGraceHalfMaxSkill.setxPos(1); //Level 1 skill //Chance Stat Calculations rollChanceHalfMax = RandomChanceUtil.getRandomChanceExecutionChance(rollHalfMaxSkill); @@ -408,10 +407,10 @@ public Double[] getStats(Player player) { double playerChanceRoll, playerChanceGrace; - RandomChanceSkill roll = new RandomChanceSkill(player, getSubSkillType()); - RandomChanceSkill graceful = new RandomChanceSkill(player, getSubSkillType()); + SkillProbabilityWrapper roll = new SkillProbabilityWrapper(player, getSubSkillType()); + SkillProbabilityWrapper graceful = new SkillProbabilityWrapper(player, getSubSkillType()); - graceful.setSkillLevel(graceful.getSkillLevel() * 2); //Double odds + graceful.setxPos(graceful.getxPos() * 2); //Double odds //Calculate playerChanceRoll = RandomChanceUtil.getRandomChanceExecutionChance(roll); diff --git a/src/main/java/com/gmail/nossr50/datatypes/treasure/Treasure.java b/src/main/java/com/gmail/nossr50/datatypes/treasure/Treasure.java index 04ce7cca71..664760364a 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/treasure/Treasure.java +++ b/src/main/java/com/gmail/nossr50/datatypes/treasure/Treasure.java @@ -1,26 +1,37 @@ package com.gmail.nossr50.datatypes.treasure; import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.util.random.Probability; +import com.gmail.nossr50.util.random.ProbabilityFactory; +import com.gmail.nossr50.util.random.ProbabilityImpl; +import com.google.common.base.Objects; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; public abstract class Treasure { private int xp; private double dropChance; + private @NotNull Probability dropProbability; private int dropLevel; - private ItemStack drop; + private @NotNull ItemStack drop; public Treasure(ItemStack drop, int xp, double dropChance, int dropLevel) { this.drop = drop; this.xp = xp; this.dropChance = dropChance; + this.dropProbability = new ProbabilityImpl(ProbabilityFactory.probabilityFromPercent(dropChance)); this.dropLevel = dropLevel; } - public ItemStack getDrop() { + public @NotNull Probability getDropProbability() { + return dropProbability; + } + + public @NotNull ItemStack getDrop() { return drop; } - public void setDrop(ItemStack drop) { + public void setDrop(@NotNull ItemStack drop) { this.drop = drop; } @@ -36,8 +47,9 @@ public double getDropChance() { return dropChance; } - public void setDropChance(Double dropChance) { + public void setDropChance(double dropChance) { this.dropChance = dropChance; + this.dropProbability = new ProbabilityImpl(ProbabilityFactory.probabilityFromPercent(dropChance)); } public int getDropLevel() { @@ -51,4 +63,28 @@ public int getDropLevel() { public void setDropLevel(int dropLevel) { this.dropLevel = dropLevel; } + + @Override + public String toString() { + return "Treasure{" + + "xp=" + xp + + ", dropChance=" + dropChance + + ", dropProbability=" + dropProbability + + ", dropLevel=" + dropLevel + + ", drop=" + drop + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Treasure treasure = (Treasure) o; + return xp == treasure.xp && Double.compare(treasure.dropChance, dropChance) == 0 && dropLevel == treasure.dropLevel && Objects.equal(dropProbability, treasure.dropProbability) && Objects.equal(drop, treasure.drop); + } + + @Override + public int hashCode() { + return Objects.hashCode(xp, dropChance, dropProbability, dropLevel, drop); + } } diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index ede2081e6a..e653ceb5a7 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -25,9 +25,8 @@ import com.gmail.nossr50.util.compat.layers.persistentdata.MobMetaFlagType; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; -import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.CombatUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; +import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.worldguard.WorldGuardManager; import com.gmail.nossr50.worldguard.WorldGuardUtils; import org.bukkit.Material; @@ -180,7 +179,7 @@ public void onProjectileLaunch(ProjectileLaunchEvent event) { } } - if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.ARCHERY_ARROW_RETRIEVAL, player)) { + if (SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.ARCHERY_ARROW_RETRIEVAL, player)) { projectile.setMetadata(mcMMO.trackedArrow, mcMMO.metadataValue); } } diff --git a/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java b/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java index a4903e123d..f022d838ac 100644 --- a/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java @@ -12,10 +12,8 @@ import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; -import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.ParticleEffectUtils; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.Location; import org.bukkit.entity.Entity; @@ -88,7 +86,7 @@ public double dodgeCheck(Entity attacker, double damage) { double modifiedDamage = Acrobatics.calculateModifiedDodgeDamage(damage, Acrobatics.dodgeDamageModifier); Player player = getPlayer(); - if (!isFatal(modifiedDamage) && RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.ACROBATICS_DODGE, player)) { + if (!isFatal(modifiedDamage) && SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.ACROBATICS_DODGE, player)) { ParticleEffectUtils.playDodgeEffect(player); if (mmoPlayer.useChatNotifications()) { diff --git a/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java b/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java index 8ef8a0e1a2..ed03930535 100644 --- a/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java +++ b/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java @@ -9,9 +9,9 @@ import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; -import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillActivationType; +import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; @@ -88,7 +88,7 @@ public void retrieveArrows(LivingEntity target, Projectile projectile) { * @param defender The {@link Player} being affected by the ability */ public double daze(Player defender) { - if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.ARCHERY_DAZE, getPlayer())) { + if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.ARCHERY_DAZE, getPlayer())) { return 0; } @@ -116,7 +116,7 @@ public double daze(Player defender) { * @param oldDamage The raw damage value of this arrow before we modify it */ public double skillShot(double oldDamage) { - if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.ARCHERY_SKILL_SHOT, getPlayer())) { + if (!SkillUtils.isSkillRNGSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.ARCHERY_SKILL_SHOT, getPlayer())) { return oldDamage; } diff --git a/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java b/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java index ead48f6d85..15c94ee072 100644 --- a/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java +++ b/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java @@ -11,7 +11,7 @@ import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; -import com.gmail.nossr50.util.random.RandomChanceUtil; +import com.gmail.nossr50.util.random.SkillProbabilityType; import com.gmail.nossr50.util.skills.*; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; @@ -69,7 +69,7 @@ public boolean canActivateAbility() { * Handle the effects of the Axe Mastery ability */ public double axeMastery() { - if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.AXES_AXE_MASTERY, getPlayer())) { + if (!SkillUtils.isSkillRNGSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.AXES_AXE_MASTERY, getPlayer())) { return 0; } @@ -83,7 +83,7 @@ public double axeMastery() { * @param damage The amount of damage initially dealt by the event */ public double criticalHit(LivingEntity target, double damage) { - if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.AXES_CRITICAL_STRIKES, getPlayer())) { + if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.AXES_CRITICAL_STRIKES, getPlayer())) { return 0; } @@ -119,7 +119,7 @@ public void impactCheck(@NotNull LivingEntity target) { for (ItemStack armor : target.getEquipment().getArmorContents()) { if (armor != null && ItemUtils.isArmor(armor)) { - if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_STATIC_CHANCE, SubSkillType.AXES_ARMOR_IMPACT, getPlayer())) { + if (SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.AXES_ARMOR_IMPACT, getPlayer())) { SkillUtils.handleDurabilityChange(armor, durabilityDamage, 1); } } @@ -137,7 +137,7 @@ public double getImpactDurabilityDamage() { */ public double greaterImpact(@NotNull LivingEntity target) { //static chance (3rd param) - if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_STATIC_CHANCE, SubSkillType.AXES_GREATER_IMPACT, getPlayer())) { + if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.AXES_GREATER_IMPACT, getPlayer())) { return 0; } diff --git a/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java b/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java index 14eda7e320..3ed6f5f2a7 100644 --- a/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java +++ b/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java @@ -41,7 +41,7 @@ public void excavationBlockCheck(BlockState blockState) { for (ExcavationTreasure treasure : treasures) { if (skillLevel >= treasure.getDropLevel() - && RandomChanceUtil.checkRandomChanceExecutionSuccess(getPlayer(), PrimarySkillType.EXCAVATION, treasure.getDropChance())) { + && SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.EXCAVATION, getPlayer(), treasure.getDropProbability())) { //Spawn Vanilla XP orbs if a dice roll succeeds if(RandomChanceUtil.rollDice(getArchaelogyExperienceOrbChance(), 100)) { diff --git a/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java b/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java index b64de6a379..fef8816b5e 100644 --- a/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java @@ -20,8 +20,6 @@ import com.gmail.nossr50.util.*; import com.gmail.nossr50.util.compat.layers.skills.MasterAnglerCompatibilityLayer; import com.gmail.nossr50.util.player.NotificationManager; -import com.gmail.nossr50.util.random.RandomChanceSkillStatic; -import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; @@ -63,11 +61,14 @@ public FishingManager(McMMOPlayer mcMMOPlayer) { } public boolean canShake(Entity target) { - return target instanceof LivingEntity && RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.FISHING_SHAKE) && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.FISHING_SHAKE); + return target instanceof LivingEntity && RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.FISHING_SHAKE) + && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.FISHING_SHAKE); } public boolean canMasterAngler() { - return mcMMO.getCompatibilityManager().getMasterAnglerCompatibilityLayer() != null && getSkillLevel() >= RankUtils.getUnlockLevel(SubSkillType.FISHING_MASTER_ANGLER) && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.FISHING_MASTER_ANGLER); + return mcMMO.getCompatibilityManager().getMasterAnglerCompatibilityLayer() != null + && getSkillLevel() >= RankUtils.getUnlockLevel(SubSkillType.FISHING_MASTER_ANGLER) + && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.FISHING_MASTER_ANGLER); } // public void setFishingRodCastTimestamp() @@ -477,8 +478,8 @@ public Location getHookLocation() { * * @param target The {@link LivingEntity} affected by the ability */ - public void shakeCheck(LivingEntity target) { - if (RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getShakeChance(), getPlayer(), SubSkillType.FISHING_SHAKE))) { + public void shakeCheck(@NotNull LivingEntity target) { + if (SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.FISHING, getPlayer(), getShakeChance())) { List possibleDrops = Fishing.findPossibleDrops(target); if (possibleDrops == null || possibleDrops.isEmpty()) { diff --git a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java b/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java index 4a8104dd9f..906d538a4a 100644 --- a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java +++ b/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java @@ -21,10 +21,8 @@ import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.*; import com.gmail.nossr50.util.player.NotificationManager; -import com.gmail.nossr50.util.random.RandomChanceSkillStatic; import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; @@ -589,7 +587,7 @@ private boolean checkDoubleDrop(BlockState blockState) * @return true if the ability was successful, false otherwise */ public boolean processGreenThumbBlocks(BlockState blockState) { - if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.HERBALISM_GREEN_THUMB, getPlayer())) { + if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.HERBALISM_GREEN_THUMB, getPlayer())) { NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE_FAILED, "Herbalism.Ability.GTh.Fail"); return false; } @@ -604,7 +602,7 @@ public boolean processGreenThumbBlocks(BlockState blockState) { * @return true if the ability was successful, false otherwise */ public boolean processHylianLuck(BlockState blockState) { - if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.HERBALISM_HYLIAN_LUCK, getPlayer())) { + if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.HERBALISM_HYLIAN_LUCK, getPlayer())) { return false; } @@ -623,7 +621,7 @@ public boolean processHylianLuck(BlockState blockState) { for (HylianTreasure treasure : treasures) { if (skillLevel >= treasure.getDropLevel() - && RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(treasure.getDropChance(), getPlayer(), SubSkillType.HERBALISM_HYLIAN_LUCK))) { + && RandomChanceUtil.processProbabilityResults(new SkillProbabilityWrapperStatic(treasure.getDropChance(), getPlayer(), SubSkillType.HERBALISM_HYLIAN_LUCK))) { if (!EventUtils.simulateBlockBreak(blockState.getBlock(), player, false)) { return false; } @@ -660,7 +658,7 @@ public boolean processShroomThumb(BlockState blockState) { playerInventory.removeItem(new ItemStack(Material.RED_MUSHROOM)); player.updateInventory(); - if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.HERBALISM_SHROOM_THUMB, player)) { + if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.HERBALISM_SHROOM_THUMB, player)) { NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Herbalism.Ability.ShroomThumb.Fail"); return false; } diff --git a/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java b/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java index 8e8e56a3c9..527b34ef26 100644 --- a/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java +++ b/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java @@ -16,10 +16,8 @@ import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; -import com.gmail.nossr50.util.random.RandomChanceSkillStatic; import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; @@ -291,7 +289,7 @@ private boolean checkPlayerProcRepair() { if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.REPAIR_SUPER_REPAIR)) return false; - if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.REPAIR_SUPER_REPAIR, getPlayer())) { + if (SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.REPAIR_SUPER_REPAIR, getPlayer())) { NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Repair.Skills.FeltEasy"); return true; } @@ -342,10 +340,10 @@ private void addEnchants(ItemStack item) { Enchantment enchantment = enchant.getKey(); - if (RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getKeepEnchantChance(), getPlayer(), SubSkillType.REPAIR_ARCANE_FORGING))) { + if (RandomChanceUtil.processProbabilityResults(new SkillProbabilityWrapperStatic(getKeepEnchantChance(), getPlayer(), SubSkillType.REPAIR_ARCANE_FORGING))) { if (ArcaneForging.arcaneForgingDowngrades && enchantLevel > 1 - && (!RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(100 - getDowngradeEnchantChance(), getPlayer(), SubSkillType.REPAIR_ARCANE_FORGING)))) { + && (!RandomChanceUtil.processProbabilityResults(new SkillProbabilityWrapperStatic(100 - getDowngradeEnchantChance(), getPlayer(), SubSkillType.REPAIR_ARCANE_FORGING)))) { item.addUnsafeEnchantment(enchantment, enchantLevel - 1); downgraded = true; } diff --git a/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java b/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java index 2545a15d28..eaa044c989 100644 --- a/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java +++ b/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java @@ -16,7 +16,6 @@ import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; -import com.gmail.nossr50.util.random.RandomChanceSkillStatic; import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; @@ -123,7 +122,7 @@ public void handleSalvage(Location location, ItemStack item) { for(int x = 0; x < potentialSalvageYield-1; x++) { - if(RandomChanceUtil.rollDice(chanceOfSuccess, 100)) { + if(RandomChanceUtil.rollDiceSimple(chanceOfSuccess, 100)) { chanceOfSuccess-=3; chanceOfSuccess = Math.max(chanceOfSuccess, 90); @@ -253,12 +252,12 @@ private ItemStack arcaneSalvageCheck(Map enchants) { if (!Salvage.arcaneSalvageEnchantLoss || Permissions.hasSalvageEnchantBypassPerk(player) - || RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getExtractFullEnchantChance(), getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE))) { + || RandomChanceUtil.processProbabilityResults(new SkillProbabilityWrapperStatic(getExtractFullEnchantChance(), getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE))) { enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel, true); } else if (enchantLevel > 1 && Salvage.arcaneSalvageDowngrades - && RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getExtractPartialEnchantChance(), getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE))) { + && RandomChanceUtil.processProbabilityResults(new SkillProbabilityWrapperStatic(getExtractPartialEnchantChance(), getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE))) { enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel - 1, true); downgraded = true; } else { diff --git a/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java b/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java index 5187187658..5f48ea5d8e 100644 --- a/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java @@ -8,9 +8,8 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.Permissions; -import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; +import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.event.inventory.FurnaceBurnEvent; import org.bukkit.inventory.ItemStack; @@ -28,7 +27,7 @@ public SmeltingManager(McMMOPlayer mcMMOPlayer) { public boolean isSecondSmeltSuccessful() { return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.SMELTING_SECOND_SMELT) - && RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.SMELTING_SECOND_SMELT, getPlayer()); + && SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.SMELTING_SECOND_SMELT, getPlayer()); } /* diff --git a/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java b/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java index 1c3fa3766c..b7716667e9 100644 --- a/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java @@ -11,10 +11,9 @@ import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; -import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; +import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; @@ -62,7 +61,7 @@ public boolean canUseSerratedStrike() { */ public void ruptureCheck(@NotNull LivingEntity target) throws IllegalStateException { if(BleedTimerTask.isBleedOperationAllowed()) { - if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.SWORDS_RUPTURE, getPlayer())) { + if (SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.SWORDS_RUPTURE, getPlayer())) { if (target instanceof Player) { Player defender = (Player) target; @@ -129,7 +128,7 @@ public int getRuptureBleedTicks() * @param damage The amount of damage initially dealt by the event */ public void counterAttackChecks(@NotNull LivingEntity attacker, double damage) { - if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.SWORDS_COUNTER_ATTACK, getPlayer())) { + if (SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.SWORDS_COUNTER_ATTACK, getPlayer())) { CombatUtils.dealDamage(attacker, damage / Swords.counterAttackModifier, getPlayer()); NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Countered"); diff --git a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java index 6a902dd435..2f6c1d86ce 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java @@ -18,11 +18,10 @@ import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.compat.layers.persistentdata.MobMetaFlagType; import com.gmail.nossr50.util.player.NotificationManager; -import com.gmail.nossr50.util.random.RandomChanceSkillStatic; import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.ParticleEffectUtils; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; +import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; import com.gmail.nossr50.util.text.StringUtils; @@ -147,7 +146,7 @@ public void awardTamingXP(@NotNull LivingEntity entity) { * @param damage The damage being absorbed by the wolf */ public void fastFoodService(@NotNull Wolf wolf, double damage) { - if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_STATIC_CHANCE, SubSkillType.TAMING_FAST_FOOD_SERVICE, getPlayer())) { + if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.TAMING_FAST_FOOD_SERVICE, getPlayer())) { return; } @@ -168,7 +167,7 @@ public void fastFoodService(@NotNull Wolf wolf, double damage) { */ public double gore(@NotNull LivingEntity target, double damage) { if(BleedTimerTask.isBleedOperationAllowed()) { - if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.TAMING_GORE, getPlayer())) { + if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.TAMING_GORE, getPlayer())) { return 0; } @@ -276,7 +275,7 @@ public void pummel(LivingEntity target, Wolf wolf) { if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_PUMMEL)) return; - if(!RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(AdvancedConfig.getInstance().getPummelChance(), getPlayer(), SubSkillType.TAMING_PUMMEL))) + if(!RandomChanceUtil.processProbabilityResults(new SkillProbabilityWrapperStatic(AdvancedConfig.getInstance().getPummelChance(), getPlayer(), SubSkillType.TAMING_PUMMEL))) return; ParticleEffectUtils.playGreaterImpactEffect(target); diff --git a/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java b/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java index 73bf3dce91..b2fe84017c 100644 --- a/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java +++ b/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java @@ -16,9 +16,9 @@ import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; -import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillActivationType; +import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.entity.Item; @@ -72,7 +72,7 @@ public boolean canUseBlockCracker() { } public boolean blockCrackerCheck(@NotNull BlockState blockState) { - if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.UNARMED_BLOCK_CRACKER, getPlayer())) { + if (!SkillUtils.isSkillRNGSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.UNARMED_BLOCK_CRACKER, getPlayer())) { return false; } @@ -103,7 +103,7 @@ public boolean blockCrackerCheck(@NotNull BlockState blockState) { * @param defender The defending player */ public void disarmCheck(@NotNull Player defender) { - if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.UNARMED_DISARM, getPlayer()) && !hasIronGrip(defender)) { + if (SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.UNARMED_DISARM, getPlayer()) && !hasIronGrip(defender)) { if (EventUtils.callDisarmEvent(defender).isCancelled()) { return; } @@ -126,7 +126,7 @@ public void disarmCheck(@NotNull Player defender) { * Check for arrow deflection. */ public boolean deflectCheck() { - if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.UNARMED_ARROW_DEFLECT, getPlayer())) { + if (SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.UNARMED_ARROW_DEFLECT, getPlayer())) { NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Combat.ArrowDeflect"); return true; } @@ -149,7 +149,7 @@ public double berserkDamage(double damage) { * Handle the effects of the Iron Arm ability */ public double calculateSteelArmStyleDamage() { - if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.UNARMED_STEEL_ARM_STYLE, getPlayer())) { + if (!SkillUtils.isSkillRNGSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.UNARMED_STEEL_ARM_STYLE, getPlayer())) { return 0; } @@ -183,7 +183,7 @@ public double getSteelArmStyleDamage() { private boolean hasIronGrip(@NotNull Player defender) { if (!Misc.isNPCEntityExcludingVillagers(defender) && Permissions.isSubSkillEnabled(defender, SubSkillType.UNARMED_IRON_GRIP) - && RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.UNARMED_IRON_GRIP, defender)) { + && SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.UNARMED_IRON_GRIP, defender)) { NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, "Unarmed.Ability.IronGrip.Defender"); NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Unarmed.Ability.IronGrip.Attacker"); diff --git a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java index 4aa7cb4783..d86c0d698c 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java @@ -17,7 +17,6 @@ import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -70,11 +69,11 @@ public boolean canUseTreeFeller(ItemStack heldItem) { } private boolean checkHarvestLumberActivation() { - return RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.WOODCUTTING_HARVEST_LUMBER, getPlayer()); + return SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.WOODCUTTING_HARVEST_LUMBER, getPlayer()); } private boolean checkCleanCutsActivation() { - return RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.WOODCUTTING_CLEAN_CUTS, getPlayer()); + return SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.WOODCUTTING_CLEAN_CUTS, getPlayer()); } /** @@ -328,7 +327,7 @@ private void dropTreeFellerLootFromBlocks(@NotNull Set treeFellerBlo if(RankUtils.hasReachedRank(2, player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) { if(AdvancedConfig.getInstance().isKnockOnWoodXPOrbEnabled()) { - if(RandomChanceUtil.rollDice(10, 100)) { + if(RandomChanceUtil.rollDiceSimple(10, 100)) { int randOrbCount = Math.max(1, Misc.getRandom().nextInt(100)); Misc.spawnExperienceOrb(blockState.getLocation(), randOrbCount); } diff --git a/src/main/java/com/gmail/nossr50/util/BlockUtils.java b/src/main/java/com/gmail/nossr50/util/BlockUtils.java index 80c5a3ca15..a951057b59 100644 --- a/src/main/java/com/gmail/nossr50/util/BlockUtils.java +++ b/src/main/java/com/gmail/nossr50/util/BlockUtils.java @@ -8,7 +8,6 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.repair.Repair; import com.gmail.nossr50.skills.salvage.Salvage; -import com.gmail.nossr50.util.random.RandomChanceSkill; import com.gmail.nossr50.util.random.RandomChanceUtil; import org.bukkit.Material; import org.bukkit.block.Block; @@ -55,7 +54,7 @@ public static void markDropsAsBonus(@NotNull BlockState blockState, int amount) */ public static boolean checkDoubleDrops(Player player, BlockState blockState, PrimarySkillType skillType, SubSkillType subSkillType) { if (Config.getInstance().getDoubleDropsEnabled(skillType, blockState.getType()) && Permissions.isSubSkillEnabled(player, subSkillType)) { - return RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkill(player, subSkillType, true)); + return RandomChanceUtil.processProbabilityResults(new SkillProbabilityWrapper(player, subSkillType, true)); } return false; diff --git a/src/main/java/com/gmail/nossr50/util/Misc.java b/src/main/java/com/gmail/nossr50/util/Misc.java index 9b74f110ca..1bd24c5e37 100644 --- a/src/main/java/com/gmail/nossr50/util/Misc.java +++ b/src/main/java/com/gmail/nossr50/util/Misc.java @@ -344,4 +344,26 @@ public void run() { experienceOrb.setExperience(orbExpValue); } } + +// public static void hackyUnitTest(@NotNull McMMOPlayer normalPlayer) { +// mcMMO.p.getLogger().info("Starting hacky unit test..."); +// int iterations = 1000000; +// double ratioDivisor = 10000; //10000 because we run the test 1,000,000 times +// double expectedFailRate = 100.0D - RandomChanceUtil.getRandomChanceExecutionSuccess(normalPlayer.getPlayer(), SubSkillType.MINING_MOTHER_LODE, true); +// +// double win = 0, loss = 0; +// for(int x = 0; x < iterations; x++) { +// if(RandomChanceUtil.checkRandomChanceExecutionSuccess(normalPlayer.getPlayer(), SubSkillType.MINING_MOTHER_LODE, true)) { +// win++; +// } else { +// loss++; +// } +// } +// +// double lossRatio = (loss / ratioDivisor); +// mcMMO.p.getLogger().info("Expected Fail Rate: "+expectedFailRate); +// mcMMO.p.getLogger().info("Loss Ratio for hacky test: "+lossRatio); +//// Assert.assertEquals(lossRatio, expectedFailRate, 0.01D); +// } + } diff --git a/src/main/java/com/gmail/nossr50/util/random/Probability.java b/src/main/java/com/gmail/nossr50/util/random/Probability.java new file mode 100644 index 0000000000..0e939bc8be --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/random/Probability.java @@ -0,0 +1,14 @@ +package com.gmail.nossr50.util.random; + +public interface Probability { + /** + * The value of this Probability + * Should return a result between 0 and 1 (inclusive) + * 1 should represent something that will always succeed + * 0.5 should represent something that succeeds around half the time + * etc + * + * @return the value of probability + */ + double getValue(); +} diff --git a/src/main/java/com/gmail/nossr50/util/random/ProbabilityFactory.java b/src/main/java/com/gmail/nossr50/util/random/ProbabilityFactory.java new file mode 100644 index 0000000000..f3a7db5b20 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/random/ProbabilityFactory.java @@ -0,0 +1,77 @@ +package com.gmail.nossr50.util.random; + +import com.gmail.nossr50.config.AdvancedConfig; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.util.player.UserManager; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class ProbabilityFactory { + + public static @NotNull Probability ofPercentageValue(double percentageValue) { + return new ProbabilityImpl(probabilityFromPercent(percentageValue)); + } + + public static @NotNull Probability ofSubSkill(@Nullable Player player, + @NotNull SubSkillType subSkillType, + @NotNull SkillProbabilityType skillProbabilityType) throws InvalidStaticChance, RuntimeException { + + switch (skillProbabilityType) { + case DYNAMIC_CONFIGURABLE: + double probabilityCeiling; + double xCeiling; + double xPos; + + if (player != null) { + McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + if(mmoPlayer != null) + xPos = mmoPlayer.getSkillLevel(subSkillType.getParentSkill()); + else + xPos = 0; + } else { + xPos = 0; + } + + //Probability ceiling is configurable in this type + probabilityCeiling = AdvancedConfig.getInstance().getMaximumProbability(subSkillType); + //The xCeiling is configurable in this type + xCeiling = AdvancedConfig.getInstance().getMaxBonusLevel(subSkillType); + return new ProbabilityImpl(xPos, xCeiling, probabilityCeiling); + case STATIC_CONFIGURABLE: + return ofPercentageValue(getStaticRandomChance(subSkillType)); + default: + throw new RuntimeException("No case in switch statement for Skill Probability Type!"); + } + } + + /** + * Convert a probability from a percentage + * @param percentage value to convert + * @return 0 -> 1 inclusive representation of probability + */ + public static double probabilityFromPercent(double percentage) { + return percentage / 100; + } + + /** + * Grabs static activation rolls for Secondary Abilities + * + * @param subSkillType The secondary ability to grab properties of + * @return The static activation roll involved in the RNG calculation + * @throws InvalidStaticChance if the skill has no defined static chance this exception will be thrown and you should know you're a naughty boy + */ + private static double getStaticRandomChance(@NotNull SubSkillType subSkillType) throws InvalidStaticChance { + switch (subSkillType) { + case AXES_ARMOR_IMPACT: + return AdvancedConfig.getInstance().getImpactChance(); + case AXES_GREATER_IMPACT: + return AdvancedConfig.getInstance().getGreaterImpactChance(); + case TAMING_FAST_FOOD_SERVICE: + return AdvancedConfig.getInstance().getFastFoodChance(); + default: + throw new InvalidStaticChance(); + } + } +} diff --git a/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java b/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java new file mode 100644 index 0000000000..6401ca7574 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java @@ -0,0 +1,63 @@ +package com.gmail.nossr50.util.random; + +import com.gmail.nossr50.api.exceptions.ValueOutOfBoundsException; +import com.google.common.base.Objects; + +public class ProbabilityImpl implements Probability { + + private final double probabilityValue; + + /** + * Create a probability with a static value + * + * @param staticProbability the value to assign to this probability + */ + public ProbabilityImpl(double staticProbability) throws ValueOutOfBoundsException { + if(staticProbability > 1) { + throw new ValueOutOfBoundsException("Value should never be above 1 for Probability! This suggests a coding mistake, contact the devs!"); + } else if (staticProbability < 0) { + throw new ValueOutOfBoundsException("Value should never be negative for Probability! This suggests a coding mistake, contact the devs!"); + } + + probabilityValue = staticProbability; + } + + public ProbabilityImpl(double xPos, double xCeiling, double probabilityCeiling) throws ValueOutOfBoundsException { + if(probabilityCeiling > 100) { + throw new ValueOutOfBoundsException("Probability Ceiling should never be above 100!"); + } else if (probabilityCeiling < 0) { + throw new ValueOutOfBoundsException("Probability Ceiling should never be below 0!"); + } + + //Get the percent success, this will be from 0-100 + double probabilityPercent = (probabilityCeiling * (xPos / xCeiling)); + + //Convert to a 0-1 floating point representation + this.probabilityValue = probabilityPercent / 100.0D; + } + + @Override + public double getValue() { + return probabilityValue; + } + + @Override + public String toString() { + return "ProbabilityImpl{" + + "probabilityValue=" + probabilityValue + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ProbabilityImpl that = (ProbabilityImpl) o; + return Double.compare(that.probabilityValue, probabilityValue) == 0; + } + + @Override + public int hashCode() { + return Objects.hashCode(probabilityValue); + } +} diff --git a/src/main/java/com/gmail/nossr50/util/random/RandomChanceExecution.java b/src/main/java/com/gmail/nossr50/util/random/RandomChanceExecution.java deleted file mode 100644 index e5d51d7401..0000000000 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceExecution.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.gmail.nossr50.util.random; - -public interface RandomChanceExecution { - /** - * Gets the XPos used in the formula for success - * - * @return value of x for our success probability graph - */ - double getXPos(); - - /** - * The maximum odds for this RandomChanceExecution - * For example, if this value is 10, then 10% odds would be the maximum and would be achieved only when xPos equaled the LinearCurvePeak - * - * @return maximum probability odds from 0.00 (no chance of ever happened) to 100.0 (probability can be guaranteed) - */ - double getProbabilityCap(); -} diff --git a/src/main/java/com/gmail/nossr50/util/random/RandomChanceSkill.java b/src/main/java/com/gmail/nossr50/util/random/RandomChanceSkill.java deleted file mode 100644 index 92d91ec831..0000000000 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceSkill.java +++ /dev/null @@ -1,176 +0,0 @@ -package com.gmail.nossr50.util.random; - -import com.gmail.nossr50.datatypes.player.McMMOPlayer; -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.jetbrains.annotations.Nullable; - -public class RandomChanceSkill implements RandomChanceExecution { - protected final double probabilityCap; - protected final boolean isLucky; - protected int skillLevel; - protected final double resultModifier; - protected final double maximumBonusLevelCap; - - public RandomChanceSkill(@Nullable Player player, @NotNull SubSkillType subSkillType, double resultModifier) { - this.probabilityCap = RandomChanceUtil.LINEAR_CURVE_VAR; - - final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); - if (player != null && mcMMOPlayer != null) { - this.skillLevel = mcMMOPlayer.getSkillLevel(subSkillType.getParentSkill()); - } else { - this.skillLevel = 0; - } - - if (player != null) - isLucky = Permissions.lucky(player, subSkillType.getParentSkill()); - else - isLucky = false; - - this.resultModifier = resultModifier; - this.maximumBonusLevelCap = RandomChanceUtil.getMaxBonusLevelCap(subSkillType); - } - - public RandomChanceSkill(@Nullable Player player, @NotNull SubSkillType subSkillType) { - this.probabilityCap = RandomChanceUtil.LINEAR_CURVE_VAR; - - final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); - if (player != null && mcMMOPlayer != null) { - this.skillLevel = mcMMOPlayer.getSkillLevel(subSkillType.getParentSkill()); - } else { - this.skillLevel = 0; - } - - if (player != null) - isLucky = Permissions.lucky(player, subSkillType.getParentSkill()); - else - isLucky = false; - - this.resultModifier = 1.0D; - this.maximumBonusLevelCap = RandomChanceUtil.getMaxBonusLevelCap(subSkillType); - } - - public RandomChanceSkill(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean hasCap) { - if (hasCap) - this.probabilityCap = RandomChanceUtil.getMaximumProbability(subSkillType); - else - this.probabilityCap = RandomChanceUtil.LINEAR_CURVE_VAR; - - final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); - if (player != null && mcMMOPlayer != null) { - this.skillLevel = mcMMOPlayer.getSkillLevel(subSkillType.getParentSkill()); - } else { - this.skillLevel = 0; - } - - if (player != null) - isLucky = Permissions.lucky(player, subSkillType.getParentSkill()); - else - isLucky = false; - - this.resultModifier = 1.0D; - this.maximumBonusLevelCap = RandomChanceUtil.getMaxBonusLevelCap(subSkillType); - } - - public RandomChanceSkill(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean hasCap, boolean luckyOverride) { - if (hasCap) - this.probabilityCap = RandomChanceUtil.getMaximumProbability(subSkillType); - else - this.probabilityCap = RandomChanceUtil.LINEAR_CURVE_VAR; - - final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); - if (player != null && mcMMOPlayer != null) { - this.skillLevel = mcMMOPlayer.getSkillLevel(subSkillType.getParentSkill()); - } else { - this.skillLevel = 0; - } - - isLucky = luckyOverride; - - this.resultModifier = 1.0D; - this.maximumBonusLevelCap = RandomChanceUtil.getMaxBonusLevelCap(subSkillType); - } - - public RandomChanceSkill(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean hasCap, double resultModifier) { - if (hasCap) - this.probabilityCap = RandomChanceUtil.getMaximumProbability(subSkillType); - else - this.probabilityCap = RandomChanceUtil.LINEAR_CURVE_VAR; - - final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); - if (player != null && mcMMOPlayer != null) { - this.skillLevel = mcMMOPlayer.getSkillLevel(subSkillType.getParentSkill()); - } else { - this.skillLevel = 0; - } - - if (player != null) - isLucky = Permissions.lucky(player, subSkillType.getParentSkill()); - else - isLucky = false; - - this.resultModifier = resultModifier; - this.maximumBonusLevelCap = RandomChanceUtil.getMaxBonusLevelCap(subSkillType); - } - - /** - * Gets the skill level of the player who owns this RandomChanceSkill - * - * @return the current skill level relating to this RandomChanceSkill - */ - public int getSkillLevel() { - return skillLevel; - } - - /** - * Modify the skill level used for this skill's RNG calculations - * - * @param newSkillLevel new skill level - */ - public void setSkillLevel(int newSkillLevel) { - skillLevel = newSkillLevel; - } - - /** - * The maximum bonus level for this skill - * This is when the skills level no longer increases the odds of success - * For example, a value of 25 will mean the success chance no longer grows after skill level 25 - * - * @return the maximum bonus from skill level for this skill - */ - public double getMaximumBonusLevelCap() { - return maximumBonusLevelCap; - } - - /** - * Gets the XPos used in the formula for success - * - * @return value of x for our success probability graph - */ - @Override - public double getXPos() { - return getSkillLevel(); - } - - /** - * The maximum odds for this RandomChanceExecution - * For example, if this value is 10, then 10% odds would be the maximum and would be achieved only when xPos equaled the LinearCurvePeak - * - * @return maximum probability odds from 0.00 (no chance of ever happened) to 100.0 (probability can be guaranteed) - */ - @Override - public double getProbabilityCap() { - return probabilityCap; - } - - public boolean isLucky() { - return isLucky; - } - - public double getResultModifier() { - return resultModifier; - } -} diff --git a/src/main/java/com/gmail/nossr50/util/random/RandomChanceSkillStatic.java b/src/main/java/com/gmail/nossr50/util/random/RandomChanceSkillStatic.java deleted file mode 100644 index c96b71d6b7..0000000000 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceSkillStatic.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.gmail.nossr50.util.random; - -import com.gmail.nossr50.datatypes.skills.SubSkillType; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class RandomChanceSkillStatic extends RandomChanceSkill { - private final double xPos; - - public RandomChanceSkillStatic(double xPos, @Nullable Player player, @NotNull SubSkillType subSkillType) { - super(player, subSkillType); - - this.xPos = xPos; - } - - public RandomChanceSkillStatic(double xPos, @Nullable Player player, @NotNull SubSkillType subSkillType, boolean luckyOverride) { - super(player, subSkillType, false, luckyOverride); - - this.xPos = xPos; - } - - public RandomChanceSkillStatic(double xPos, @Nullable Player player, @NotNull SubSkillType subSkillType, double resultModifier) { - super(player, subSkillType, resultModifier); - - this.xPos = xPos; - } - - /** - * Gets the XPos used in the formula for success - * - * @return value of x for our success probability graph - */ - @Override - public double getXPos() { - return xPos; - } - - /** - * The maximum odds for this RandomChanceExecution - * For example, if this value is 10, then 10% odds would be the maximum and would be achieved only when xPos equaled the LinearCurvePeak - * - * @return maximum probability odds from 0.00 (no chance of ever happened) to 100.0 (probability can be guaranteed) - */ - @Override - public double getProbabilityCap() { - return probabilityCap; - } - - /** - * The maximum bonus level for this skill - * This is when the skills level no longer increases the odds of success - * For example, a value of 25 will mean the success chance no longer grows after skill level 25 - * - * @return the maximum bonus from skill level for this skill - */ - @Override - public double getMaximumBonusLevelCap() { - return 100; - } -} diff --git a/src/main/java/com/gmail/nossr50/util/random/RandomChanceStatic.java b/src/main/java/com/gmail/nossr50/util/random/RandomChanceStatic.java deleted file mode 100644 index 3204a348d0..0000000000 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceStatic.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.gmail.nossr50.util.random; - -public class RandomChanceStatic implements RandomChanceExecution { - private final double xPos; - private final double probabilityCap; - private final boolean isLucky; - - public RandomChanceStatic(double xPos, boolean isLucky) { - this.xPos = xPos; - this.probabilityCap = xPos; - this.isLucky = isLucky; - } - - /** - * Gets the XPos used in the formula for success - * - * @return value of x for our success probability graph - */ - @Override - public double getXPos() { - return xPos; - } - - /** - * The maximum odds for this RandomChanceExecution - * For example, if this value is 10, then 10% odds would be the maximum and would be achieved only when xPos equaled the LinearCurvePeak - * - * @return maximum probability odds from 0.00 (no chance of ever happened) to 100.0 (probability can be guaranteed) - */ - @Override - public double getProbabilityCap() { - return probabilityCap; - } - - public boolean isLucky() { - return isLucky; - } -} diff --git a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java index 200893fa7f..8641860bec 100644 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java +++ b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java @@ -1,325 +1,78 @@ package com.gmail.nossr50.util.random; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; -import com.gmail.nossr50.events.skills.secondaryabilities.SubSkillEvent; -import com.gmail.nossr50.events.skills.secondaryabilities.SubSkillRandomCheckEvent; -import com.gmail.nossr50.util.EventUtils; -import com.gmail.nossr50.util.Permissions; -import com.gmail.nossr50.util.skills.SkillActivationType; +import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.text.DecimalFormat; import java.util.concurrent.ThreadLocalRandom; +//TODO: Normalize chance values +//TODO: Test the 2 types of SkillProbabilityTypes +//TODO: Update calls to this class and its members public class RandomChanceUtil { public static final @NotNull DecimalFormat percent = new DecimalFormat("##0.00%"); - //public static final DecimalFormat decimal = new DecimalFormat("##0.00"); - public static final double LINEAR_CURVE_VAR = 100.0D; public static final double LUCKY_MODIFIER = 1.333D; /** - * This method is the final step in determining if a Sub-Skill / Secondary Skill in mcMMO successfully activates either from chance or otherwise - * Random skills check for success based on numbers and then fire a cancellable event, if that event is not cancelled they succeed - * non-RNG skills just fire the cancellable event and succeed if they go uncancelled + * Simulate an outcome on a probability and return true or false for the result of that outcome * - * @param skillActivationType this value represents what kind of activation procedures this sub-skill uses - * @param subSkillType The identifier for this specific sub-skill - * @param player The owner of this sub-skill - * @return returns true if all conditions are met and the event is not cancelled + * @param probability target probability + * @return true if the probability succeeded, false if it failed */ - public static boolean isActivationSuccessful(@NotNull SkillActivationType skillActivationType, @NotNull SubSkillType subSkillType, @Nullable Player player) { - switch (skillActivationType) { - case RANDOM_LINEAR_100_SCALE_WITH_CAP: - return checkRandomChanceExecutionSuccess(player, subSkillType, true); - case RANDOM_STATIC_CHANCE: - return checkRandomStaticChanceExecutionSuccess(player, subSkillType); - case ALWAYS_FIRES: - SubSkillEvent event = EventUtils.callSubSkillEvent(player, subSkillType); - return !event.isCancelled(); - default: - return false; - } - } - - public static double getActivationChance(@NotNull SkillActivationType skillActivationType, @NotNull SubSkillType subSkillType, @Nullable Player player, boolean luckyOverride) { - switch (skillActivationType) { - case RANDOM_LINEAR_100_SCALE_WITH_CAP: - return getRandomChanceExecutionSuccess(player, subSkillType, true, luckyOverride); - case RANDOM_STATIC_CHANCE: - return getRandomStaticChanceExecutionSuccess(player, subSkillType, luckyOverride); - default: - return 0.1337; - } - } - - /** - * Checks whether or not the random chance succeeds - * - * @return true if the random chance succeeds - */ - public static boolean checkRandomChanceExecutionSuccess(@NotNull Player player, @NotNull PrimarySkillType primarySkillType, double chance) { - //Check the odds - chance *= 100; - - chance = addLuck(player, primarySkillType, chance); - - /* - * Stuff like treasures can specify a drop chance from 0.05 to 100 - * Because of that we need to use a large int bound and multiply the chance by 100 - */ - return rollDice(chance, 10000); - } - - public static boolean rollDice(double chanceOfSuccess, int bound) { - return rollDice(chanceOfSuccess, bound, 1.0F); - } - - public static boolean rollDice(double chanceOfSuccess, int bound, double resultModifier) { - return chanceOfSuccess > (ThreadLocalRandom.current().nextInt(bound) * resultModifier); + public static boolean processProbability(@NotNull Probability probability) { + return isSuccessfulRoll(probability.getValue()); } /** - * Used for stuff like Excavation, Fishing, etc... + * Modify and then Simulate an outcome on a probability and return true or false for the result of that outcome * - * @param randomChance - * @return + * @param probability target probability + * @param probabilityMultiplier probability will be multiplied by this before success is checked + * @return true if the probability succeeded, false if it failed */ - public static boolean checkRandomChanceExecutionSuccess(@NotNull RandomChanceSkillStatic randomChance, double resultModifier) { - double chanceOfSuccess = calculateChanceOfSuccess(randomChance); - - //Check the odds - return rollDice(chanceOfSuccess, 100, resultModifier); + public static boolean processProbability(@NotNull Probability probability, double probabilityMultiplier) { + double probabilityValue = probability.getValue() * probabilityMultiplier; + return isSuccessfulRoll(probabilityValue); } /** - * Used for stuff like Excavation, Fishing, etc... + * Simulates a "roll of the dice" + * If the value passed is higher than the "random" value, than it is a successful roll * - * @param randomChance - * @return + * @param probabilityValue probability value + * @return true for succeeding, false for failing */ - public static boolean checkRandomChanceExecutionSuccess(@NotNull RandomChanceSkillStatic randomChance) { - return checkRandomChanceExecutionSuccess(randomChance, 1.0F); - } - - public static boolean checkRandomChanceExecutionSuccess(@NotNull RandomChanceSkill randomChance) { - double chanceOfSuccess = calculateChanceOfSuccess(randomChance); - - //Check the odds - return rollDice(chanceOfSuccess, 100); + private static boolean isSuccessfulRoll(double probabilityValue) { + return probabilityValue >= ThreadLocalRandom.current().nextDouble(1.0D); } /** - * Gets the Static Chance for something to activate + * Return a chance of success in "percentage" format, show to the player in UI elements * - * @param randomChance - * @return - */ - public static double getRandomChanceExecutionChance(@NotNull RandomChanceExecution randomChance) { - return getChanceOfSuccess(randomChance.getXPos(), randomChance.getProbabilityCap(), LINEAR_CURVE_VAR); - } - - public static double getRandomChanceExecutionChance(@NotNull RandomChanceExecution randomChance, boolean luckyOverride) { - return getChanceOfSuccess(randomChance.getXPos(), randomChance.getProbabilityCap(), LINEAR_CURVE_VAR); - } - - public static double getRandomChanceExecutionChance(@NotNull RandomChanceStatic randomChance) { - double chanceOfSuccess = getChanceOfSuccess(randomChance.getXPos(), randomChance.getProbabilityCap(), LINEAR_CURVE_VAR); - - chanceOfSuccess = addLuck(randomChance.isLucky(), chanceOfSuccess); - - return chanceOfSuccess; - } - - public static double calculateChanceOfSuccess(@NotNull RandomChanceSkill randomChance) { - double skillLevel = randomChance.getSkillLevel(); - double maximumProbability = randomChance.getProbabilityCap(); - double maximumBonusLevel = randomChance.getMaximumBonusLevelCap(); - - double chanceOfSuccess; - - if (skillLevel >= maximumBonusLevel) { - //Chance of success is equal to the maximum probability if the maximum bonus level has been reached - chanceOfSuccess = maximumProbability; - } else { - //Get chance of success - chanceOfSuccess = getChanceOfSuccess(randomChance.getXPos(), maximumProbability, maximumBonusLevel); - } - - //Add Luck - chanceOfSuccess = addLuck(randomChance.isLucky(), chanceOfSuccess); - - return chanceOfSuccess; - } - - public static double calculateChanceOfSuccess(@NotNull RandomChanceSkillStatic randomChance) { - double chanceOfSuccess = getChanceOfSuccess(randomChance.getXPos(), 100, 100); - - //Add Luck - chanceOfSuccess = addLuck(randomChance.isLucky(), chanceOfSuccess); - - return chanceOfSuccess; - } - - /** - * The formula for RNG success is determined like this - * maximum probability * ( x / maxlevel ) + * @param player target player + * @param subSkillType target subskill + * @param isLucky whether or not to apply luck modifiers * - * @return the chance of success from 0-100 (100 = guaranteed) + * @return "percentage" representation of success */ - private static int getChanceOfSuccess(double skillLevel, double maxProbability, double maxLevel) { - //return (int) (x / (y / LINEAR_CURVE_VAR)); - return (int) (maxProbability * (skillLevel / maxLevel)); - // max probability * (weight/maxlevel) = chance of success - } - - private static int getChanceOfSuccess(double x, double y) { - return (int) (x / (y / LINEAR_CURVE_VAR)); - // max probability * (weight/maxlevel) = chance of success - } - - public static double getRandomChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean hasCap) { - RandomChanceSkill rcs = new RandomChanceSkill(player, subSkillType, hasCap); - return calculateChanceOfSuccess(rcs); - } - - public static double getRandomChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean hasCap, boolean luckyOverride) { - RandomChanceSkill rcs = new RandomChanceSkill(player, subSkillType, hasCap, luckyOverride); - return calculateChanceOfSuccess(rcs); - } - - public static double getRandomStaticChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean luckyOverride) { + private static double chanceOfSuccessPercentage(@NotNull Player player, @NotNull SubSkillType subSkillType, boolean isLucky) { try { - return getRandomChanceExecutionChance(new RandomChanceSkillStatic(getStaticRandomChance(subSkillType), player, subSkillType, luckyOverride)); - } catch (InvalidStaticChance invalidStaticChance) { - //Catch invalid static skills - invalidStaticChance.printStackTrace(); - } - - return 0.1337; //Puts on shades - } - - public static boolean checkRandomChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean hasCap) { - return checkRandomChanceExecutionSuccess(new RandomChanceSkill(player, subSkillType, hasCap)); - } - - public static boolean checkRandomChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType) { - return checkRandomChanceExecutionSuccess(new RandomChanceSkill(player, subSkillType)); - } - - public static boolean checkRandomChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean hasCap, double resultModifier) { - return checkRandomChanceExecutionSuccess(new RandomChanceSkill(player, subSkillType, hasCap, resultModifier)); - } - - public static boolean checkRandomChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType, double resultModifier) { - return checkRandomChanceExecutionSuccess(new RandomChanceSkill(player, subSkillType, resultModifier)); - } + Probability probability = SkillUtils.getSubSkillProbability(subSkillType, player); + //Probability values are on a 0-1 scale and need to be "transformed" into a 1-100 scale + double percentageValue = probability.getValue() * 100; + //Apply lucky modifier + if(isLucky) { + percentageValue *= LUCKY_MODIFIER; + } - public static boolean checkRandomStaticChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType) { - try { - return checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getStaticRandomChance(subSkillType), player, subSkillType)); + return percentageValue; } catch (InvalidStaticChance invalidStaticChance) { - //Catch invalid static skills invalidStaticChance.printStackTrace(); + return 0; } - - return false; - } - - /** - * Grabs static activation rolls for Secondary Abilities - * - * @param subSkillType The secondary ability to grab properties of - * @return The static activation roll involved in the RNG calculation - * @throws InvalidStaticChance if the skill has no defined static chance this exception will be thrown and you should know you're a naughty boy - */ - public static double getStaticRandomChance(@NotNull SubSkillType subSkillType) throws InvalidStaticChance { - switch (subSkillType) { - case AXES_ARMOR_IMPACT: - return AdvancedConfig.getInstance().getImpactChance(); - case AXES_GREATER_IMPACT: - return AdvancedConfig.getInstance().getGreaterImpactChance(); - case TAMING_FAST_FOOD_SERVICE: - return AdvancedConfig.getInstance().getFastFoodChance(); - default: - throw new InvalidStaticChance(); - } - } - - public static boolean sendSkillEvent(Player player, SubSkillType subSkillType, double activationChance) { - SubSkillRandomCheckEvent event = new SubSkillRandomCheckEvent(player, subSkillType, activationChance); - return !event.isCancelled(); - } - - public static String @NotNull [] calculateAbilityDisplayValues(@NotNull SkillActivationType skillActivationType, @NotNull Player player, @NotNull SubSkillType subSkillType) { - double successChance = getActivationChance(skillActivationType, subSkillType, player, false); - double successChanceLucky = getActivationChance(skillActivationType, subSkillType, player, true); - - String[] displayValues = new String[2]; - - boolean isLucky = Permissions.lucky(player, subSkillType.getParentSkill()); - - displayValues[0] = percent.format(Math.min(successChance, 100.0D) / 100.0D); - displayValues[1] = isLucky ? percent.format(Math.min(successChanceLucky, 100.0D) / 100.0D) : null; - - return displayValues; - } - - public static String @NotNull [] calculateAbilityDisplayValuesStatic(@NotNull Player player, @NotNull PrimarySkillType primarySkillType, double chance) { - RandomChanceStatic rcs = new RandomChanceStatic(chance, false); - double successChance = getRandomChanceExecutionChance(rcs); - - RandomChanceStatic rcs_lucky = new RandomChanceStatic(chance, true); - double successChance_lucky = getRandomChanceExecutionChance(rcs_lucky); - - String[] displayValues = new String[2]; - - boolean isLucky = Permissions.lucky(player, primarySkillType); - - displayValues[0] = percent.format(Math.min(successChance, 100.0D) / 100.0D); - displayValues[1] = isLucky ? percent.format(Math.min(successChance_lucky, 100.0D) / 100.0D) : null; - - return displayValues; } - public static String @NotNull [] calculateAbilityDisplayValuesCustom(@NotNull SkillActivationType skillActivationType, @NotNull Player player, @NotNull SubSkillType subSkillType, double multiplier) { - double successChance = getActivationChance(skillActivationType, subSkillType, player, false); - double successChanceLucky = getActivationChance(skillActivationType, subSkillType, player, true); - //TODO: Most likely incorrectly displays the value for graceful roll but gonna ignore for now... - successChance *= multiplier; //Currently only used for graceful roll - String[] displayValues = new String[2]; - - boolean isLucky = Permissions.lucky(player, subSkillType.getParentSkill()); - - displayValues[0] = percent.format(Math.min(successChance, 100.0D) / 100.0D); - displayValues[1] = isLucky ? percent.format(Math.min(successChanceLucky, 100.0D) / 100.0D) : null; - - return displayValues; - } - - public static double addLuck(@NotNull Player player, @NotNull PrimarySkillType primarySkillType, double chance) { - if (Permissions.lucky(player, primarySkillType)) - return chance * LUCKY_MODIFIER; - else - return chance; - } - - public static double addLuck(boolean isLucky, double chance) { - if (isLucky) - return chance * LUCKY_MODIFIER; - else - return chance; - } - - public static double getMaximumProbability(@NotNull SubSkillType subSkillType) { - return AdvancedConfig.getInstance().getMaximumProbability(subSkillType); - } - - public static double getMaxBonusLevelCap(@NotNull SubSkillType subSkillType) { - return AdvancedConfig.getInstance().getMaxBonusLevel(subSkillType); - } } diff --git a/src/main/java/com/gmail/nossr50/util/random/SkillProbabilityType.java b/src/main/java/com/gmail/nossr50/util/random/SkillProbabilityType.java new file mode 100644 index 0000000000..95814f6a1d --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/random/SkillProbabilityType.java @@ -0,0 +1,6 @@ +package com.gmail.nossr50.util.random; + +public enum SkillProbabilityType { + DYNAMIC_CONFIGURABLE, //Has multiple values used for calculation (taken from config files) + STATIC_CONFIGURABLE, //A single value used for calculations (taken from config files) +} diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java index 08b931764e..13c4049637 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java @@ -14,9 +14,11 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.compat.layers.persistentdata.AbstractPersistentDataLayer; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.random.*; import com.gmail.nossr50.util.text.StringUtils; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -334,4 +336,92 @@ public static int getRepairAndSalvageQuantities(Material itemMaterial, Material return quantity; } + + /** + * This is one of several Skill RNG check methods + * This helper method is for specific {@link SubSkillType}, which help mcMMO understand where the RNG values used in our calculations come from from this {@link SubSkillType} + * + * 1) Determine where the RNG values come from for the passed {@link SubSkillType} + * NOTE: In the config file, there are values which are static and which are more dynamic, this is currently a bit hardcoded and will need to be updated manually + * + * 2) Determine whether or not to use Lucky multiplier and influence the outcome + * + * 3) Creates a {@link Probability} and pipes it to {@link RandomChanceUtil} which processes the result and returns it + * + * @param subSkillType target subskill + * @param player target player, can be null (null players are given odds equivalent to a player with no levels or luck) + * @return true if the Skill RNG succeeds, false if it fails + */ + public static boolean isSkillRNGSuccessful(@NotNull SubSkillType subSkillType, @Nullable Player player) { + try { + //Process probability + Probability probability = getSubSkillProbability(subSkillType, player); + //Player can be null + boolean isLucky = player != null && Permissions.lucky(player, subSkillType.getParentSkill()); + + if(isLucky) { + return RandomChanceUtil.processProbability(probability, RandomChanceUtil.LUCKY_MODIFIER); + } else { + return RandomChanceUtil.processProbability(probability); + } + + } catch (RuntimeException | InvalidStaticChance e) { + e.printStackTrace(); + } + + return false; + } + + /** + * This is one of several Skill RNG check methods + * This helper method is specific to static value RNG, which can be influenced by a player's Luck + * + * @param primarySkillType the related primary skill + * @param player the target player, can be null (null players have the worst odds) + * @param probabilityPercentage the probability of this player succeeding in "percentage" format (0-100 inclusive) + * @return true if the RNG succeeds, false if it fails + */ + public static boolean isStaticSkillRNGSuccessful(@NotNull PrimarySkillType primarySkillType, @Nullable Player player, double probabilityPercentage) { + //Grab a probability converted from a "percentage" value + Probability probability = ProbabilityFactory.ofPercentageValue(probabilityPercentage); + + return isStaticSkillRNGSuccessful(primarySkillType, player, probability); + } + + /** + * This is one of several Skill RNG check methods + * This helper method is specific to static value RNG, which can be influenced by a player's Luck + * + * @param primarySkillType the related primary skill + * @param player the target player, can be null (null players have the worst odds) + * @param probability the probability of this player succeeding + * @return true if the RNG succeeds, false if it fails + */ + public static boolean isStaticSkillRNGSuccessful(@NotNull PrimarySkillType primarySkillType, @Nullable Player player, @NotNull Probability probability) { + boolean isLucky = player != null && Permissions.lucky(player, primarySkillType); + + if(isLucky) { + return RandomChanceUtil.processProbability(probability, RandomChanceUtil.LUCKY_MODIFIER); + } else { + return RandomChanceUtil.processProbability(probability); + } + } + + /** + * Grab the {@link Probability} for a specific {@link SubSkillType} for a specific {@link Player} + * + * @param subSkillType target subskill + * @param player target player + * @return the Probability of this skill succeeding + * @throws InvalidStaticChance when a skill that does not have a hard coded static chance and it is asked for + * @throws RuntimeException + */ + public static @NotNull Probability getSubSkillProbability(@NotNull SubSkillType subSkillType, @Nullable Player player) throws InvalidStaticChance, RuntimeException { + SkillProbabilityType skillProbabilityType = SkillProbabilityType.DYNAMIC_CONFIGURABLE; + + if(subSkillType == SubSkillType.TAMING_FAST_FOOD_SERVICE || subSkillType == SubSkillType.AXES_ARMOR_IMPACT || subSkillType == SubSkillType.AXES_GREATER_IMPACT) + skillProbabilityType = SkillProbabilityType.STATIC_CONFIGURABLE; + + return ProbabilityFactory.ofSubSkill(player, subSkillType, skillProbabilityType); + } } diff --git a/src/test/java/com/gmail/nossr50/util/random/RandomChanceTest.java b/src/test/java/com/gmail/nossr50/util/random/RandomChanceTest.java index f28e7e8427..d417635fc4 100644 --- a/src/test/java/com/gmail/nossr50/util/random/RandomChanceTest.java +++ b/src/test/java/com/gmail/nossr50/util/random/RandomChanceTest.java @@ -21,7 +21,7 @@ ////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}) +//@PrepareForTest({RandomChanceUtil.class, UserManager.class, PrimarySkillType.class}) //public class RandomChanceTest { // // private Player luckyPlayer; @@ -37,12 +37,12 @@ // // @Before // public void setUpMock() { -// primarySkillType = PrimarySkillType.HERBALISM; -// subSkillType = SubSkillType.HERBALISM_GREEN_THUMB; +// primarySkillType = PrimarySkillType.MINING; +// subSkillType = SubSkillType.MINING_MOTHER_LODE; // // //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); +// PowerMockito.stub(PowerMockito.method(RandomChanceUtil.class, "getMaximumProbability", subSkillType.getClass())).toReturn(10.0D); +// PowerMockito.stub(PowerMockito.method(RandomChanceUtil.class, "getMaxBonusLevelCap", subSkillType.getClass())).toReturn(10000D); // // normalPlayer = mock(Player.class); // luckyPlayer = mock(Player.class); @@ -62,39 +62,39 @@ // 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); +// Mockito.when(mmoPlayerNormal.getSkillLevel(primarySkillType)).thenReturn(2150); +// Mockito.when(mmoPlayerLucky.getSkillLevel(primarySkillType)).thenReturn(2150); // } // // @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); +// assertEquals(2.15D, getSuccessChance(mmoPlayerNormal),0.00D); +// assertEquals(2.15D * RandomChanceUtil.LUCKY_MODIFIER, getSuccessChance(mmoPlayerLucky),0.00D); // } // -// @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 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 expectedFailRate = 100.0D - 2.15D; // // double win = 0, loss = 0; // for(int x = 0; x < 100000; x++) { -// if(RandomChanceUtil.checkRandomChanceExecutionSuccess(normalPlayer, SubSkillType.HERBALISM_GREEN_THUMB, true)) { +// if(RandomChanceUtil.checkRandomChanceExecutionSuccess(normalPlayer, SubSkillType.MINING_MOTHER_LODE, true)) { // win++; // } else { // loss++; @@ -102,7 +102,7 @@ // } // // double lossRatio = (loss / ratioDivisor); -// Assert.assertEquals(lossRatio, expectedFailRate, 1D); +// Assert.assertEquals(lossRatio, expectedFailRate, 0.01D); // } // // private double getSuccessChance(@NotNull McMMOPlayer mmoPlayer) { From fe889cf1c50e7980263ce92483a8f5506d1ca0db Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 17 Feb 2021 16:32:40 -0800 Subject: [PATCH 11/75] RandomChanceUtil Refactor part 2 --- .../gmail/nossr50/commands/skills/AcrobaticsCommand.java | 4 ++-- .../com/gmail/nossr50/commands/skills/ArcheryCommand.java | 4 ++-- .../com/gmail/nossr50/commands/skills/AxesCommand.java | 2 +- .../gmail/nossr50/commands/skills/HerbalismCommand.java | 8 ++++---- .../com/gmail/nossr50/commands/skills/MiningCommand.java | 4 ++-- .../com/gmail/nossr50/commands/skills/RepairCommand.java | 2 +- .../gmail/nossr50/commands/skills/SmeltingCommand.java | 4 ++-- .../com/gmail/nossr50/commands/skills/SwordsCommand.java | 4 ++-- .../com/gmail/nossr50/commands/skills/TamingCommand.java | 2 +- .../com/gmail/nossr50/commands/skills/UnarmedCommand.java | 6 +++--- .../gmail/nossr50/commands/skills/WoodcuttingCommand.java | 4 ++-- .../datatypes/skills/subskills/acrobatics/Roll.java | 6 +++--- .../java/com/gmail/nossr50/listeners/EntityListener.java | 2 +- .../nossr50/skills/acrobatics/AcrobaticsManager.java | 3 ++- .../com/gmail/nossr50/skills/archery/ArcheryManager.java | 2 +- .../java/com/gmail/nossr50/skills/axes/AxesManager.java | 6 +++--- .../gmail/nossr50/skills/herbalism/HerbalismManager.java | 6 +++--- .../com/gmail/nossr50/skills/repair/RepairManager.java | 2 +- .../gmail/nossr50/skills/smelting/SmeltingManager.java | 2 +- .../com/gmail/nossr50/skills/swords/SwordsManager.java | 4 ++-- .../com/gmail/nossr50/skills/taming/TamingManager.java | 4 ++-- .../com/gmail/nossr50/skills/unarmed/UnarmedManager.java | 6 +++--- .../nossr50/skills/woodcutting/WoodcuttingManager.java | 7 ++++--- 23 files changed, 48 insertions(+), 46 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java index bcb5368b5b..681506aac7 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java @@ -29,7 +29,7 @@ public AcrobaticsCommand() { protected void dataCalculations(Player player, float skillValue) { // ACROBATICS_DODGE if (canDodge) { - String[] dodgeStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.ACROBATICS_DODGE); + String[] dodgeStrings = getAbilityDisplayValues(player, SubSkillType.ACROBATICS_DODGE); dodgeChance = dodgeStrings[0]; dodgeChanceLucky = dodgeStrings[1]; } @@ -70,7 +70,7 @@ protected List statsDisplay(Player player, float skillValue, boolean has graceChance = RandomChanceUtil.getRandomChanceExecutionChance(grace_rcs); //damageThreshold = AdvancedConfig.getInstance().getRollDamageThreshold(); - String[] rollStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.ACROBATICS_ROLL); + String[] rollStrings = getAbilityDisplayValues(player, SubSkillType.ACROBATICS_ROLL); //Format double rollChanceLucky = rollChance * 1.333D; diff --git a/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java index 31500493c0..404c6bb4cd 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java @@ -32,14 +32,14 @@ public ArcheryCommand() { protected void dataCalculations(Player player, float skillValue) { // ARCHERY_ARROW_RETRIEVAL if (canRetrieve) { - String[] retrieveStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.ARCHERY_ARROW_RETRIEVAL); + String[] retrieveStrings = getAbilityDisplayValues(player, SubSkillType.ARCHERY_ARROW_RETRIEVAL); retrieveChance = retrieveStrings[0]; retrieveChanceLucky = retrieveStrings[1]; } // ARCHERY_DAZE if (canDaze) { - String[] dazeStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.ARCHERY_DAZE); + String[] dazeStrings = getAbilityDisplayValues(player, SubSkillType.ARCHERY_DAZE); dazeChance = dazeStrings[0]; dazeChanceLucky = dazeStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java index 1a0e74e18c..5f462790ec 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java @@ -47,7 +47,7 @@ protected void dataCalculations(Player player, float skillValue) { // CRITICAL HIT if (canCritical) { - String[] criticalHitStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.AXES_CRITICAL_STRIKES); + String[] criticalHitStrings = getAbilityDisplayValues(player, SubSkillType.AXES_CRITICAL_STRIKES); critChance = criticalHitStrings[0]; critChanceLucky = criticalHitStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java index 8d8d13b6f7..107e7b2152 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java @@ -44,7 +44,7 @@ protected void dataCalculations(Player player, float skillValue) { // DOUBLE DROPS if (canDoubleDrop) { - String[] doubleDropStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.HERBALISM_DOUBLE_DROPS); + String[] doubleDropStrings = getAbilityDisplayValues(player, SubSkillType.HERBALISM_DOUBLE_DROPS); doubleDropChance = doubleDropStrings[0]; doubleDropChanceLucky = doubleDropStrings[1]; } @@ -65,21 +65,21 @@ protected void dataCalculations(Player player, float skillValue) { if (canGreenThumbBlocks || canGreenThumbPlants) { greenThumbStage = RankUtils.getRank(player, SubSkillType.HERBALISM_GREEN_THUMB); - String[] greenThumbStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.HERBALISM_GREEN_THUMB); + String[] greenThumbStrings = getAbilityDisplayValues(player, SubSkillType.HERBALISM_GREEN_THUMB); greenThumbChance = greenThumbStrings[0]; greenThumbChanceLucky = greenThumbStrings[1]; } // HYLIAN LUCK if (hasHylianLuck) { - String[] hylianLuckStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.HERBALISM_HYLIAN_LUCK); + String[] hylianLuckStrings = getAbilityDisplayValues(player, SubSkillType.HERBALISM_HYLIAN_LUCK); hylianLuckChance = hylianLuckStrings[0]; hylianLuckChanceLucky = hylianLuckStrings[1]; } // SHROOM THUMB if (canShroomThumb) { - String[] shroomThumbStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.HERBALISM_SHROOM_THUMB); + String[] shroomThumbStrings = getAbilityDisplayValues(player, SubSkillType.HERBALISM_SHROOM_THUMB); shroomThumbChance = shroomThumbStrings[0]; shroomThumbChanceLucky = shroomThumbStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java index b94ad33fd4..1d0674988a 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java @@ -56,14 +56,14 @@ protected void dataCalculations(Player player, float skillValue) { // Mastery TRIPLE DROPS if (canMotherLode) { - String[] masteryTripleDropStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.MINING_MOTHER_LODE); + String[] masteryTripleDropStrings = getAbilityDisplayValues(player, SubSkillType.MINING_MOTHER_LODE); tripleDropChance = masteryTripleDropStrings[0]; tripleDropChanceLucky = masteryTripleDropStrings[1]; } // DOUBLE DROPS if (canDoubleDrop) { - String[] doubleDropStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.MINING_DOUBLE_DROPS); + String[] doubleDropStrings = getAbilityDisplayValues(player, SubSkillType.MINING_DOUBLE_DROPS); doubleDropChance = doubleDropStrings[0]; doubleDropChanceLucky = doubleDropStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java index c6687a5c4d..aab831deef 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java @@ -67,7 +67,7 @@ protected void dataCalculations(Player player, float skillValue) { // SUPER REPAIR if (canSuperRepair) { - String[] superRepairStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.REPAIR_SUPER_REPAIR); + String[] superRepairStrings = getAbilityDisplayValues(player, SubSkillType.REPAIR_SUPER_REPAIR); superRepairChance = superRepairStrings[0]; superRepairChanceLucky = superRepairStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java index 3c251b1296..cdeff075e2 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java @@ -38,14 +38,14 @@ protected void dataCalculations(Player player, float skillValue) { // FLUX MINING /*if (canFluxMine) { - String[] fluxMiningStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.SMELTING_FLUX_MINING); + String[] fluxMiningStrings = getAbilityDisplayValues(player, SubSkillType.SMELTING_FLUX_MINING); str_fluxMiningChance = fluxMiningStrings[0]; str_fluxMiningChanceLucky = fluxMiningStrings[1]; }*/ // SECOND SMELT if (canSecondSmelt) { - String[] secondSmeltStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.SMELTING_SECOND_SMELT); + String[] secondSmeltStrings = getAbilityDisplayValues(player, SubSkillType.SMELTING_SECOND_SMELT); str_secondSmeltChance = secondSmeltStrings[0]; str_secondSmeltChanceLucky = secondSmeltStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java index 967cd1a22e..c5cbdaeb2e 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java @@ -36,7 +36,7 @@ public SwordsCommand() { protected void dataCalculations(Player player, float skillValue) { // SWORDS_COUNTER_ATTACK if (canCounter) { - String[] counterStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.SWORDS_COUNTER_ATTACK); + String[] counterStrings = getAbilityDisplayValues(player, SubSkillType.SWORDS_COUNTER_ATTACK); counterChance = counterStrings[0]; counterChanceLucky = counterStrings[1]; } @@ -45,7 +45,7 @@ protected void dataCalculations(Player player, float skillValue) { if (canBleed) { bleedLength = UserManager.getPlayer(player).getSwordsManager().getRuptureBleedTicks(); - String[] bleedStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.SWORDS_RUPTURE); + String[] bleedStrings = getAbilityDisplayValues(player, SubSkillType.SWORDS_RUPTURE); bleedChance = bleedStrings[0]; bleedChanceLucky = bleedStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java index 639de87c14..47a954d80c 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java @@ -34,7 +34,7 @@ public TamingCommand() { @Override protected void dataCalculations(Player player, float skillValue) { if (canGore) { - String[] goreStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.TAMING_GORE); + String[] goreStrings = getAbilityDisplayValues(player, SubSkillType.TAMING_GORE); goreChance = goreStrings[0]; goreChanceLucky = goreStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java index f93e948cb6..5890ae8435 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java @@ -39,7 +39,7 @@ public UnarmedCommand() { protected void dataCalculations(Player player, float skillValue) { // UNARMED_ARROW_DEFLECT if (canDeflect) { - String[] deflectStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.UNARMED_ARROW_DEFLECT); + String[] deflectStrings = getAbilityDisplayValues(player, SubSkillType.UNARMED_ARROW_DEFLECT); deflectChance = deflectStrings[0]; deflectChanceLucky = deflectStrings[1]; } @@ -53,7 +53,7 @@ protected void dataCalculations(Player player, float skillValue) { // UNARMED_DISARM if (canDisarm) { - String[] disarmStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.UNARMED_DISARM); + String[] disarmStrings = getAbilityDisplayValues(player, SubSkillType.UNARMED_DISARM); disarmChance = disarmStrings[0]; disarmChanceLucky = disarmStrings[1]; } @@ -65,7 +65,7 @@ protected void dataCalculations(Player player, float skillValue) { // IRON GRIP if (canIronGrip) { - String[] ironGripStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.UNARMED_IRON_GRIP); + String[] ironGripStrings = getAbilityDisplayValues(player, SubSkillType.UNARMED_IRON_GRIP); ironGripChance = ironGripStrings[0]; ironGripChanceLucky = ironGripStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java index 4b282629cf..5eacbaaca1 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java @@ -42,7 +42,7 @@ protected void dataCalculations(Player player, float skillValue) { //Clean Cuts if(canTripleDrop) { - String[] tripleDropStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.WOODCUTTING_CLEAN_CUTS); + String[] tripleDropStrings = getAbilityDisplayValues(player, SubSkillType.WOODCUTTING_CLEAN_CUTS); tripleDropChance = tripleDropStrings[0]; tripleDropChanceLucky = tripleDropStrings[1]; } @@ -56,7 +56,7 @@ protected void dataCalculations(Player player, float skillValue) { } private void setDoubleDropClassicChanceStrings(Player player) { - String[] doubleDropStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.WOODCUTTING_HARVEST_LUMBER); + String[] doubleDropStrings = getAbilityDisplayValues(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER); doubleDropChance = doubleDropStrings[0]; doubleDropChanceLucky = doubleDropStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java index 4e9fc852a7..1a4be56e6e 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java @@ -124,14 +124,14 @@ public void addStats(TextComponent.Builder componentBuilder, Player player) { float skillValue = playerProfile.getSkillLevel(getPrimarySkill()); boolean isLucky = Permissions.lucky(player, getPrimarySkill()); - String[] rollStrings = RandomChanceUtil.calculateAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.ACROBATICS_ROLL); + String[] rollStrings = RandomChanceUtil.calculateAbilityDisplayValues(player, SubSkillType.ACROBATICS_ROLL); rollChance = rollStrings[0]; rollChanceLucky = rollStrings[1]; /* * Graceful is double the odds of a normal roll */ - String[] gracefulRollStrings = RandomChanceUtil.calculateAbilityDisplayValuesCustom(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.ACROBATICS_ROLL, 2.0D); + String[] gracefulRollStrings = RandomChanceUtil.calculateAbilityDisplayValuesCustom(player, SubSkillType.ACROBATICS_ROLL, 2.0D); gracefulRollChance = gracefulRollStrings[0]; gracefulRollChanceLucky = gracefulRollStrings[1]; @@ -198,7 +198,7 @@ private double rollCheck(Player player, McMMOPlayer mcMMOPlayer, double damage) double modifiedDamage = calculateModifiedRollDamage(damage, AdvancedConfig.getInstance().getRollDamageThreshold()); if (!isFatal(player, modifiedDamage) - && SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.ACROBATICS_ROLL, player)) { + && SkillUtils.isSkillRNGSuccessful(SubSkillType.ACROBATICS_ROLL, player)) { NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Acrobatics.Roll.Text"); SoundManager.sendCategorizedSound(player, player.getLocation(), SoundType.ROLL_ACTIVATED, SoundCategory.PLAYERS); //player.sendMessage(LocaleLoader.getString("Acrobatics.Roll.Text")); diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index e653ceb5a7..423ff0acd7 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -179,7 +179,7 @@ public void onProjectileLaunch(ProjectileLaunchEvent event) { } } - if (SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.ARCHERY_ARROW_RETRIEVAL, player)) { + if (SkillUtils.isSkillRNGSuccessful(SubSkillType.ARCHERY_ARROW_RETRIEVAL, player)) { projectile.setMetadata(mcMMO.trackedArrow, mcMMO.metadataValue); } } diff --git a/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java b/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java index f022d838ac..7b7f7e1000 100644 --- a/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java @@ -86,7 +86,8 @@ public double dodgeCheck(Entity attacker, double damage) { double modifiedDamage = Acrobatics.calculateModifiedDodgeDamage(damage, Acrobatics.dodgeDamageModifier); Player player = getPlayer(); - if (!isFatal(modifiedDamage) && SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.ACROBATICS_DODGE, player)) { + if (!isFatal(modifiedDamage) + && SkillUtils.isSkillRNGSuccessful(SubSkillType.ACROBATICS_DODGE, player)) { ParticleEffectUtils.playDodgeEffect(player); if (mmoPlayer.useChatNotifications()) { diff --git a/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java b/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java index ed03930535..c3d2756b69 100644 --- a/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java +++ b/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java @@ -88,7 +88,7 @@ public void retrieveArrows(LivingEntity target, Projectile projectile) { * @param defender The {@link Player} being affected by the ability */ public double daze(Player defender) { - if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.ARCHERY_DAZE, getPlayer())) { + if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.ARCHERY_DAZE, getPlayer())) { return 0; } diff --git a/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java b/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java index 15c94ee072..73593a362c 100644 --- a/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java +++ b/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java @@ -83,7 +83,7 @@ public double axeMastery() { * @param damage The amount of damage initially dealt by the event */ public double criticalHit(LivingEntity target, double damage) { - if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.AXES_CRITICAL_STRIKES, getPlayer())) { + if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.AXES_CRITICAL_STRIKES, getPlayer())) { return 0; } @@ -119,7 +119,7 @@ public void impactCheck(@NotNull LivingEntity target) { for (ItemStack armor : target.getEquipment().getArmorContents()) { if (armor != null && ItemUtils.isArmor(armor)) { - if (SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.AXES_ARMOR_IMPACT, getPlayer())) { + if (SkillUtils.isSkillRNGSuccessful(SubSkillType.AXES_ARMOR_IMPACT, getPlayer())) { SkillUtils.handleDurabilityChange(armor, durabilityDamage, 1); } } @@ -137,7 +137,7 @@ public double getImpactDurabilityDamage() { */ public double greaterImpact(@NotNull LivingEntity target) { //static chance (3rd param) - if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.AXES_GREATER_IMPACT, getPlayer())) { + if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.AXES_GREATER_IMPACT, getPlayer())) { return 0; } diff --git a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java b/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java index 906d538a4a..0c1d04ae3e 100644 --- a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java +++ b/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java @@ -587,7 +587,7 @@ private boolean checkDoubleDrop(BlockState blockState) * @return true if the ability was successful, false otherwise */ public boolean processGreenThumbBlocks(BlockState blockState) { - if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.HERBALISM_GREEN_THUMB, getPlayer())) { + if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.HERBALISM_GREEN_THUMB, getPlayer())) { NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE_FAILED, "Herbalism.Ability.GTh.Fail"); return false; } @@ -602,7 +602,7 @@ public boolean processGreenThumbBlocks(BlockState blockState) { * @return true if the ability was successful, false otherwise */ public boolean processHylianLuck(BlockState blockState) { - if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.HERBALISM_HYLIAN_LUCK, getPlayer())) { + if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.HERBALISM_HYLIAN_LUCK, getPlayer())) { return false; } @@ -658,7 +658,7 @@ public boolean processShroomThumb(BlockState blockState) { playerInventory.removeItem(new ItemStack(Material.RED_MUSHROOM)); player.updateInventory(); - if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.HERBALISM_SHROOM_THUMB, player)) { + if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.HERBALISM_SHROOM_THUMB, player)) { NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Herbalism.Ability.ShroomThumb.Fail"); return false; } diff --git a/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java b/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java index 527b34ef26..ac244f4743 100644 --- a/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java +++ b/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java @@ -289,7 +289,7 @@ private boolean checkPlayerProcRepair() { if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.REPAIR_SUPER_REPAIR)) return false; - if (SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.REPAIR_SUPER_REPAIR, getPlayer())) { + if (SkillUtils.isSkillRNGSuccessful(SubSkillType.REPAIR_SUPER_REPAIR, getPlayer())) { NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Repair.Skills.FeltEasy"); return true; } diff --git a/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java b/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java index 5f48ea5d8e..5390e23909 100644 --- a/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java @@ -27,7 +27,7 @@ public SmeltingManager(McMMOPlayer mcMMOPlayer) { public boolean isSecondSmeltSuccessful() { return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.SMELTING_SECOND_SMELT) - && SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.SMELTING_SECOND_SMELT, getPlayer()); + && SkillUtils.isSkillRNGSuccessful(SubSkillType.SMELTING_SECOND_SMELT, getPlayer()); } /* diff --git a/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java b/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java index b7716667e9..ed7bb96c61 100644 --- a/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java @@ -61,7 +61,7 @@ public boolean canUseSerratedStrike() { */ public void ruptureCheck(@NotNull LivingEntity target) throws IllegalStateException { if(BleedTimerTask.isBleedOperationAllowed()) { - if (SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.SWORDS_RUPTURE, getPlayer())) { + if (SkillUtils.isSkillRNGSuccessful(SubSkillType.SWORDS_RUPTURE, getPlayer())) { if (target instanceof Player) { Player defender = (Player) target; @@ -128,7 +128,7 @@ public int getRuptureBleedTicks() * @param damage The amount of damage initially dealt by the event */ public void counterAttackChecks(@NotNull LivingEntity attacker, double damage) { - if (SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.SWORDS_COUNTER_ATTACK, getPlayer())) { + if (SkillUtils.isSkillRNGSuccessful(SubSkillType.SWORDS_COUNTER_ATTACK, getPlayer())) { CombatUtils.dealDamage(attacker, damage / Swords.counterAttackModifier, getPlayer()); NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Countered"); diff --git a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java index 2f6c1d86ce..de8b55d368 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java @@ -146,7 +146,7 @@ public void awardTamingXP(@NotNull LivingEntity entity) { * @param damage The damage being absorbed by the wolf */ public void fastFoodService(@NotNull Wolf wolf, double damage) { - if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.TAMING_FAST_FOOD_SERVICE, getPlayer())) { + if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.TAMING_FAST_FOOD_SERVICE, getPlayer())) { return; } @@ -167,7 +167,7 @@ public void fastFoodService(@NotNull Wolf wolf, double damage) { */ public double gore(@NotNull LivingEntity target, double damage) { if(BleedTimerTask.isBleedOperationAllowed()) { - if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.TAMING_GORE, getPlayer())) { + if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.TAMING_GORE, getPlayer())) { return 0; } diff --git a/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java b/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java index b2fe84017c..7975951460 100644 --- a/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java +++ b/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java @@ -103,7 +103,7 @@ public boolean blockCrackerCheck(@NotNull BlockState blockState) { * @param defender The defending player */ public void disarmCheck(@NotNull Player defender) { - if (SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.UNARMED_DISARM, getPlayer()) && !hasIronGrip(defender)) { + if (SkillUtils.isSkillRNGSuccessful(SubSkillType.UNARMED_DISARM, getPlayer()) && !hasIronGrip(defender)) { if (EventUtils.callDisarmEvent(defender).isCancelled()) { return; } @@ -126,7 +126,7 @@ public void disarmCheck(@NotNull Player defender) { * Check for arrow deflection. */ public boolean deflectCheck() { - if (SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.UNARMED_ARROW_DEFLECT, getPlayer())) { + if (SkillUtils.isSkillRNGSuccessful(SubSkillType.UNARMED_ARROW_DEFLECT, getPlayer())) { NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Combat.ArrowDeflect"); return true; } @@ -183,7 +183,7 @@ public double getSteelArmStyleDamage() { private boolean hasIronGrip(@NotNull Player defender) { if (!Misc.isNPCEntityExcludingVillagers(defender) && Permissions.isSubSkillEnabled(defender, SubSkillType.UNARMED_IRON_GRIP) - && SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.UNARMED_IRON_GRIP, defender)) { + && SkillUtils.isSkillRNGSuccessful(SubSkillType.UNARMED_IRON_GRIP, defender)) { NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, "Unarmed.Ability.IronGrip.Defender"); NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Unarmed.Ability.IronGrip.Attacker"); diff --git a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java index d86c0d698c..4b5556b5e7 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java @@ -69,11 +69,11 @@ public boolean canUseTreeFeller(ItemStack heldItem) { } private boolean checkHarvestLumberActivation() { - return SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.WOODCUTTING_HARVEST_LUMBER, getPlayer()); + return SkillUtils.isSkillRNGSuccessful(SubSkillType.WOODCUTTING_HARVEST_LUMBER, getPlayer()); } private boolean checkCleanCutsActivation() { - return SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.WOODCUTTING_CLEAN_CUTS, getPlayer()); + return SkillUtils.isSkillRNGSuccessful(SubSkillType.WOODCUTTING_CLEAN_CUTS, getPlayer()); } /** @@ -327,7 +327,8 @@ private void dropTreeFellerLootFromBlocks(@NotNull Set treeFellerBlo if(RankUtils.hasReachedRank(2, player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) { if(AdvancedConfig.getInstance().isKnockOnWoodXPOrbEnabled()) { - if(RandomChanceUtil.rollDiceSimple(10, 100)) { + //TODO: Test the results of this RNG, should be 10% + if(SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.WOODCUTTING, player, 10)) { int randOrbCount = Math.max(1, Misc.getRandom().nextInt(100)); Misc.spawnExperienceOrb(blockState.getLocation(), randOrbCount); } From e30c7110ebeb01e33842b6321518fee7d8427be0 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 18 Feb 2021 12:48:16 -0800 Subject: [PATCH 12/75] RandomChanceUtil refactor part 3 --- Changelog.txt | 2 ++ .../datatypes/skills/PrimarySkillType.java | 4 ++- .../events/skills/McMMOPlayerSkillEvent.java | 6 ++-- .../secondaryabilities/SubSkillEvent.java | 28 +++++---------- .../skills/archery/ArcheryManager.java | 7 ++-- .../nossr50/skills/axes/AxesManager.java | 12 ++++--- .../skills/unarmed/UnarmedManager.java | 9 +++-- .../com/gmail/nossr50/util/EventUtils.java | 17 +-------- .../nossr50/util/random/ProbabilityImpl.java | 4 +-- .../gmail/nossr50/util/skills/SkillUtils.java | 36 +++++++++++++++++-- 10 files changed, 65 insertions(+), 60 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 96529da12b..0187955869 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,4 +1,6 @@ Version 2.1.175 + (API) 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 + Treasure drop rate from Shake, Fishing, Hylian, and Excavation now benefit from the Luck perk Added a setting to chat.yml to toggle sending party or admin chat messages to console Added a set of "mastery" subskills meant for end game progression Added the mastery subskill 'Mother Lode' to Mining diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java index 8a7df7ac07..d1e9b45a9d 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java @@ -28,6 +28,8 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.entity.Tameable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collections; @@ -215,7 +217,7 @@ public boolean isChildSkill() { } } - public static PrimarySkillType bySecondaryAbility(SubSkillType subSkillType) { + public static @Nullable PrimarySkillType bySecondaryAbility(@NotNull SubSkillType subSkillType) { for (PrimarySkillType type : values()) { if (type.getSkillAbilities().contains(subSkillType)) { return type; diff --git a/src/main/java/com/gmail/nossr50/events/skills/McMMOPlayerSkillEvent.java b/src/main/java/com/gmail/nossr50/events/skills/McMMOPlayerSkillEvent.java index e899ea528b..6238886c0b 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/McMMOPlayerSkillEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/McMMOPlayerSkillEvent.java @@ -11,10 +11,10 @@ * Generic event for mcMMO skill handling. */ public abstract class McMMOPlayerSkillEvent extends PlayerEvent { - protected PrimarySkillType skill; + protected @NotNull PrimarySkillType skill; protected int skillLevel; - protected McMMOPlayerSkillEvent(Player player, PrimarySkillType skill) { + protected McMMOPlayerSkillEvent(@NotNull Player player, @NotNull PrimarySkillType skill) { super(player); this.skill = skill; this.skillLevel = UserManager.getPlayer(player).getSkillLevel(skill); @@ -23,7 +23,7 @@ protected McMMOPlayerSkillEvent(Player player, PrimarySkillType skill) { /** * @return The skill involved in this event */ - public PrimarySkillType getSkill() { + public @NotNull PrimarySkillType getSkill() { return skill; } diff --git a/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java b/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java index ee4fbb873f..88912d7642 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java @@ -1,48 +1,36 @@ package com.gmail.nossr50.events.skills.secondaryabilities; -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; -import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.events.skills.McMMOPlayerSkillEvent; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; +import org.jetbrains.annotations.NotNull; public class SubSkillEvent extends McMMOPlayerSkillEvent implements Cancellable { - private SubSkillType subSkillType; + private final @NotNull SubSkillType subSkillType; private boolean cancelled = false; private double resultModifier = 1.0D; /** - * Only skills using the old system will fire this event * @param player target player * @param subSkillType target subskill - * @Deprecated Skills will be using a new system stemming from the AbstractSubSkill class so make sure you check for both events, this event will be removed eventually. */ - @Deprecated - public SubSkillEvent(Player player, SubSkillType subSkillType) { - super(player, PrimarySkillType.bySecondaryAbility(subSkillType)); + public SubSkillEvent(@NotNull Player player, @NotNull SubSkillType subSkillType) { + super(player, subSkillType.getParentSkill()); this.subSkillType = subSkillType; } /** - * Only skills using the old system will fire this event * @param player target player * @param subSkillType target subskill - * @param resultModifier a value multiplied against the final result of the dice roll, typically between 0-1.0 - * @Deprecated Skills will be using a new system stemming from the AbstractSubSkill class so make sure you check for both events, this event will be removed eventually. + * @param resultModifier a value multiplied against the probability (1.5 would increase probability by 50%) */ - @Deprecated - public SubSkillEvent(Player player, SubSkillType subSkillType, double resultModifier) { - super(player, PrimarySkillType.bySecondaryAbility(subSkillType)); + public SubSkillEvent(@NotNull Player player, @NotNull SubSkillType subSkillType, double resultModifier) { + super(player, subSkillType.getParentSkill()); this.subSkillType = subSkillType; this.resultModifier = resultModifier; } - public SubSkillEvent(Player player, AbstractSubSkill abstractSubSkill) - { - super(player, abstractSubSkill.getPrimarySkill()); - } - public double getResultModifier() { return resultModifier; } @@ -55,7 +43,7 @@ public void setResultModifier(double resultModifier) { * Gets the SubSkillType involved in the event * @return the SubSkillType */ - public SubSkillType getSubSkillType() { + public @NotNull SubSkillType getSubSkillType() { return subSkillType; } diff --git a/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java b/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java index c3d2756b69..e3f9db0afd 100644 --- a/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java +++ b/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java @@ -10,7 +10,6 @@ import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.Location; import org.bukkit.entity.Entity; @@ -116,10 +115,10 @@ public double daze(Player defender) { * @param oldDamage The raw damage value of this arrow before we modify it */ public double skillShot(double oldDamage) { - if (!SkillUtils.isSkillRNGSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.ARCHERY_SKILL_SHOT, getPlayer())) { + if (SkillUtils.isNonRNGSkillActivationSuccessful(SubSkillType.ARCHERY_SKILL_SHOT, getPlayer())) { + return Archery.getSkillShotBonusDamage(getPlayer(), oldDamage); + } else { return oldDamage; } - - return Archery.getSkillShotBonusDamage(getPlayer(), oldDamage); } } diff --git a/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java b/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java index 73593a362c..d654e2fdd9 100644 --- a/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java +++ b/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java @@ -11,8 +11,10 @@ import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; -import com.gmail.nossr50.util.random.SkillProbabilityType; -import com.gmail.nossr50.util.skills.*; +import com.gmail.nossr50.util.skills.CombatUtils; +import com.gmail.nossr50.util.skills.ParticleEffectUtils; +import com.gmail.nossr50.util.skills.RankUtils; +import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.event.entity.EntityDamageEvent.DamageModifier; @@ -69,11 +71,11 @@ public boolean canActivateAbility() { * Handle the effects of the Axe Mastery ability */ public double axeMastery() { - if (!SkillUtils.isSkillRNGSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.AXES_AXE_MASTERY, getPlayer())) { - return 0; + if (SkillUtils.isNonRNGSkillActivationSuccessful(SubSkillType.AXES_AXE_MASTERY, getPlayer())) { + return Axes.getAxeMasteryBonusDamage(getPlayer()); } - return Axes.getAxeMasteryBonusDamage(getPlayer()); + return 0; } /** diff --git a/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java b/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java index 7975951460..744c23a433 100644 --- a/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java +++ b/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java @@ -17,7 +17,6 @@ import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.Material; import org.bukkit.block.BlockState; @@ -72,7 +71,7 @@ public boolean canUseBlockCracker() { } public boolean blockCrackerCheck(@NotNull BlockState blockState) { - if (!SkillUtils.isSkillRNGSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.UNARMED_BLOCK_CRACKER, getPlayer())) { + if (!SkillUtils.isNonRNGSkillActivationSuccessful(SubSkillType.UNARMED_BLOCK_CRACKER, getPlayer())) { return false; } @@ -149,11 +148,11 @@ public double berserkDamage(double damage) { * Handle the effects of the Iron Arm ability */ public double calculateSteelArmStyleDamage() { - if (!SkillUtils.isSkillRNGSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.UNARMED_STEEL_ARM_STYLE, getPlayer())) { - return 0; + if (SkillUtils.isNonRNGSkillActivationSuccessful(SubSkillType.UNARMED_STEEL_ARM_STYLE, getPlayer())) { + return getSteelArmStyleDamage(); } - return getSteelArmStyleDamage(); + return 0; } public double getSteelArmStyleDamage() { diff --git a/src/main/java/com/gmail/nossr50/util/EventUtils.java b/src/main/java/com/gmail/nossr50/util/EventUtils.java index e1f2d1b975..6d95300195 100644 --- a/src/main/java/com/gmail/nossr50/util/EventUtils.java +++ b/src/main/java/com/gmail/nossr50/util/EventUtils.java @@ -9,7 +9,6 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; -import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.events.experience.McMMOPlayerLevelChangeEvent; import com.gmail.nossr50.events.experience.McMMOPlayerLevelDownEvent; import com.gmail.nossr50.events.experience.McMMOPlayerLevelUpEvent; @@ -190,8 +189,7 @@ public static boolean isRealPlayerDamaged(@NotNull EntityDamageEvent entityDamag * @param subSkillType target subskill * @return the event after it has been fired */ - @Deprecated - public static @NotNull SubSkillEvent callSubSkillEvent(Player player, SubSkillType subSkillType) { + public static @NotNull SubSkillEvent callSubSkillEvent(@NotNull Player player, @NotNull SubSkillType subSkillType) { SubSkillEvent event = new SubSkillEvent(player, subSkillType); mcMMO.p.getServer().getPluginManager().callEvent(event); @@ -213,19 +211,6 @@ public static boolean isRealPlayerDamaged(@NotNull EntityDamageEvent entityDamag return event; } - /** - * Calls a new SubSkillEvent for this SubSkill and then returns it - * @param player target player - * @param abstractSubSkill target subskill - * @return the event after it has been fired - */ - public static SubSkillEvent callSubSkillEvent(Player player, AbstractSubSkill abstractSubSkill) { - SubSkillEvent event = new SubSkillEvent(player, abstractSubSkill); - mcMMO.p.getServer().getPluginManager().callEvent(event); - - return event; - } - public static FakePlayerAnimationEvent callFakeArmSwingEvent(Player player) { FakePlayerAnimationEvent event = new FakePlayerAnimationEvent(player); mcMMO.p.getServer().getPluginManager().callEvent(event); diff --git a/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java b/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java index 6401ca7574..e5b4a5cc80 100644 --- a/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java +++ b/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java @@ -13,9 +13,7 @@ public class ProbabilityImpl implements Probability { * @param staticProbability the value to assign to this probability */ public ProbabilityImpl(double staticProbability) throws ValueOutOfBoundsException { - if(staticProbability > 1) { - throw new ValueOutOfBoundsException("Value should never be above 1 for Probability! This suggests a coding mistake, contact the devs!"); - } else if (staticProbability < 0) { + if (staticProbability < 0) { throw new ValueOutOfBoundsException("Value should never be negative for Probability! This suggests a coding mistake, contact the devs!"); } diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java index 13c4049637..799a9c2f84 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java @@ -10,8 +10,10 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; +import com.gmail.nossr50.events.skills.secondaryabilities.SubSkillEvent; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; @@ -348,16 +350,34 @@ public static int getRepairAndSalvageQuantities(Material itemMaterial, Material * * 3) Creates a {@link Probability} and pipes it to {@link RandomChanceUtil} which processes the result and returns it * + * This also calls a {@link SubSkillEvent} which can be cancelled, if it is cancelled this will return false + * The outcome of the probability can also be modified by this event that is called + * * @param subSkillType target subskill * @param player target player, can be null (null players are given odds equivalent to a player with no levels or luck) * @return true if the Skill RNG succeeds, false if it fails */ - public static boolean isSkillRNGSuccessful(@NotNull SubSkillType subSkillType, @Nullable Player player) { + public static boolean isSkillRNGSuccessful(@NotNull SubSkillType subSkillType, @NotNull Player player) { try { //Process probability Probability probability = getSubSkillProbability(subSkillType, player); - //Player can be null - boolean isLucky = player != null && Permissions.lucky(player, subSkillType.getParentSkill()); + + //Send out event + SubSkillEvent subSkillEvent = EventUtils.callSubSkillEvent(player, subSkillType); + + if(subSkillEvent.isCancelled()) { + return false; //Event got cancelled so this doesn't succeed + } + + //Result modifier + double resultModifier = subSkillEvent.getResultModifier(); + + //Mutate probability + if(resultModifier != 1.0D) + probability = ProbabilityFactory.ofPercentageValue(probability.getValue() * resultModifier); + + //Luck + boolean isLucky = Permissions.lucky(player, subSkillType.getParentSkill()); if(isLucky) { return RandomChanceUtil.processProbability(probability, RandomChanceUtil.LUCKY_MODIFIER); @@ -407,6 +427,16 @@ public static boolean isStaticSkillRNGSuccessful(@NotNull PrimarySkillType prima } } + /** + * Skills activate without RNG, this allows other plugins to prevent that activation + * @param subSkillType target subskill + * @param player target player + * @return true if the skill succeeds (wasn't cancelled by any other plugin) + */ + public static boolean isNonRNGSkillActivationSuccessful(@NotNull SubSkillType subSkillType, @NotNull Player player) { + return !EventUtils.callSubSkillEvent(player, subSkillType).isCancelled(); + } + /** * Grab the {@link Probability} for a specific {@link SubSkillType} for a specific {@link Player} * From 6a3671a190123d54a85af8e2aba85009381c22a3 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 18 Feb 2021 16:41:57 -0800 Subject: [PATCH 13/75] RandomChanceUtil refactor part 4 --- .../commands/skills/AcrobaticsCommand.java | 24 +-- .../commands/skills/ArcheryCommand.java | 5 +- .../nossr50/commands/skills/AxesCommand.java | 3 +- .../commands/skills/FishingCommand.java | 7 +- .../commands/skills/HerbalismCommand.java | 9 +- .../commands/skills/MiningCommand.java | 5 +- .../commands/skills/RepairCommand.java | 3 +- .../nossr50/commands/skills/SkillCommand.java | 6 - .../commands/skills/SmeltingCommand.java | 5 +- .../commands/skills/SwordsCommand.java | 5 +- .../commands/skills/TamingCommand.java | 3 +- .../commands/skills/UnarmedCommand.java | 7 +- .../commands/skills/WoodcuttingCommand.java | 5 +- .../skills/subskills/acrobatics/Roll.java | 139 ++++++++++-------- .../SubSkillRandomCheckEvent.java | 88 ++++++----- .../skills/excavation/ExcavationManager.java | 3 +- .../skills/herbalism/HerbalismManager.java | 5 +- .../nossr50/skills/mining/MiningManager.java | 5 +- .../nossr50/skills/repair/RepairManager.java | 5 +- .../skills/salvage/SalvageManager.java | 7 +- .../nossr50/skills/taming/TamingManager.java | 3 +- .../woodcutting/WoodcuttingManager.java | 1 - .../com/gmail/nossr50/util/BlockUtils.java | 6 +- .../util/random/ProbabilityFactory.java | 8 +- .../nossr50/util/random/RandomChanceUtil.java | 34 +++-- .../gmail/nossr50/util/skills/SkillUtils.java | 59 ++++---- 26 files changed, 228 insertions(+), 222 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java index 681506aac7..48e252a03d 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java @@ -6,7 +6,7 @@ import com.gmail.nossr50.listeners.InteractionManager; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.util.Permissions; -import com.gmail.nossr50.util.random.RandomChanceUtil; +import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -29,7 +29,7 @@ public AcrobaticsCommand() { protected void dataCalculations(Player player, float skillValue) { // ACROBATICS_DODGE if (canDodge) { - String[] dodgeStrings = getAbilityDisplayValues(player, SubSkillType.ACROBATICS_DODGE); + String[] dodgeStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.ACROBATICS_DODGE); dodgeChance = dodgeStrings[0]; dodgeChanceLucky = dodgeStrings[1]; } @@ -56,25 +56,7 @@ protected List statsDisplay(Player player, float skillValue, boolean has if(abstractSubSkill != null) { - double rollChance, graceChance; - - //Chance to roll at half - SkillProbabilityWrapper roll_rcs = new SkillProbabilityWrapper(player, SubSkillType.ACROBATICS_ROLL); - - //Chance to graceful roll - SkillProbabilityWrapper grace_rcs = new SkillProbabilityWrapper(player, SubSkillType.ACROBATICS_ROLL); - grace_rcs.setxPos(grace_rcs.getxPos() * 2); //Double Odds - - //Chance Stat Calculations - rollChance = RandomChanceUtil.getRandomChanceExecutionChance(roll_rcs); - graceChance = RandomChanceUtil.getRandomChanceExecutionChance(grace_rcs); - //damageThreshold = AdvancedConfig.getInstance().getRollDamageThreshold(); - - String[] rollStrings = getAbilityDisplayValues(player, SubSkillType.ACROBATICS_ROLL); - - //Format - double rollChanceLucky = rollChance * 1.333D; - double graceChanceLucky = graceChance * 1.333D; + String[] rollStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.ACROBATICS_ROLL); messages.add(getStatMessage(SubSkillType.ACROBATICS_ROLL, rollStrings[0]) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", rollStrings[1]) : "")); diff --git a/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java index 404c6bb4cd..46c2506521 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java @@ -6,6 +6,7 @@ import com.gmail.nossr50.skills.archery.Archery; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.skills.CombatUtils; +import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -32,14 +33,14 @@ public ArcheryCommand() { protected void dataCalculations(Player player, float skillValue) { // ARCHERY_ARROW_RETRIEVAL if (canRetrieve) { - String[] retrieveStrings = getAbilityDisplayValues(player, SubSkillType.ARCHERY_ARROW_RETRIEVAL); + String[] retrieveStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.ARCHERY_ARROW_RETRIEVAL); retrieveChance = retrieveStrings[0]; retrieveChanceLucky = retrieveStrings[1]; } // ARCHERY_DAZE if (canDaze) { - String[] dazeStrings = getAbilityDisplayValues(player, SubSkillType.ARCHERY_DAZE); + String[] dazeStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.ARCHERY_DAZE); dazeChance = dazeStrings[0]; dazeChanceLucky = dazeStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java index 5f462790ec..26cdc5d280 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java @@ -8,6 +8,7 @@ import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; +import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -47,7 +48,7 @@ protected void dataCalculations(Player player, float skillValue) { // CRITICAL HIT if (canCritical) { - String[] criticalHitStrings = getAbilityDisplayValues(player, SubSkillType.AXES_CRITICAL_STRIKES); + String[] criticalHitStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.AXES_CRITICAL_STRIKES); critChance = criticalHitStrings[0]; critChanceLucky = criticalHitStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java index 4d3409a232..3cf6c91173 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java @@ -9,8 +9,10 @@ import com.gmail.nossr50.skills.fishing.FishingManager; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; -import com.gmail.nossr50.util.random.RandomChanceUtil; +import com.gmail.nossr50.util.random.Probability; +import com.gmail.nossr50.util.random.ProbabilityFactory; import com.gmail.nossr50.util.skills.RankUtils; +import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.StringUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; @@ -80,7 +82,8 @@ protected void dataCalculations(Player player, float skillValue) { // FISHING_SHAKE if (canShake) { - String[] shakeStrings = RandomChanceUtil.calculateAbilityDisplayValuesStatic(player, PrimarySkillType.FISHING, fishingManager.getShakeChance()); + Probability shakeProbability = ProbabilityFactory.ofPercentageValue(fishingManager.getShakeChance()); + String[] shakeStrings = SkillUtils.getRNGDisplayValues(shakeProbability); shakeChance = shakeStrings[0]; shakeChanceLucky = shakeStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java index 107e7b2152..4a705db4c2 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java @@ -5,6 +5,7 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.skills.RankUtils; +import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.Material; @@ -44,7 +45,7 @@ protected void dataCalculations(Player player, float skillValue) { // DOUBLE DROPS if (canDoubleDrop) { - String[] doubleDropStrings = getAbilityDisplayValues(player, SubSkillType.HERBALISM_DOUBLE_DROPS); + String[] doubleDropStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.HERBALISM_DOUBLE_DROPS); doubleDropChance = doubleDropStrings[0]; doubleDropChanceLucky = doubleDropStrings[1]; } @@ -65,21 +66,21 @@ protected void dataCalculations(Player player, float skillValue) { if (canGreenThumbBlocks || canGreenThumbPlants) { greenThumbStage = RankUtils.getRank(player, SubSkillType.HERBALISM_GREEN_THUMB); - String[] greenThumbStrings = getAbilityDisplayValues(player, SubSkillType.HERBALISM_GREEN_THUMB); + String[] greenThumbStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.HERBALISM_GREEN_THUMB); greenThumbChance = greenThumbStrings[0]; greenThumbChanceLucky = greenThumbStrings[1]; } // HYLIAN LUCK if (hasHylianLuck) { - String[] hylianLuckStrings = getAbilityDisplayValues(player, SubSkillType.HERBALISM_HYLIAN_LUCK); + String[] hylianLuckStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.HERBALISM_HYLIAN_LUCK); hylianLuckChance = hylianLuckStrings[0]; hylianLuckChanceLucky = hylianLuckStrings[1]; } // SHROOM THUMB if (canShroomThumb) { - String[] shroomThumbStrings = getAbilityDisplayValues(player, SubSkillType.HERBALISM_SHROOM_THUMB); + String[] shroomThumbStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.HERBALISM_SHROOM_THUMB); shroomThumbChance = shroomThumbStrings[0]; shroomThumbChanceLucky = shroomThumbStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java index 1d0674988a..42744d5c91 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java @@ -7,6 +7,7 @@ import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.RankUtils; +import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -56,14 +57,14 @@ protected void dataCalculations(Player player, float skillValue) { // Mastery TRIPLE DROPS if (canMotherLode) { - String[] masteryTripleDropStrings = getAbilityDisplayValues(player, SubSkillType.MINING_MOTHER_LODE); + String[] masteryTripleDropStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.MINING_MOTHER_LODE); tripleDropChance = masteryTripleDropStrings[0]; tripleDropChanceLucky = masteryTripleDropStrings[1]; } // DOUBLE DROPS if (canDoubleDrop) { - String[] doubleDropStrings = getAbilityDisplayValues(player, SubSkillType.MINING_DOUBLE_DROPS); + String[] doubleDropStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.MINING_DOUBLE_DROPS); doubleDropChance = doubleDropStrings[0]; doubleDropChanceLucky = doubleDropStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java index aab831deef..ff81f63687 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java @@ -12,6 +12,7 @@ import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.RankUtils; +import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.Material; @@ -67,7 +68,7 @@ protected void dataCalculations(Player player, float skillValue) { // SUPER REPAIR if (canSuperRepair) { - String[] superRepairStrings = getAbilityDisplayValues(player, SubSkillType.REPAIR_SUPER_REPAIR); + String[] superRepairStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.REPAIR_SUPER_REPAIR); superRepairChance = superRepairStrings[0]; superRepairChanceLucky = superRepairStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java index 48e4faf376..6a40bbdb70 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java @@ -11,10 +11,8 @@ import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; -import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.gmail.nossr50.util.skills.PerksUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.text.StringUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import com.google.common.collect.ImmutableList; @@ -219,10 +217,6 @@ protected int calculateRank(float skillValue, int maxLevel, int rankChangeLevel) return Math.min((int) skillValue, maxLevel) / rankChangeLevel; } - protected static String[] getAbilityDisplayValues(SkillActivationType skillActivationType, Player player, SubSkillType subSkill) { - return RandomChanceUtil.calculateAbilityDisplayValues(skillActivationType, player, subSkill); - } - protected String[] calculateLengthDisplayValues(Player player, float skillValue) { int maxLength = skill.getAbility().getMaxLength(); int abilityLengthVar = AdvancedConfig.getInstance().getAbilityLength(); diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java index cdeff075e2..27b10b7c63 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java @@ -6,6 +6,7 @@ import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.RankUtils; +import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -38,14 +39,14 @@ protected void dataCalculations(Player player, float skillValue) { // FLUX MINING /*if (canFluxMine) { - String[] fluxMiningStrings = getAbilityDisplayValues(player, SubSkillType.SMELTING_FLUX_MINING); + String[] fluxMiningStrings = getRNGDisplayValues(player, SubSkillType.SMELTING_FLUX_MINING); str_fluxMiningChance = fluxMiningStrings[0]; str_fluxMiningChanceLucky = fluxMiningStrings[1]; }*/ // SECOND SMELT if (canSecondSmelt) { - String[] secondSmeltStrings = getAbilityDisplayValues(player, SubSkillType.SMELTING_SECOND_SMELT); + String[] secondSmeltStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.SMELTING_SECOND_SMELT); str_secondSmeltChance = secondSmeltStrings[0]; str_secondSmeltChanceLucky = secondSmeltStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java index c5cbdaeb2e..8dc6ed1c79 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java @@ -8,6 +8,7 @@ import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; +import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -36,7 +37,7 @@ public SwordsCommand() { protected void dataCalculations(Player player, float skillValue) { // SWORDS_COUNTER_ATTACK if (canCounter) { - String[] counterStrings = getAbilityDisplayValues(player, SubSkillType.SWORDS_COUNTER_ATTACK); + String[] counterStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.SWORDS_COUNTER_ATTACK); counterChance = counterStrings[0]; counterChanceLucky = counterStrings[1]; } @@ -45,7 +46,7 @@ protected void dataCalculations(Player player, float skillValue) { if (canBleed) { bleedLength = UserManager.getPlayer(player).getSwordsManager().getRuptureBleedTicks(); - String[] bleedStrings = getAbilityDisplayValues(player, SubSkillType.SWORDS_RUPTURE); + String[] bleedStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.SWORDS_RUPTURE); bleedChance = bleedStrings[0]; bleedChanceLucky = bleedStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java index 47a954d80c..729901f212 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java @@ -5,6 +5,7 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.skills.taming.Taming; import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.EntityType; @@ -34,7 +35,7 @@ public TamingCommand() { @Override protected void dataCalculations(Player player, float skillValue) { if (canGore) { - String[] goreStrings = getAbilityDisplayValues(player, SubSkillType.TAMING_GORE); + String[] goreStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.TAMING_GORE); goreChance = goreStrings[0]; goreChanceLucky = goreStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java index 5890ae8435..1092ff415c 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java @@ -7,6 +7,7 @@ import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; +import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -39,7 +40,7 @@ public UnarmedCommand() { protected void dataCalculations(Player player, float skillValue) { // UNARMED_ARROW_DEFLECT if (canDeflect) { - String[] deflectStrings = getAbilityDisplayValues(player, SubSkillType.UNARMED_ARROW_DEFLECT); + String[] deflectStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.UNARMED_ARROW_DEFLECT); deflectChance = deflectStrings[0]; deflectChanceLucky = deflectStrings[1]; } @@ -53,7 +54,7 @@ protected void dataCalculations(Player player, float skillValue) { // UNARMED_DISARM if (canDisarm) { - String[] disarmStrings = getAbilityDisplayValues(player, SubSkillType.UNARMED_DISARM); + String[] disarmStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.UNARMED_DISARM); disarmChance = disarmStrings[0]; disarmChanceLucky = disarmStrings[1]; } @@ -65,7 +66,7 @@ protected void dataCalculations(Player player, float skillValue) { // IRON GRIP if (canIronGrip) { - String[] ironGripStrings = getAbilityDisplayValues(player, SubSkillType.UNARMED_IRON_GRIP); + String[] ironGripStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.UNARMED_IRON_GRIP); ironGripChance = ironGripStrings[0]; ironGripChanceLucky = ironGripStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java index 5eacbaaca1..f050c03b8f 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java @@ -5,6 +5,7 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.skills.RankUtils; +import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -42,7 +43,7 @@ protected void dataCalculations(Player player, float skillValue) { //Clean Cuts if(canTripleDrop) { - String[] tripleDropStrings = getAbilityDisplayValues(player, SubSkillType.WOODCUTTING_CLEAN_CUTS); + String[] tripleDropStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.WOODCUTTING_CLEAN_CUTS); tripleDropChance = tripleDropStrings[0]; tripleDropChanceLucky = tripleDropStrings[1]; } @@ -56,7 +57,7 @@ protected void dataCalculations(Player player, float skillValue) { } private void setDoubleDropClassicChanceStrings(Player player) { - String[] doubleDropStrings = getAbilityDisplayValues(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER); + String[] doubleDropStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER); doubleDropChance = doubleDropStrings[0]; doubleDropChanceLucky = doubleDropStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java index 1a4be56e6e..c192e6c0bd 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java @@ -6,6 +6,7 @@ import com.gmail.nossr50.datatypes.interactions.NotificationType; 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.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; @@ -14,8 +15,8 @@ import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; -import com.gmail.nossr50.util.random.RandomChanceUtil; -import com.gmail.nossr50.util.random.SkillProbabilityType; +import com.gmail.nossr50.util.random.Probability; +import com.gmail.nossr50.util.random.ProbabilityImpl; import com.gmail.nossr50.util.skills.PerksUtils; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; @@ -32,6 +33,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; import java.util.Locale; @@ -124,14 +126,17 @@ public void addStats(TextComponent.Builder componentBuilder, Player player) { float skillValue = playerProfile.getSkillLevel(getPrimarySkill()); boolean isLucky = Permissions.lucky(player, getPrimarySkill()); - String[] rollStrings = RandomChanceUtil.calculateAbilityDisplayValues(player, SubSkillType.ACROBATICS_ROLL); + String[] rollStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.ACROBATICS_ROLL); rollChance = rollStrings[0]; rollChanceLucky = rollStrings[1]; /* * Graceful is double the odds of a normal roll */ - String[] gracefulRollStrings = RandomChanceUtil.calculateAbilityDisplayValuesCustom(player, SubSkillType.ACROBATICS_ROLL, 2.0D); + //TODO: Yeah I know, ...I'm tired I'll clean it up later + Probability probability = getRollProbability(player); + Probability gracefulProbability = new ProbabilityImpl(probability.getValue() * 2); + String[] gracefulRollStrings = SkillUtils.getRNGDisplayValues(gracefulProbability); gracefulRollChance = gracefulRollStrings[0]; gracefulRollChanceLucky = gracefulRollStrings[1]; @@ -162,6 +167,11 @@ public void addStats(TextComponent.Builder componentBuilder, Player player) { } + @NotNull + private Probability getRollProbability(Player player) { + return SkillUtils.getSubSkillProbability(SubSkillType.ACROBATICS_ROLL, player); + } + @Override public boolean isSuperAbility() { return false; @@ -235,11 +245,12 @@ private int getActivationChance(McMMOPlayer mcMMOPlayer) { private double gracefulRollCheck(Player player, McMMOPlayer mcMMOPlayer, double damage, int skillLevel) { double modifiedDamage = calculateModifiedRollDamage(damage, AdvancedConfig.getInstance().getRollDamageThreshold() * 2); - SkillProbabilityWrapper rcs = new SkillProbabilityWrapper(player, subSkillType); - rcs.setxPos(rcs.getxPos() * 2); //Double the effective odds + double gracefulOdds = SkillUtils.getSubSkillProbability(subSkillType, player).getValue() * 2; + Probability gracefulProbability = new ProbabilityImpl(gracefulOdds); if (!isFatal(player, modifiedDamage) - && RandomChanceUtil.processProbabilityResults(rcs)) + //TODO: Graceful isn't sending out an event + && SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.ACROBATICS, player, gracefulProbability)) { NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Acrobatics.Ability.Proc"); SoundManager.sendCategorizedSound(player, player.getLocation(), SoundType.ROLL_ACTIVATED, SoundCategory.PLAYERS,0.5F); @@ -352,48 +363,49 @@ public void printInfo(Player player) { */ @Override public String getMechanics() { - //Vars passed to locale - //0 = chance to roll at half max level - //1 = chance to roll with grace at half max level - //2 = level where maximum bonus is reached - //3 = additive chance to succeed per level - //4 = damage threshold when rolling - //5 = damage threshold when rolling with grace - //6 = half of level where maximum bonus is reached - /* - Roll: - # ChanceMax: Maximum chance of rolling when on or higher - # MaxBonusLevel: On this level or higher, the roll chance will not go higher than - # DamageThreshold: The max damage a player can negate with a roll - ChanceMax: 100.0 - MaxBonusLevel: 100 - DamageThreshold: 7.0 - */ - double rollChanceHalfMax, graceChanceHalfMax, damageThreshold, chancePerLevel; - - //Chance to roll at half max skill - SkillProbabilityWrapper rollHalfMaxSkill = new SkillProbabilityWrapper(null, subSkillType); - int halfMaxSkillValue = AdvancedConfig.getInstance().getMaxBonusLevel(SubSkillType.ACROBATICS_ROLL)/2; - rollHalfMaxSkill.setxPos(halfMaxSkillValue); - - //Chance to graceful roll at full skill - SkillProbabilityWrapper rollGraceHalfMaxSkill = new SkillProbabilityWrapper(null, subSkillType); - rollGraceHalfMaxSkill.setxPos(halfMaxSkillValue * 2); //Double the effective odds - - //Chance to roll per level - SkillProbabilityWrapper rollOneSkillLevel = new SkillProbabilityWrapper(null, subSkillType); - rollGraceHalfMaxSkill.setxPos(1); //Level 1 skill - - //Chance Stat Calculations - rollChanceHalfMax = RandomChanceUtil.getRandomChanceExecutionChance(rollHalfMaxSkill); - graceChanceHalfMax = RandomChanceUtil.getRandomChanceExecutionChance(rollGraceHalfMaxSkill); - damageThreshold = AdvancedConfig.getInstance().getRollDamageThreshold(); - - chancePerLevel = RandomChanceUtil.getRandomChanceExecutionChance(rollOneSkillLevel); - - double maxLevel = AdvancedConfig.getInstance().getMaxBonusLevel(SubSkillType.ACROBATICS_ROLL); - - return LocaleLoader.getString("Acrobatics.SubSkill.Roll.Mechanics", rollChanceHalfMax, graceChanceHalfMax, maxLevel, chancePerLevel, damageThreshold, damageThreshold * 2,halfMaxSkillValue); + return "This feature is currently not implemented but will be in the future! -mcMMO Devs"; +// //Vars passed to locale +// //0 = chance to roll at half max level +// //1 = chance to roll with grace at half max level +// //2 = level where maximum bonus is reached +// //3 = additive chance to succeed per level +// //4 = damage threshold when rolling +// //5 = damage threshold when rolling with grace +// //6 = half of level where maximum bonus is reached +// /* +// Roll: +// # ChanceMax: Maximum chance of rolling when on or higher +// # MaxBonusLevel: On this level or higher, the roll chance will not go higher than +// # DamageThreshold: The max damage a player can negate with a roll +// ChanceMax: 100.0 +// MaxBonusLevel: 100 +// DamageThreshold: 7.0 +// */ +// double rollChanceHalfMax, graceChanceHalfMax, damageThreshold, chancePerLevel; +// +// //Chance to roll at half max skill +// SkillProbabilityWrapper rollHalfMaxSkill = new SkillProbabilityWrapper(null, subSkillType); +// int halfMaxSkillValue = AdvancedConfig.getInstance().getMaxBonusLevel(SubSkillType.ACROBATICS_ROLL)/2; +// rollHalfMaxSkill.setxPos(halfMaxSkillValue); +// +// //Chance to graceful roll at full skill +// SkillProbabilityWrapper rollGraceHalfMaxSkill = new SkillProbabilityWrapper(null, subSkillType); +// rollGraceHalfMaxSkill.setxPos(halfMaxSkillValue * 2); //Double the effective odds +// +// //Chance to roll per level +// SkillProbabilityWrapper rollOneSkillLevel = new SkillProbabilityWrapper(null, subSkillType); +// rollGraceHalfMaxSkill.setxPos(1); //Level 1 skill +// +// //Chance Stat Calculations +// rollChanceHalfMax = RandomChanceUtil.getRandomChanceExecutionChance(rollHalfMaxSkill); +// graceChanceHalfMax = RandomChanceUtil.getRandomChanceExecutionChance(rollGraceHalfMaxSkill); +// damageThreshold = AdvancedConfig.getInstance().getRollDamageThreshold(); +// +// chancePerLevel = RandomChanceUtil.getRandomChanceExecutionChance(rollOneSkillLevel); +// +// double maxLevel = AdvancedConfig.getInstance().getMaxBonusLevel(SubSkillType.ACROBATICS_ROLL); +// +// return LocaleLoader.getString("Acrobatics.SubSkill.Roll.Mechanics", rollChanceHalfMax, graceChanceHalfMax, maxLevel, chancePerLevel, damageThreshold, damageThreshold * 2,halfMaxSkillValue); } /** @@ -405,26 +417,27 @@ public String getMechanics() { @Override public Double[] getStats(Player player) { - double playerChanceRoll, playerChanceGrace; - - SkillProbabilityWrapper roll = new SkillProbabilityWrapper(player, getSubSkillType()); - SkillProbabilityWrapper graceful = new SkillProbabilityWrapper(player, getSubSkillType()); - - graceful.setxPos(graceful.getxPos() * 2); //Double odds - - //Calculate - playerChanceRoll = RandomChanceUtil.getRandomChanceExecutionChance(roll); - playerChanceGrace = RandomChanceUtil.getRandomChanceExecutionChance(graceful); - - return new Double[]{ playerChanceRoll, playerChanceGrace }; +// double playerChanceRoll, playerChanceGrace; +// +// SkillProbabilityWrapper roll = new SkillProbabilityWrapper(player, getSubSkillType()); +// SkillProbabilityWrapper graceful = new SkillProbabilityWrapper(player, getSubSkillType()); +// +// graceful.setxPos(graceful.getxPos() * 2); //Double odds +// +// //Calculate +// playerChanceRoll = RandomChanceUtil.getRandomChanceExecutionChance(roll); +// playerChanceGrace = RandomChanceUtil.getRandomChanceExecutionChance(graceful); +// +// return new Double[]{ playerChanceRoll, playerChanceGrace }; + return new Double[] {0.0, 0.0}; } - public void addFallLocation(Player player) + public void addFallLocation(@NotNull Player player) { UserManager.getPlayer(player).getAcrobaticsManager().addLocationToFallMap(getBlockLocation(player)); } - public Location getBlockLocation(Player player) + public @NotNull Location getBlockLocation(@NotNull Player player) { return player.getLocation().getBlock().getLocation(); } diff --git a/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillRandomCheckEvent.java b/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillRandomCheckEvent.java index c1a90a425a..3756c6cdd7 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillRandomCheckEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillRandomCheckEvent.java @@ -1,47 +1,41 @@ -package com.gmail.nossr50.events.skills.secondaryabilities; - -import com.gmail.nossr50.datatypes.skills.SubSkillType; -import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; -import org.bukkit.entity.Player; - -public class SubSkillRandomCheckEvent extends SubSkillEvent { - private double chance; - - public SubSkillRandomCheckEvent(Player player, SubSkillType ability, double chance) { - super(player, ability); - this.chance = chance; - } - - public SubSkillRandomCheckEvent(Player player, AbstractSubSkill abstractSubSkill, double chance) - { - super(player, abstractSubSkill); - this.chance = chance; - } - - /** - * Gets the activation chance of the ability 0D being no chance, 100.0D being 100% chance - * - * @return The activation chance of the ability - */ - public double getChance() { - return chance; - } - - /** - * Sets the activation chance of the ability [0D-100.0D] - * - * @param chance The activation chance of the ability - */ - public void setChance(double chance) { - this.chance = chance; - } - - /** - * Sets the activation chance of the ability to 100% or 0% - * - * @param success whether it should be successful or not - */ - public void setSuccessful(boolean success) { - this.chance = success ? 100.0D : 0D; - } -} +//package com.gmail.nossr50.events.skills.secondaryabilities; +// +//import com.gmail.nossr50.datatypes.skills.SubSkillType; +//import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; +//import org.bukkit.entity.Player; +// +//public class SubSkillRandomCheckEvent extends SubSkillEvent { +// private double chance; +// +// public SubSkillRandomCheckEvent(Player player, SubSkillType ability, double chance) { +// super(player, ability); +// this.chance = chance; +// } +// +// /** +// * Gets the activation chance of the ability 0D being no chance, 100.0D being 100% chance +// * +// * @return The activation chance of the ability +// */ +// public double getChance() { +// return chance; +// } +// +// /** +// * Sets the activation chance of the ability [0D-100.0D] +// * +// * @param chance The activation chance of the ability +// */ +// public void setChance(double chance) { +// this.chance = chance; +// } +// +// /** +// * Sets the activation chance of the ability to 100% or 0% +// * +// * @param success whether it should be successful or not +// */ +// public void setSuccessful(boolean success) { +// this.chance = success ? 100.0D : 0D; +// } +//} diff --git a/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java b/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java index 3ed6f5f2a7..00f6f2450b 100644 --- a/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java +++ b/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java @@ -10,7 +10,6 @@ import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; -import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.Location; @@ -44,7 +43,7 @@ public void excavationBlockCheck(BlockState blockState) { && SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.EXCAVATION, getPlayer(), treasure.getDropProbability())) { //Spawn Vanilla XP orbs if a dice roll succeeds - if(RandomChanceUtil.rollDice(getArchaelogyExperienceOrbChance(), 100)) { + if(SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.EXCAVATION, getPlayer(), getArchaelogyExperienceOrbChance())) { Misc.spawnExperienceOrb(location, getExperienceOrbsReward()); } diff --git a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java b/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java index 0c1d04ae3e..476012eade 100644 --- a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java +++ b/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java @@ -21,7 +21,6 @@ import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.*; import com.gmail.nossr50.util.player.NotificationManager; -import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.sounds.SoundManager; @@ -621,7 +620,7 @@ public boolean processHylianLuck(BlockState blockState) { for (HylianTreasure treasure : treasures) { if (skillLevel >= treasure.getDropLevel() - && RandomChanceUtil.processProbabilityResults(new SkillProbabilityWrapperStatic(treasure.getDropChance(), getPlayer(), SubSkillType.HERBALISM_HYLIAN_LUCK))) { + && SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.HERBALISM, player, treasure.getDropChance())) { if (!EventUtils.simulateBlockBreak(blockState.getBlock(), player, false)) { return false; } @@ -740,7 +739,7 @@ private boolean processGreenThumbPlants(BlockState blockState, BlockBreakEvent b return false; } - if (!greenTerra && !RandomChanceUtil.checkRandomChanceExecutionSuccess(player, SubSkillType.HERBALISM_GREEN_THUMB, true)) { + if (!greenTerra && !SkillUtils.isSkillRNGSuccessful(SubSkillType.HERBALISM_GREEN_THUMB, player)) { return false; } diff --git a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java index 186746fadf..2e2c6c0889 100644 --- a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java +++ b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java @@ -15,7 +15,6 @@ import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.*; import com.gmail.nossr50.util.player.NotificationManager; -import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; import org.apache.commons.lang.math.RandomUtils; @@ -114,7 +113,7 @@ public void miningBlockCheck(BlockState blockState) { private boolean processTripleDrops(@NotNull BlockState blockState) { //TODO: Make this readable - if (RandomChanceUtil.checkRandomChanceExecutionSuccess(getPlayer(), SubSkillType.MINING_MOTHER_LODE, true)) { + if (SkillUtils.isSkillRNGSuccessful(SubSkillType.MINING_MOTHER_LODE, getPlayer())) { BlockUtils.markDropsAsBonus(blockState, 2); return true; } else { @@ -124,7 +123,7 @@ private boolean processTripleDrops(@NotNull BlockState blockState) { private void processDoubleDrops(@NotNull BlockState blockState) { //TODO: Make this readable - if (RandomChanceUtil.checkRandomChanceExecutionSuccess(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS, true)) { + if (SkillUtils.isSkillRNGSuccessful(SubSkillType.MINING_DOUBLE_DROPS, getPlayer())) { boolean useTriple = mmoPlayer.getAbilityMode(skill.getAbility()) && AdvancedConfig.getInstance().getAllowMiningTripleDrops(); BlockUtils.markDropsAsBonus(blockState, useTriple); } diff --git a/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java b/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java index ac244f4743..6d355f4fba 100644 --- a/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java +++ b/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java @@ -16,7 +16,6 @@ import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; -import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.sounds.SoundManager; @@ -340,10 +339,10 @@ private void addEnchants(ItemStack item) { Enchantment enchantment = enchant.getKey(); - if (RandomChanceUtil.processProbabilityResults(new SkillProbabilityWrapperStatic(getKeepEnchantChance(), getPlayer(), SubSkillType.REPAIR_ARCANE_FORGING))) { + if (SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.REPAIR, getPlayer(), getKeepEnchantChance())) { if (ArcaneForging.arcaneForgingDowngrades && enchantLevel > 1 - && (!RandomChanceUtil.processProbabilityResults(new SkillProbabilityWrapperStatic(100 - getDowngradeEnchantChance(), getPlayer(), SubSkillType.REPAIR_ARCANE_FORGING)))) { + && (!SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.REPAIR, getPlayer(), 100 - getDowngradeEnchantChance()))) { item.addUnsafeEnchantment(enchantment, enchantLevel - 1); downgraded = true; } diff --git a/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java b/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java index eaa044c989..ef067d83ca 100644 --- a/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java +++ b/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java @@ -16,7 +16,6 @@ import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; -import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.sounds.SoundManager; @@ -122,7 +121,7 @@ public void handleSalvage(Location location, ItemStack item) { for(int x = 0; x < potentialSalvageYield-1; x++) { - if(RandomChanceUtil.rollDiceSimple(chanceOfSuccess, 100)) { + if(SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.SALVAGE, player, chanceOfSuccess)) { chanceOfSuccess-=3; chanceOfSuccess = Math.max(chanceOfSuccess, 90); @@ -252,12 +251,12 @@ private ItemStack arcaneSalvageCheck(Map enchants) { if (!Salvage.arcaneSalvageEnchantLoss || Permissions.hasSalvageEnchantBypassPerk(player) - || RandomChanceUtil.processProbabilityResults(new SkillProbabilityWrapperStatic(getExtractFullEnchantChance(), getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE))) { + || SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.SALVAGE, player, getExtractFullEnchantChance())) { enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel, true); } else if (enchantLevel > 1 && Salvage.arcaneSalvageDowngrades - && RandomChanceUtil.processProbabilityResults(new SkillProbabilityWrapperStatic(getExtractPartialEnchantChance(), getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE))) { + && SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.SALVAGE, player, getExtractPartialEnchantChance())) { enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel - 1, true); downgraded = true; } else { diff --git a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java index de8b55d368..717b407b7b 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java @@ -18,7 +18,6 @@ import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.compat.layers.persistentdata.MobMetaFlagType; import com.gmail.nossr50.util.player.NotificationManager; -import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.ParticleEffectUtils; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; @@ -275,7 +274,7 @@ public void pummel(LivingEntity target, Wolf wolf) { if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_PUMMEL)) return; - if(!RandomChanceUtil.processProbabilityResults(new SkillProbabilityWrapperStatic(AdvancedConfig.getInstance().getPummelChance(), getPlayer(), SubSkillType.TAMING_PUMMEL))) + if(!SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.TAMING, getPlayer(), AdvancedConfig.getInstance().getPummelChance())) return; ParticleEffectUtils.playGreaterImpactEffect(target); diff --git a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java index 4b5556b5e7..df4154859b 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java @@ -14,7 +14,6 @@ import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.*; import com.gmail.nossr50.util.player.NotificationManager; -import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; diff --git a/src/main/java/com/gmail/nossr50/util/BlockUtils.java b/src/main/java/com/gmail/nossr50/util/BlockUtils.java index a951057b59..bf94a04a6b 100644 --- a/src/main/java/com/gmail/nossr50/util/BlockUtils.java +++ b/src/main/java/com/gmail/nossr50/util/BlockUtils.java @@ -8,7 +8,7 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.repair.Repair; import com.gmail.nossr50.skills.salvage.Salvage; -import com.gmail.nossr50.util.random.RandomChanceUtil; +import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockState; @@ -52,9 +52,9 @@ public static void markDropsAsBonus(@NotNull BlockState blockState, int amount) * @param blockState the blockstate * @return true if the player succeeded in the check */ - public static boolean checkDoubleDrops(Player player, BlockState blockState, PrimarySkillType skillType, SubSkillType subSkillType) { + public static boolean checkDoubleDrops(@NotNull Player player, @NotNull BlockState blockState, @NotNull PrimarySkillType skillType, @NotNull SubSkillType subSkillType) { if (Config.getInstance().getDoubleDropsEnabled(skillType, blockState.getType()) && Permissions.isSubSkillEnabled(player, subSkillType)) { - return RandomChanceUtil.processProbabilityResults(new SkillProbabilityWrapper(player, subSkillType, true)); + return SkillUtils.isSkillRNGSuccessful(subSkillType, player); } return false; diff --git a/src/main/java/com/gmail/nossr50/util/random/ProbabilityFactory.java b/src/main/java/com/gmail/nossr50/util/random/ProbabilityFactory.java index f3a7db5b20..9d00ac1698 100644 --- a/src/main/java/com/gmail/nossr50/util/random/ProbabilityFactory.java +++ b/src/main/java/com/gmail/nossr50/util/random/ProbabilityFactory.java @@ -16,7 +16,7 @@ public class ProbabilityFactory { public static @NotNull Probability ofSubSkill(@Nullable Player player, @NotNull SubSkillType subSkillType, - @NotNull SkillProbabilityType skillProbabilityType) throws InvalidStaticChance, RuntimeException { + @NotNull SkillProbabilityType skillProbabilityType) { switch (skillProbabilityType) { case DYNAMIC_CONFIGURABLE: @@ -40,7 +40,11 @@ public class ProbabilityFactory { xCeiling = AdvancedConfig.getInstance().getMaxBonusLevel(subSkillType); return new ProbabilityImpl(xPos, xCeiling, probabilityCeiling); case STATIC_CONFIGURABLE: - return ofPercentageValue(getStaticRandomChance(subSkillType)); + try { + return ofPercentageValue(getStaticRandomChance(subSkillType)); + } catch (InvalidStaticChance invalidStaticChance) { + invalidStaticChance.printStackTrace(); + } default: throw new RuntimeException("No case in switch statement for Skill Probability Type!"); } diff --git a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java index 8641860bec..968dec2227 100644 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java +++ b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java @@ -9,7 +9,6 @@ import java.util.concurrent.ThreadLocalRandom; //TODO: Normalize chance values -//TODO: Test the 2 types of SkillProbabilityTypes //TODO: Update calls to this class and its members public class RandomChanceUtil { public static final @NotNull DecimalFormat percent = new DecimalFormat("##0.00%"); @@ -57,22 +56,29 @@ private static boolean isSuccessfulRoll(double probabilityValue) { * * @return "percentage" representation of success */ - private static double chanceOfSuccessPercentage(@NotNull Player player, @NotNull SubSkillType subSkillType, boolean isLucky) { - try { - Probability probability = SkillUtils.getSubSkillProbability(subSkillType, player); - //Probability values are on a 0-1 scale and need to be "transformed" into a 1-100 scale - double percentageValue = probability.getValue() * 100; + public static double chanceOfSuccessPercentage(@NotNull Player player, @NotNull SubSkillType subSkillType, boolean isLucky) { + Probability probability = SkillUtils.getSubSkillProbability(subSkillType, player); + //Probability values are on a 0-1 scale and need to be "transformed" into a 1-100 scale + double percentageValue = probability.getValue() * 100; - //Apply lucky modifier - if(isLucky) { - percentageValue *= LUCKY_MODIFIER; - } + //Apply lucky modifier + if(isLucky) { + percentageValue *= LUCKY_MODIFIER; + } + + return percentageValue; + } - return percentageValue; - } catch (InvalidStaticChance invalidStaticChance) { - invalidStaticChance.printStackTrace(); - return 0; + public static double chanceOfSuccessPercentage(@NotNull Probability probability, boolean isLucky) { + //Probability values are on a 0-1 scale and need to be "transformed" into a 1-100 scale + double percentageValue = probability.getValue() * 100; + + //Apply lucky modifier + if(isLucky) { + percentageValue *= LUCKY_MODIFIER; } + + return percentageValue; } } diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java index 799a9c2f84..086e4a3018 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java @@ -358,38 +358,31 @@ public static int getRepairAndSalvageQuantities(Material itemMaterial, Material * @return true if the Skill RNG succeeds, false if it fails */ public static boolean isSkillRNGSuccessful(@NotNull SubSkillType subSkillType, @NotNull Player player) { - try { - //Process probability - Probability probability = getSubSkillProbability(subSkillType, player); + //Process probability + Probability probability = getSubSkillProbability(subSkillType, player); - //Send out event - SubSkillEvent subSkillEvent = EventUtils.callSubSkillEvent(player, subSkillType); + //Send out event + SubSkillEvent subSkillEvent = EventUtils.callSubSkillEvent(player, subSkillType); - if(subSkillEvent.isCancelled()) { - return false; //Event got cancelled so this doesn't succeed - } - - //Result modifier - double resultModifier = subSkillEvent.getResultModifier(); + if(subSkillEvent.isCancelled()) { + return false; //Event got cancelled so this doesn't succeed + } - //Mutate probability - if(resultModifier != 1.0D) - probability = ProbabilityFactory.ofPercentageValue(probability.getValue() * resultModifier); + //Result modifier + double resultModifier = subSkillEvent.getResultModifier(); - //Luck - boolean isLucky = Permissions.lucky(player, subSkillType.getParentSkill()); + //Mutate probability + if(resultModifier != 1.0D) + probability = ProbabilityFactory.ofPercentageValue(probability.getValue() * resultModifier); - if(isLucky) { - return RandomChanceUtil.processProbability(probability, RandomChanceUtil.LUCKY_MODIFIER); - } else { - return RandomChanceUtil.processProbability(probability); - } + //Luck + boolean isLucky = Permissions.lucky(player, subSkillType.getParentSkill()); - } catch (RuntimeException | InvalidStaticChance e) { - e.printStackTrace(); + if(isLucky) { + return RandomChanceUtil.processProbability(probability, RandomChanceUtil.LUCKY_MODIFIER); + } else { + return RandomChanceUtil.processProbability(probability); } - - return false; } /** @@ -446,7 +439,7 @@ public static boolean isNonRNGSkillActivationSuccessful(@NotNull SubSkillType su * @throws InvalidStaticChance when a skill that does not have a hard coded static chance and it is asked for * @throws RuntimeException */ - public static @NotNull Probability getSubSkillProbability(@NotNull SubSkillType subSkillType, @Nullable Player player) throws InvalidStaticChance, RuntimeException { + public static @NotNull Probability getSubSkillProbability(@NotNull SubSkillType subSkillType, @Nullable Player player) { SkillProbabilityType skillProbabilityType = SkillProbabilityType.DYNAMIC_CONFIGURABLE; if(subSkillType == SubSkillType.TAMING_FAST_FOOD_SERVICE || subSkillType == SubSkillType.AXES_ARMOR_IMPACT || subSkillType == SubSkillType.AXES_GREATER_IMPACT) @@ -454,4 +447,18 @@ public static boolean isNonRNGSkillActivationSuccessful(@NotNull SubSkillType su return ProbabilityFactory.ofSubSkill(player, subSkillType, skillProbabilityType); } + + public static @NotNull String[] getRNGDisplayValues(@NotNull Player player, @NotNull SubSkillType subSkill) { + double firstValue = RandomChanceUtil.chanceOfSuccessPercentage(player, subSkill, false); + double secondValue = RandomChanceUtil.chanceOfSuccessPercentage(player, subSkill, true); + + return new String[]{RandomChanceUtil.percent.format(firstValue), RandomChanceUtil.percent.format(secondValue)}; + } + + public static @NotNull String[] getRNGDisplayValues(@NotNull Probability probability) { + double firstValue = RandomChanceUtil.chanceOfSuccessPercentage(probability, false); + double secondValue = RandomChanceUtil.chanceOfSuccessPercentage(probability, true); + + return new String[]{RandomChanceUtil.percent.format(firstValue), RandomChanceUtil.percent.format(secondValue)}; + } } From f039b4cbfa023f5569130327036f81cc45a988cb Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 23 Feb 2021 19:22:39 -0800 Subject: [PATCH 14/75] Fix display values for RNG --- .../nossr50/util/random/InvalidActivationException.java | 5 ----- .../java/com/gmail/nossr50/util/random/RandomChanceUtil.java | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) delete mode 100644 src/main/java/com/gmail/nossr50/util/random/InvalidActivationException.java diff --git a/src/main/java/com/gmail/nossr50/util/random/InvalidActivationException.java b/src/main/java/com/gmail/nossr50/util/random/InvalidActivationException.java deleted file mode 100644 index 677d3e63ea..0000000000 --- a/src/main/java/com/gmail/nossr50/util/random/InvalidActivationException.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.gmail.nossr50.util.random; - -public class InvalidActivationException extends Exception { - //Weee -} diff --git a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java index 968dec2227..65b6b19800 100644 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java +++ b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java @@ -59,7 +59,7 @@ private static boolean isSuccessfulRoll(double probabilityValue) { public static double chanceOfSuccessPercentage(@NotNull Player player, @NotNull SubSkillType subSkillType, boolean isLucky) { Probability probability = SkillUtils.getSubSkillProbability(subSkillType, player); //Probability values are on a 0-1 scale and need to be "transformed" into a 1-100 scale - double percentageValue = probability.getValue() * 100; + double percentageValue = probability.getValue(); //Doesn't need to be scaled //Apply lucky modifier if(isLucky) { @@ -71,7 +71,7 @@ public static double chanceOfSuccessPercentage(@NotNull Player player, @NotNull public static double chanceOfSuccessPercentage(@NotNull Probability probability, boolean isLucky) { //Probability values are on a 0-1 scale and need to be "transformed" into a 1-100 scale - double percentageValue = probability.getValue() * 100; + double percentageValue = probability.getValue(); //Apply lucky modifier if(isLucky) { From b077d9e0fbf4402c2d98621b84eb504eb59c7fde Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 4 Dec 2022 17:50:43 -0800 Subject: [PATCH 15/75] Fix compilation errors --- .../commands/skills/PowerLevelCommand.java | 2 +- .../nossr50/commands/skills/SkillCommand.java | 6 +-- .../skills/subskills/acrobatics/Roll.java | 12 ++---- .../nossr50/skills/mining/MiningManager.java | 2 +- .../nossr50/skills/swords/SwordsManager.java | 7 +++- .../nossr50/skills/taming/TamingManager.java | 17 +++------ .../woodcutting/WoodcuttingManager.java | 7 ++-- .../com/gmail/nossr50/util/BlockUtils.java | 37 +++++++++---------- .../gmail/nossr50/util/MobHealthbarUtils.java | 2 +- .../util/random/ProbabilityFactory.java | 11 +++--- .../gmail/nossr50/util/skills/SkillUtils.java | 2 + 11 files changed, 50 insertions(+), 55 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java index 67e725cdc1..425dc1604c 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java @@ -35,7 +35,7 @@ public void processCommand(String[] args) { mmoPlayer.getPlayer().sendMessage("Your power level is: "+powerLevel); //This is not gonna stay, just to show that the command executes in debug //Send the players a few blank lines to make finding the top of the skill command easier - if (AdvancedConfig.getInstance().doesSkillCommandSendBlankLines()) { + if (mcMMO.p.getAdvancedConfig().doesSkillCommandSendBlankLines()) { for (int i = 0; i < 2; i++) { player.sendMessage(""); } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java index df3f8a8a4a..8b20cd6bd0 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java @@ -232,9 +232,9 @@ protected int calculateRank(float skillValue, int maxLevel, int rankChangeLevel) return Math.min((int) skillValue, maxLevel) / rankChangeLevel; } - protected String[] getAbilityDisplayValues(SkillActivationType skillActivationType, Player player, SubSkillType subSkill) { - return RandomChanceUtil.calculateAbilityDisplayValues(skillActivationType, player, subSkill); - } +// protected String[] getAbilityDisplayValues(SkillActivationType skillActivationType, Player player, SubSkillType subSkill) { +// return RandomChanceUtil.calculateAbilityDisplayValues(skillActivationType, player, subSkill); +// } protected String[] calculateLengthDisplayValues(Player player, float skillValue) { int maxLength = mcMMO.p.getSkillTools().getSuperAbilityMaxLength(mcMMO.p.getSkillTools().getSuperAbility(skill)); diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java index 8f485b93be..da8c057d23 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java @@ -422,16 +422,10 @@ public String getMechanics() { @Override public Double[] getStats(Player player) { - double playerChanceRoll, playerChanceGrace; + double playerChanceRoll = SkillUtils.getSubSkillProbability(subSkillType, player).getValue(); + double playerChanceGrace = playerChanceRoll * 2; - RandomChanceSkill roll = new RandomChanceSkill(player, getSubSkillType()); - RandomChanceSkill graceful = new RandomChanceSkill(player, getSubSkillType()); - - graceful.setSkillLevel(graceful.getSkillLevel() * 2); //Double odds - - //Calculate - playerChanceRoll = RandomChanceUtil.getRandomChanceExecutionChance(roll); - playerChanceGrace = RandomChanceUtil.getRandomChanceExecutionChance(graceful); + double gracefulOdds = SkillUtils.getSubSkillProbability(subSkillType, player).getValue() * 2; return new Double[]{ playerChanceRoll, playerChanceGrace }; } diff --git a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java index 9b517097b0..6ad6f958ed 100644 --- a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java +++ b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java @@ -125,7 +125,7 @@ private boolean processTripleDrops(@NotNull BlockState blockState) { private void processDoubleDrops(@NotNull BlockState blockState) { //TODO: Make this readable if (SkillUtils.isSkillRNGSuccessful(SubSkillType.MINING_DOUBLE_DROPS, getPlayer())) { - boolean useTriple = mmoPlayer.getAbilityMode(skill.getAbility()) && AdvancedConfig.getInstance().getAllowMiningTripleDrops(); + boolean useTriple = mmoPlayer.getAbilityMode(SuperAbilityType.SUPER_BREAKER) && mcMMO.p.getAdvancedConfig().getAllowMiningTripleDrops(); BlockUtils.markDropsAsBonus(blockState, useTriple); } } diff --git a/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java b/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java index 5b34fcc34a..d6d5f0e079 100644 --- a/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java @@ -18,6 +18,7 @@ import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillActivationType; +import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; @@ -76,7 +77,8 @@ public void processRupture(@NotNull LivingEntity target) { return; //Don't apply bleed } - if (RandomChanceUtil.rollDice(mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(getRuptureRank()), 100)) { + double ruptureOdds = mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(getRuptureRank()); + if (SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.SWORDS, this.getPlayer(), ruptureOdds)) { if (target instanceof Player defender) { @@ -141,7 +143,8 @@ else if(ItemUtils.isStoneTool(itemStack)) * @param damage The amount of damage initially dealt by the event */ public void counterAttackChecks(@NotNull LivingEntity attacker, double damage) { - if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.SWORDS_COUNTER_ATTACK, getPlayer())) { + + if (SkillUtils.isSkillRNGSuccessful(SubSkillType.SWORDS_COUNTER_ATTACK, getPlayer())) { CombatUtils.dealDamage(attacker, damage / Swords.counterAttackModifier, getPlayer()); NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Countered"); diff --git a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java index d751b4f497..9051360676 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java @@ -262,7 +262,7 @@ public void pummel(LivingEntity target, Wolf wolf) { if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_PUMMEL)) return; - if(!SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.TAMING, getPlayer(), AdvancedConfig.getInstance().getPummelChance())) + if(!SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.TAMING, getPlayer(), mcMMO.p.getAdvancedConfig().getPummelChance())) return; ParticleEffectUtils.playGreaterImpactEffect(target); @@ -372,17 +372,12 @@ private void processCallOfTheWild() { } private void spawnCOTWEntity(CallOfTheWildType callOfTheWildType, Location spawnLocation, EntityType entityType) { - switch(callOfTheWildType) { - case CAT: + switch (callOfTheWildType) { + case CAT -> //Entity type is needed for cats because in 1.13 and below we spawn ocelots, in 1.14 and above we spawn cats - spawnCat(spawnLocation, entityType); - break; - case HORSE: - spawnHorse(spawnLocation); - break; - case WOLF: - spawnWolf(spawnLocation); - break; + spawnCat(spawnLocation, entityType); + case HORSE -> spawnHorse(spawnLocation); + case WOLF -> spawnWolf(spawnLocation); } } diff --git a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java index 197dc4cc9b..c7b27d6114 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java @@ -1,6 +1,7 @@ package com.gmail.nossr50.skills.woodcutting; import com.gmail.nossr50.api.ItemSpawnReason; +import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.interactions.NotificationType; @@ -91,19 +92,19 @@ public void processBonusDropCheck(@NotNull BlockState blockState) { if(Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, blockState.getType())) { //Mastery enabled for player if(Permissions.canUseSubSkill(getPlayer(), SubSkillType.WOODCUTTING_CLEAN_CUTS)) { - if(checkCleanCutsActivation()) { + if(checkCleanCutsActivation(blockState.getType())) { //Triple drops spawnHarvestLumberBonusDrops(blockState); spawnHarvestLumberBonusDrops(blockState); } else { //Harvest Lumber Check - if(checkHarvestLumberActivation()) { + if(checkHarvestLumberActivation(blockState.getType())) { spawnHarvestLumberBonusDrops(blockState); } } //No Mastery (no Clean Cuts) } else if (Permissions.canUseSubSkill(getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER)) { - if(checkHarvestLumberActivation()) { + if(checkHarvestLumberActivation(blockState.getType())) { spawnHarvestLumberBonusDrops(blockState); } } diff --git a/src/main/java/com/gmail/nossr50/util/BlockUtils.java b/src/main/java/com/gmail/nossr50/util/BlockUtils.java index 06b0ef31b7..3e51492ab6 100644 --- a/src/main/java/com/gmail/nossr50/util/BlockUtils.java +++ b/src/main/java/com/gmail/nossr50/util/BlockUtils.java @@ -7,8 +7,7 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.repair.Repair; import com.gmail.nossr50.skills.salvage.Salvage; -import com.gmail.nossr50.util.random.RandomChanceSkill; -import com.gmail.nossr50.util.random.RandomChanceUtil; +import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; @@ -68,7 +67,7 @@ public static void markDropsAsBonus(BlockState blockState, int amount) { */ public static boolean checkDoubleDrops(Player player, BlockState blockState, PrimarySkillType skillType, SubSkillType subSkillType) { if (mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(skillType, blockState.getType()) && Permissions.isSubSkillEnabled(player, subSkillType)) { - return RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkill(player, subSkillType, true)); + return SkillUtils.isSkillRNGSuccessful(subSkillType, player); } return false; @@ -201,22 +200,22 @@ public static boolean isNonWoodPartOfTree(@NotNull Material material) { return mcMMO.getMaterialMapStore().isTreeFellerDestructible(material); } - /** - * Determine if a given block should be affected by Flux Mining - * - * @param blockState The {@link BlockState} of the block to check - * @return true if the block should affected by Flux Mining, false otherwise - */ - public static boolean affectedByFluxMining(BlockState blockState) { - switch (blockState.getType()) { - case IRON_ORE: - case GOLD_ORE: - return true; - - default: - return false; - } - } +// /** +// * Determine if a given block should be affected by Flux Mining +// * +// * @param blockState The {@link BlockState} of the block to check +// * @return true if the block should affected by Flux Mining, false otherwise +// */ +// public static boolean affectedByFluxMining(BlockState blockState) { +// switch (blockState.getType()) { +// case IRON_ORE: +// case GOLD_ORE: +// return true; +// +// default: +// return false; +// } +// } /** * Determine if a given block can activate Herbalism abilities diff --git a/src/main/java/com/gmail/nossr50/util/MobHealthbarUtils.java b/src/main/java/com/gmail/nossr50/util/MobHealthbarUtils.java index 285d889818..2e952e6252 100644 --- a/src/main/java/com/gmail/nossr50/util/MobHealthbarUtils.java +++ b/src/main/java/com/gmail/nossr50/util/MobHealthbarUtils.java @@ -26,7 +26,7 @@ public static String fixDeathMessage(String deathMessage, Player player) { EntityDamageEvent lastDamageCause = player.getLastDamageCause(); String replaceString = lastDamageCause instanceof EntityDamageByEntityEvent ? StringUtils.getPrettyEntityTypeString(((EntityDamageByEntityEvent) lastDamageCause).getDamager().getType()) : "a mob"; - return deathMessage.replaceAll("(?:(\u00A7(?:[0-9A-FK-ORa-fk-or]))*(?:[\u2764\u25A0]{1,10})){1,2}", replaceString); + return deathMessage.replaceAll("(?:(§(?:[0-9A-FK-ORa-fk-or]))*(?:[❤■]{1,10})){1,2}", replaceString); } /** diff --git a/src/main/java/com/gmail/nossr50/util/random/ProbabilityFactory.java b/src/main/java/com/gmail/nossr50/util/random/ProbabilityFactory.java index 9d00ac1698..443a035de4 100644 --- a/src/main/java/com/gmail/nossr50/util/random/ProbabilityFactory.java +++ b/src/main/java/com/gmail/nossr50/util/random/ProbabilityFactory.java @@ -3,6 +3,7 @@ import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -35,9 +36,9 @@ public class ProbabilityFactory { } //Probability ceiling is configurable in this type - probabilityCeiling = AdvancedConfig.getInstance().getMaximumProbability(subSkillType); + probabilityCeiling = mcMMO.p.getAdvancedConfig().getMaximumProbability(subSkillType); //The xCeiling is configurable in this type - xCeiling = AdvancedConfig.getInstance().getMaxBonusLevel(subSkillType); + xCeiling = mcMMO.p.getAdvancedConfig().getMaxBonusLevel(subSkillType); return new ProbabilityImpl(xPos, xCeiling, probabilityCeiling); case STATIC_CONFIGURABLE: try { @@ -69,11 +70,11 @@ public static double probabilityFromPercent(double percentage) { private static double getStaticRandomChance(@NotNull SubSkillType subSkillType) throws InvalidStaticChance { switch (subSkillType) { case AXES_ARMOR_IMPACT: - return AdvancedConfig.getInstance().getImpactChance(); + return mcMMO.p.getAdvancedConfig().getImpactChance(); case AXES_GREATER_IMPACT: - return AdvancedConfig.getInstance().getGreaterImpactChance(); + return mcMMO.p.getAdvancedConfig().getGreaterImpactChance(); case TAMING_FAST_FOOD_SERVICE: - return AdvancedConfig.getInstance().getFastFoodChance(); + return mcMMO.p.getAdvancedConfig().getFastFoodChance(); default: throw new InvalidStaticChance(); } diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java index a557314449..1ef607b3a9 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java @@ -12,8 +12,10 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.metadata.ItemMetadataService; +import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.random.*; From 05c86f1125d157894a3e899022e772d9f824d07b Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 11 Dec 2022 15:38:04 -0800 Subject: [PATCH 16/75] Add some unit tests for new RNG dice rolls --- pom.xml | 2 +- .../nossr50/util/random/RandomChanceUtil.java | 10 +-- .../nossr50/util/random/RandomChanceTest.java | 22 +----- .../util/random/RandomChanceUtilTest.java | 76 +++++++++++++++++++ 4 files changed, 85 insertions(+), 25 deletions(-) create mode 100644 src/test/java/com/gmail/nossr50/util/random/RandomChanceUtilTest.java diff --git a/pom.xml b/pom.xml index 1b70bbae78..7a832016e3 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.218 + 2.2.000-BETA-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java index 65b6b19800..f47e4e8acd 100644 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java +++ b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java @@ -4,12 +4,11 @@ import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.VisibleForTesting; import java.text.DecimalFormat; import java.util.concurrent.ThreadLocalRandom; -//TODO: Normalize chance values -//TODO: Update calls to this class and its members public class RandomChanceUtil { public static final @NotNull DecimalFormat percent = new DecimalFormat("##0.00%"); public static final double LUCKY_MODIFIER = 1.333D; @@ -43,8 +42,9 @@ public static boolean processProbability(@NotNull Probability probability, doubl * @param probabilityValue probability value * @return true for succeeding, false for failing */ - private static boolean isSuccessfulRoll(double probabilityValue) { - return probabilityValue >= ThreadLocalRandom.current().nextDouble(1.0D); + @VisibleForTesting + static boolean isSuccessfulRoll(double probabilityValue) { + return probabilityValue >= ThreadLocalRandom.current().nextDouble(100D); } /** @@ -52,7 +52,7 @@ private static boolean isSuccessfulRoll(double probabilityValue) { * * @param player target player * @param subSkillType target subskill - * @param isLucky whether or not to apply luck modifiers + * @param isLucky whether to apply luck modifiers * * @return "percentage" representation of success */ diff --git a/src/test/java/com/gmail/nossr50/util/random/RandomChanceTest.java b/src/test/java/com/gmail/nossr50/util/random/RandomChanceTest.java index d417635fc4..982acdc6be 100644 --- a/src/test/java/com/gmail/nossr50/util/random/RandomChanceTest.java +++ b/src/test/java/com/gmail/nossr50/util/random/RandomChanceTest.java @@ -85,25 +85,9 @@ //// } //// } // -// @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 = 100.0D - 2.15D; -// -// double win = 0, loss = 0; -// for(int x = 0; x < 100000; x++) { -// if(RandomChanceUtil.checkRandomChanceExecutionSuccess(normalPlayer, SubSkillType.MINING_MOTHER_LODE, true)) { -// win++; -// } else { -// loss++; -// } -// } -// -// double lossRatio = (loss / ratioDivisor); -// Assert.assertEquals(lossRatio, expectedFailRate, 0.01D); -// } +// +// +// // // private double getSuccessChance(@NotNull McMMOPlayer mmoPlayer) { // RandomChanceSkill randomChanceSkill = new RandomChanceSkill(mmoPlayer.getPlayer(), subSkillType, true); diff --git a/src/test/java/com/gmail/nossr50/util/random/RandomChanceUtilTest.java b/src/test/java/com/gmail/nossr50/util/random/RandomChanceUtilTest.java new file mode 100644 index 0000000000..c08770bfaf --- /dev/null +++ b/src/test/java/com/gmail/nossr50/util/random/RandomChanceUtilTest.java @@ -0,0 +1,76 @@ +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 com.gmail.nossr50.util.random.RandomChanceUtil.processProbability; +import static org.junit.jupiter.api.Assertions.*; + +class RandomChanceUtilTest { + + private static Stream 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) + ); + } + @Test + void testIsSuccessfulRollSucceeds() { + Probability probability = new ProbabilityImpl(100); + + for (int i = 0; i < 100000; i++) { + assertTrue(processProbability(probability)); + } + } + + @Test + void testIsSuccessfulRollFails() { + Probability probability = new ProbabilityImpl(0); + + for (int i = 0; i < 100000; i++) { + assertFalse(processProbability(probability)); + } + } + + @ParameterizedTest + @MethodSource("provideProbabilitiesForWithinExpectations") + void testProcessProbabilityWithinExpectations(Probability probability, double expectedWinPercent) { + // Probabilities are tested 200,000,000 times with a margin of error of 0.01% + int iterations = 200000000; + double winCount = 0; + + for (int i = 0; i < iterations; i++) { + if(processProbability(probability)) { + winCount++; + } + } + + double successPercent = (winCount / iterations) * 100; + System.out.println(successPercent + ", " + expectedWinPercent); + assertEquals(expectedWinPercent, successPercent, 0.01D); + } + + @Test + void chanceOfSuccessPercentage() { + } + + @Test + void testChanceOfSuccessPercentage() { + } +} \ No newline at end of file From 11cf882830c8e9c47bce0ee712c6b5506c64df9c Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 18 Dec 2022 15:04:59 -0800 Subject: [PATCH 17/75] Probability factory should live within the interface --- .../commands/skills/FishingCommand.java | 3 +- .../skills/subskills/acrobatics/Roll.java | 5 +- .../nossr50/datatypes/treasure/Treasure.java | 6 +- .../nossr50/util/random/Probability.java | 57 +++++++++++++ .../util/random/ProbabilityFactory.java | 82 ------------------- .../nossr50/util/random/ProbabilityImpl.java | 2 +- .../gmail/nossr50/util/skills/SkillUtils.java | 6 +- ...lTest.java => ProbabilityFactoryTest.java} | 15 +++- .../nossr50/util/random/ProbabilityTest.java | 24 ++++++ 9 files changed, 102 insertions(+), 98 deletions(-) delete mode 100644 src/main/java/com/gmail/nossr50/util/random/ProbabilityFactory.java rename src/test/java/com/gmail/nossr50/util/random/{RandomChanceUtilTest.java => ProbabilityFactoryTest.java} (88%) create mode 100644 src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java diff --git a/src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java index 3cf6c91173..95614ffe66 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java @@ -10,7 +10,6 @@ import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.random.Probability; -import com.gmail.nossr50.util.random.ProbabilityFactory; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.StringUtils; @@ -82,7 +81,7 @@ protected void dataCalculations(Player player, float skillValue) { // FISHING_SHAKE if (canShake) { - Probability shakeProbability = ProbabilityFactory.ofPercentageValue(fishingManager.getShakeChance()); + Probability shakeProbability = Probability.ofPercentageValue(fishingManager.getShakeChance()); String[] shakeStrings = SkillUtils.getRNGDisplayValues(shakeProbability); shakeChance = shakeStrings[0]; shakeChanceLucky = shakeStrings[1]; diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java index da8c057d23..eb165ebb03 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java @@ -136,9 +136,8 @@ public void addStats(TextComponent.Builder componentBuilder, Player player) { /* * Graceful is double the odds of a normal roll */ - //TODO: Yeah I know, ...I'm tired I'll clean it up later Probability probability = getRollProbability(player); - Probability gracefulProbability = new ProbabilityImpl(probability.getValue() * 2); + Probability gracefulProbability = Probability.ofPercentageValue(probability.getValue() * 2); String[] gracefulRollStrings = SkillUtils.getRNGDisplayValues(gracefulProbability); gracefulRollChance = gracefulRollStrings[0]; gracefulRollChanceLucky = gracefulRollStrings[1]; @@ -249,7 +248,7 @@ private double gracefulRollCheck(Player player, McMMOPlayer mcMMOPlayer, double double modifiedDamage = calculateModifiedRollDamage(damage, mcMMO.p.getAdvancedConfig().getRollDamageThreshold() * 2); double gracefulOdds = SkillUtils.getSubSkillProbability(subSkillType, player).getValue() * 2; - Probability gracefulProbability = new ProbabilityImpl(gracefulOdds); + Probability gracefulProbability = Probability.ofPercentageValue(gracefulOdds); if (!isFatal(player, modifiedDamage) //TODO: Graceful isn't sending out an event diff --git a/src/main/java/com/gmail/nossr50/datatypes/treasure/Treasure.java b/src/main/java/com/gmail/nossr50/datatypes/treasure/Treasure.java index 9a8a05521c..16d4ac20a5 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/treasure/Treasure.java +++ b/src/main/java/com/gmail/nossr50/datatypes/treasure/Treasure.java @@ -1,8 +1,6 @@ package com.gmail.nossr50.datatypes.treasure; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.util.random.Probability; -import com.gmail.nossr50.util.random.ProbabilityFactory; import com.gmail.nossr50.util.random.ProbabilityImpl; import com.google.common.base.Objects; import org.bukkit.inventory.ItemStack; @@ -19,7 +17,7 @@ public Treasure(ItemStack drop, int xp, double dropChance, int dropLevel) { this.drop = drop; this.xp = xp; this.dropChance = dropChance; - this.dropProbability = new ProbabilityImpl(ProbabilityFactory.probabilityFromPercent(dropChance)); + this.dropProbability = Probability.ofPercentageValue(dropChance / 100); this.dropLevel = dropLevel; } @@ -49,7 +47,7 @@ public double getDropChance() { public void setDropChance(double dropChance) { this.dropChance = dropChance; - this.dropProbability = new ProbabilityImpl(ProbabilityFactory.probabilityFromPercent(dropChance)); + this.dropProbability = Probability.ofPercentageValue(dropChance / 100); } public int getDropLevel() { diff --git a/src/main/java/com/gmail/nossr50/util/random/Probability.java b/src/main/java/com/gmail/nossr50/util/random/Probability.java index 0e939bc8be..d2b16fd5f0 100644 --- a/src/main/java/com/gmail/nossr50/util/random/Probability.java +++ b/src/main/java/com/gmail/nossr50/util/random/Probability.java @@ -1,5 +1,13 @@ package com.gmail.nossr50.util.random; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.player.UserManager; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + public interface Probability { /** * The value of this Probability @@ -11,4 +19,53 @@ public interface Probability { * @return the value of probability */ double getValue(); + + static @NotNull Probability ofSubSkill(@Nullable Player player, + @NotNull SubSkillType subSkillType, + @NotNull SkillProbabilityType skillProbabilityType) { + + switch (skillProbabilityType) { + case DYNAMIC_CONFIGURABLE: + double probabilityCeiling; + double xCeiling; + double xPos; + + if (player != null) { + McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + if(mmoPlayer != null) + xPos = mmoPlayer.getSkillLevel(subSkillType.getParentSkill()); + else + xPos = 0; + } else { + xPos = 0; + } + + //Probability ceiling is configurable in this type + probabilityCeiling = mcMMO.p.getAdvancedConfig().getMaximumProbability(subSkillType); + //The xCeiling is configurable in this type + xCeiling = mcMMO.p.getAdvancedConfig().getMaxBonusLevel(subSkillType); + return new ProbabilityImpl(xPos, xCeiling, probabilityCeiling); + case STATIC_CONFIGURABLE: + try { + return ofPercentageValue(getStaticRandomChance(subSkillType)); + } catch (InvalidStaticChance invalidStaticChance) { + invalidStaticChance.printStackTrace(); + } + default: + throw new RuntimeException("No case in switch statement for Skill Probability Type!"); + } + } + + static @NotNull Probability ofPercentageValue(double percentageValue) { + return new ProbabilityImpl(percentageValue / 100); + } + + static double getStaticRandomChance(@NotNull SubSkillType subSkillType) throws InvalidStaticChance { + return switch (subSkillType) { + case AXES_ARMOR_IMPACT -> mcMMO.p.getAdvancedConfig().getImpactChance(); + case AXES_GREATER_IMPACT -> mcMMO.p.getAdvancedConfig().getGreaterImpactChance(); + case TAMING_FAST_FOOD_SERVICE -> mcMMO.p.getAdvancedConfig().getFastFoodChance(); + default -> throw new InvalidStaticChance(); + }; + } } diff --git a/src/main/java/com/gmail/nossr50/util/random/ProbabilityFactory.java b/src/main/java/com/gmail/nossr50/util/random/ProbabilityFactory.java deleted file mode 100644 index 443a035de4..0000000000 --- a/src/main/java/com/gmail/nossr50/util/random/ProbabilityFactory.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.gmail.nossr50.util.random; - -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.datatypes.player.McMMOPlayer; -import com.gmail.nossr50.datatypes.skills.SubSkillType; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.player.UserManager; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class ProbabilityFactory { - - public static @NotNull Probability ofPercentageValue(double percentageValue) { - return new ProbabilityImpl(probabilityFromPercent(percentageValue)); - } - - public static @NotNull Probability ofSubSkill(@Nullable Player player, - @NotNull SubSkillType subSkillType, - @NotNull SkillProbabilityType skillProbabilityType) { - - switch (skillProbabilityType) { - case DYNAMIC_CONFIGURABLE: - double probabilityCeiling; - double xCeiling; - double xPos; - - if (player != null) { - McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - if(mmoPlayer != null) - xPos = mmoPlayer.getSkillLevel(subSkillType.getParentSkill()); - else - xPos = 0; - } else { - xPos = 0; - } - - //Probability ceiling is configurable in this type - probabilityCeiling = mcMMO.p.getAdvancedConfig().getMaximumProbability(subSkillType); - //The xCeiling is configurable in this type - xCeiling = mcMMO.p.getAdvancedConfig().getMaxBonusLevel(subSkillType); - return new ProbabilityImpl(xPos, xCeiling, probabilityCeiling); - case STATIC_CONFIGURABLE: - try { - return ofPercentageValue(getStaticRandomChance(subSkillType)); - } catch (InvalidStaticChance invalidStaticChance) { - invalidStaticChance.printStackTrace(); - } - default: - throw new RuntimeException("No case in switch statement for Skill Probability Type!"); - } - } - - /** - * Convert a probability from a percentage - * @param percentage value to convert - * @return 0 -> 1 inclusive representation of probability - */ - public static double probabilityFromPercent(double percentage) { - return percentage / 100; - } - - /** - * Grabs static activation rolls for Secondary Abilities - * - * @param subSkillType The secondary ability to grab properties of - * @return The static activation roll involved in the RNG calculation - * @throws InvalidStaticChance if the skill has no defined static chance this exception will be thrown and you should know you're a naughty boy - */ - private static double getStaticRandomChance(@NotNull SubSkillType subSkillType) throws InvalidStaticChance { - switch (subSkillType) { - case AXES_ARMOR_IMPACT: - return mcMMO.p.getAdvancedConfig().getImpactChance(); - case AXES_GREATER_IMPACT: - return mcMMO.p.getAdvancedConfig().getGreaterImpactChance(); - case TAMING_FAST_FOOD_SERVICE: - return mcMMO.p.getAdvancedConfig().getFastFoodChance(); - default: - throw new InvalidStaticChance(); - } - } -} diff --git a/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java b/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java index e5b4a5cc80..09b46fefc0 100644 --- a/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java +++ b/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java @@ -12,7 +12,7 @@ public class ProbabilityImpl implements Probability { * * @param staticProbability the value to assign to this probability */ - public ProbabilityImpl(double staticProbability) throws ValueOutOfBoundsException { + ProbabilityImpl(double staticProbability) throws ValueOutOfBoundsException { if (staticProbability < 0) { throw new ValueOutOfBoundsException("Value should never be negative for Probability! This suggests a coding mistake, contact the devs!"); } diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java index 1ef607b3a9..9108e3e9c1 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java @@ -391,7 +391,7 @@ public static boolean isSkillRNGSuccessful(@NotNull SubSkillType subSkillType, @ //Mutate probability if(resultModifier != 1.0D) - probability = ProbabilityFactory.ofPercentageValue(probability.getValue() * resultModifier); + probability = Probability.ofPercentageValue(probability.getValue() * resultModifier); //Luck boolean isLucky = Permissions.lucky(player, subSkillType.getParentSkill()); @@ -414,7 +414,7 @@ public static boolean isSkillRNGSuccessful(@NotNull SubSkillType subSkillType, @ */ public static boolean isStaticSkillRNGSuccessful(@NotNull PrimarySkillType primarySkillType, @Nullable Player player, double probabilityPercentage) { //Grab a probability converted from a "percentage" value - Probability probability = ProbabilityFactory.ofPercentageValue(probabilityPercentage); + Probability probability = Probability.ofPercentageValue(probabilityPercentage); return isStaticSkillRNGSuccessful(primarySkillType, player, probability); } @@ -463,7 +463,7 @@ public static boolean isNonRNGSkillActivationSuccessful(@NotNull SubSkillType su if(subSkillType == SubSkillType.TAMING_FAST_FOOD_SERVICE || subSkillType == SubSkillType.AXES_ARMOR_IMPACT || subSkillType == SubSkillType.AXES_GREATER_IMPACT) skillProbabilityType = SkillProbabilityType.STATIC_CONFIGURABLE; - return ProbabilityFactory.ofSubSkill(player, subSkillType, skillProbabilityType); + return Probability.ofSubSkill(player, subSkillType, skillProbabilityType); } public static @NotNull String[] getRNGDisplayValues(@NotNull Player player, @NotNull SubSkillType subSkill) { diff --git a/src/test/java/com/gmail/nossr50/util/random/RandomChanceUtilTest.java b/src/test/java/com/gmail/nossr50/util/random/ProbabilityFactoryTest.java similarity index 88% rename from src/test/java/com/gmail/nossr50/util/random/RandomChanceUtilTest.java rename to src/test/java/com/gmail/nossr50/util/random/ProbabilityFactoryTest.java index c08770bfaf..e833955169 100644 --- a/src/test/java/com/gmail/nossr50/util/random/RandomChanceUtilTest.java +++ b/src/test/java/com/gmail/nossr50/util/random/ProbabilityFactoryTest.java @@ -10,7 +10,7 @@ import static com.gmail.nossr50.util.random.RandomChanceUtil.processProbability; import static org.junit.jupiter.api.Assertions.*; -class RandomChanceUtilTest { +class ProbabilityFactoryTest { private static Stream provideProbabilitiesForWithinExpectations() { return Stream.of( @@ -48,6 +48,15 @@ void testIsSuccessfulRollFails() { } } + @Test + void testIsSuccessfulRollFailsOfPercentage() { + Probability probability = Probability.ofPercentageValue(100); + + for (int i = 0; i < 100000; i++) { + assertFalse(processProbability(probability)); + } + } + @ParameterizedTest @MethodSource("provideProbabilitiesForWithinExpectations") void testProcessProbabilityWithinExpectations(Probability probability, double expectedWinPercent) { @@ -67,10 +76,10 @@ void testProcessProbabilityWithinExpectations(Probability probability, double ex } @Test - void chanceOfSuccessPercentage() { + void ofPercentageValue() { } @Test - void testChanceOfSuccessPercentage() { + void ofSubSkill() { } } \ No newline at end of file diff --git a/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java b/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java new file mode 100644 index 0000000000..da3b6ee565 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java @@ -0,0 +1,24 @@ +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 com.gmail.nossr50.util.random.RandomChanceUtil.processProbability; +import static org.junit.jupiter.api.Assertions.*; + +class ProbabilityTest { + + + + @Test + void chanceOfSuccessPercentage() { + } + + @Test + void testChanceOfSuccessPercentage() { + } +} \ No newline at end of file From 7f66d2714120f39329b4320deb59b129231b4360 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 18 Dec 2022 15:06:44 -0800 Subject: [PATCH 18/75] Rename test --- .../util/random/ProbabilityFactoryTest.java | 85 ------------------- .../nossr50/util/random/ProbabilityTest.java | 65 +++++++++++++- 2 files changed, 63 insertions(+), 87 deletions(-) delete mode 100644 src/test/java/com/gmail/nossr50/util/random/ProbabilityFactoryTest.java diff --git a/src/test/java/com/gmail/nossr50/util/random/ProbabilityFactoryTest.java b/src/test/java/com/gmail/nossr50/util/random/ProbabilityFactoryTest.java deleted file mode 100644 index e833955169..0000000000 --- a/src/test/java/com/gmail/nossr50/util/random/ProbabilityFactoryTest.java +++ /dev/null @@ -1,85 +0,0 @@ -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 com.gmail.nossr50.util.random.RandomChanceUtil.processProbability; -import static org.junit.jupiter.api.Assertions.*; - -class ProbabilityFactoryTest { - - private static Stream 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) - ); - } - @Test - void testIsSuccessfulRollSucceeds() { - Probability probability = new ProbabilityImpl(100); - - for (int i = 0; i < 100000; i++) { - assertTrue(processProbability(probability)); - } - } - - @Test - void testIsSuccessfulRollFails() { - Probability probability = new ProbabilityImpl(0); - - for (int i = 0; i < 100000; i++) { - assertFalse(processProbability(probability)); - } - } - - @Test - void testIsSuccessfulRollFailsOfPercentage() { - Probability probability = Probability.ofPercentageValue(100); - - for (int i = 0; i < 100000; i++) { - assertFalse(processProbability(probability)); - } - } - - @ParameterizedTest - @MethodSource("provideProbabilitiesForWithinExpectations") - void testProcessProbabilityWithinExpectations(Probability probability, double expectedWinPercent) { - // Probabilities are tested 200,000,000 times with a margin of error of 0.01% - int iterations = 200000000; - double winCount = 0; - - for (int i = 0; i < iterations; i++) { - if(processProbability(probability)) { - winCount++; - } - } - - double successPercent = (winCount / iterations) * 100; - System.out.println(successPercent + ", " + expectedWinPercent); - assertEquals(expectedWinPercent, successPercent, 0.01D); - } - - @Test - void ofPercentageValue() { - } - - @Test - void ofSubSkill() { - } -} \ No newline at end of file diff --git a/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java b/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java index da3b6ee565..41e8834651 100644 --- a/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java +++ b/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java @@ -12,13 +12,74 @@ class ProbabilityTest { + private static Stream 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) + ); + } + @Test + void testIsSuccessfulRollSucceeds() { + Probability probability = new ProbabilityImpl(100); + + for (int i = 0; i < 100000; i++) { + assertTrue(processProbability(probability)); + } + } + + @Test + void testIsSuccessfulRollFails() { + Probability probability = new ProbabilityImpl(0); + + for (int i = 0; i < 100000; i++) { + assertFalse(processProbability(probability)); + } + } + @Test + void testIsSuccessfulRollFailsOfPercentage() { + Probability probability = Probability.ofPercentageValue(100); + + for (int i = 0; i < 100000; i++) { + assertFalse(processProbability(probability)); + } + } + + @ParameterizedTest + @MethodSource("provideProbabilitiesForWithinExpectations") + void testProcessProbabilityWithinExpectations(Probability probability, double expectedWinPercent) { + // Probabilities are tested 200,000,000 times with a margin of error of 0.01% + int iterations = 200000000; + double winCount = 0; + + for (int i = 0; i < iterations; i++) { + if(processProbability(probability)) { + winCount++; + } + } + + double successPercent = (winCount / iterations) * 100; + System.out.println(successPercent + ", " + expectedWinPercent); + assertEquals(expectedWinPercent, successPercent, 0.01D); + } @Test - void chanceOfSuccessPercentage() { + void ofPercentageValue() { } @Test - void testChanceOfSuccessPercentage() { + void ofSubSkill() { } } \ No newline at end of file From 59f711834b44493a3bed05abdbcdea23af12a6e1 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 18 Dec 2022 16:02:43 -0800 Subject: [PATCH 19/75] Refactor Probability API a bit --- .../commands/skills/AcrobaticsCommand.java | 6 +- .../commands/skills/ArcheryCommand.java | 6 +- .../nossr50/commands/skills/AxesCommand.java | 4 +- .../commands/skills/FishingCommand.java | 6 +- .../commands/skills/HerbalismCommand.java | 10 +- .../commands/skills/MiningCommand.java | 6 +- .../commands/skills/RepairCommand.java | 4 +- .../nossr50/commands/skills/SkillCommand.java | 2 - .../commands/skills/SmeltingCommand.java | 4 +- .../commands/skills/SwordsCommand.java | 5 +- .../commands/skills/TamingCommand.java | 4 +- .../commands/skills/UnarmedCommand.java | 8 +- .../commands/skills/WoodcuttingCommand.java | 6 +- .../skills/subskills/acrobatics/Roll.java | 23 +- .../nossr50/datatypes/treasure/Treasure.java | 5 +- .../nossr50/listeners/EntityListener.java | 4 +- .../skills/acrobatics/AcrobaticsManager.java | 3 +- .../skills/archery/ArcheryManager.java | 6 +- .../nossr50/skills/axes/AxesManager.java | 9 +- .../skills/excavation/ExcavationManager.java | 5 +- .../skills/fishing/FishingManager.java | 3 +- .../skills/herbalism/HerbalismManager.java | 11 +- .../nossr50/skills/mining/MiningManager.java | 5 +- .../nossr50/skills/repair/RepairManager.java | 7 +- .../skills/salvage/SalvageManager.java | 7 +- .../skills/smelting/SmeltingManager.java | 4 +- .../nossr50/skills/swords/SwordsManager.java | 8 +- .../nossr50/skills/taming/TamingManager.java | 6 +- .../skills/unarmed/UnarmedManager.java | 12 +- .../woodcutting/WoodcuttingManager.java | 9 +- .../com/gmail/nossr50/util/BlockUtils.java | 4 +- .../nossr50/util/random/Probability.java | 79 +++--- .../nossr50/util/random/ProbabilityImpl.java | 2 +- .../nossr50/util/random/ProbabilityUtil.java | 226 ++++++++++++++++++ .../nossr50/util/random/RandomChanceUtil.java | 84 ------- .../gmail/nossr50/util/skills/SkillUtils.java | 127 ---------- .../nossr50/util/random/ProbabilityTest.java | 72 ++++-- .../util/random/ProbabilityUtilTest.java | 22 ++ .../nossr50/util/skills/SkillToolsTest.java | 16 -- 39 files changed, 433 insertions(+), 397 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/util/random/ProbabilityUtil.java delete mode 100644 src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java create mode 100644 src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java delete mode 100644 src/test/java/com/gmail/nossr50/util/skills/SkillToolsTest.java diff --git a/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java index 48e252a03d..64950211c5 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java @@ -6,7 +6,7 @@ import com.gmail.nossr50.listeners.InteractionManager; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.util.Permissions; -import com.gmail.nossr50.util.skills.SkillUtils; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -29,7 +29,7 @@ public AcrobaticsCommand() { protected void dataCalculations(Player player, float skillValue) { // ACROBATICS_DODGE if (canDodge) { - String[] dodgeStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.ACROBATICS_DODGE); + String[] dodgeStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.ACROBATICS_DODGE); dodgeChance = dodgeStrings[0]; dodgeChanceLucky = dodgeStrings[1]; } @@ -56,7 +56,7 @@ protected List statsDisplay(Player player, float skillValue, boolean has if(abstractSubSkill != null) { - String[] rollStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.ACROBATICS_ROLL); + String[] rollStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.ACROBATICS_ROLL); messages.add(getStatMessage(SubSkillType.ACROBATICS_ROLL, rollStrings[0]) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", rollStrings[1]) : "")); diff --git a/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java index 46c2506521..dd7bf8d4b4 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java @@ -5,8 +5,8 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.skills.archery.Archery; import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.CombatUtils; -import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -33,14 +33,14 @@ public ArcheryCommand() { protected void dataCalculations(Player player, float skillValue) { // ARCHERY_ARROW_RETRIEVAL if (canRetrieve) { - String[] retrieveStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.ARCHERY_ARROW_RETRIEVAL); + String[] retrieveStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.ARCHERY_ARROW_RETRIEVAL); retrieveChance = retrieveStrings[0]; retrieveChanceLucky = retrieveStrings[1]; } // ARCHERY_DAZE if (canDaze) { - String[] dazeStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.ARCHERY_DAZE); + String[] dazeStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.ARCHERY_DAZE); dazeChance = dazeStrings[0]; dazeChanceLucky = dazeStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java index 26cdc5d280..49346aca20 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java @@ -6,9 +6,9 @@ import com.gmail.nossr50.skills.axes.Axes; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -48,7 +48,7 @@ protected void dataCalculations(Player player, float skillValue) { // CRITICAL HIT if (canCritical) { - String[] criticalHitStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.AXES_CRITICAL_STRIKES); + String[] criticalHitStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.AXES_CRITICAL_STRIKES); critChance = criticalHitStrings[0]; critChanceLucky = criticalHitStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java index 95614ffe66..6b188d2d7b 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java @@ -10,8 +10,8 @@ import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.random.Probability; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.StringUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; @@ -81,8 +81,8 @@ protected void dataCalculations(Player player, float skillValue) { // FISHING_SHAKE if (canShake) { - Probability shakeProbability = Probability.ofPercentageValue(fishingManager.getShakeChance()); - String[] shakeStrings = SkillUtils.getRNGDisplayValues(shakeProbability); + Probability shakeProbability = Probability.ofPercent(fishingManager.getShakeChance()); + String[] shakeStrings = ProbabilityUtil.getRNGDisplayValues(shakeProbability); shakeChance = shakeStrings[0]; shakeChanceLucky = shakeStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java index 8f8f170d9e..3df385974b 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java @@ -5,8 +5,8 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.Material; @@ -46,7 +46,7 @@ protected void dataCalculations(Player player, float skillValue) { // DOUBLE DROPS if (canDoubleDrop) { - String[] doubleDropStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.HERBALISM_DOUBLE_DROPS); + String[] doubleDropStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.HERBALISM_DOUBLE_DROPS); doubleDropChance = doubleDropStrings[0]; doubleDropChanceLucky = doubleDropStrings[1]; } @@ -67,21 +67,21 @@ protected void dataCalculations(Player player, float skillValue) { if (canGreenThumbBlocks || canGreenThumbPlants) { greenThumbStage = RankUtils.getRank(player, SubSkillType.HERBALISM_GREEN_THUMB); - String[] greenThumbStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.HERBALISM_GREEN_THUMB); + String[] greenThumbStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.HERBALISM_GREEN_THUMB); greenThumbChance = greenThumbStrings[0]; greenThumbChanceLucky = greenThumbStrings[1]; } // HYLIAN LUCK if (hasHylianLuck) { - String[] hylianLuckStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.HERBALISM_HYLIAN_LUCK); + String[] hylianLuckStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.HERBALISM_HYLIAN_LUCK); hylianLuckChance = hylianLuckStrings[0]; hylianLuckChanceLucky = hylianLuckStrings[1]; } // SHROOM THUMB if (canShroomThumb) { - String[] shroomThumbStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.HERBALISM_SHROOM_THUMB); + String[] shroomThumbStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.HERBALISM_SHROOM_THUMB); shroomThumbChance = shroomThumbStrings[0]; shroomThumbChanceLucky = shroomThumbStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java index 42744d5c91..72be89643d 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java @@ -6,8 +6,8 @@ import com.gmail.nossr50.skills.mining.MiningManager; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -57,14 +57,14 @@ protected void dataCalculations(Player player, float skillValue) { // Mastery TRIPLE DROPS if (canMotherLode) { - String[] masteryTripleDropStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.MINING_MOTHER_LODE); + String[] masteryTripleDropStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.MINING_MOTHER_LODE); tripleDropChance = masteryTripleDropStrings[0]; tripleDropChanceLucky = masteryTripleDropStrings[1]; } // DOUBLE DROPS if (canDoubleDrop) { - String[] doubleDropStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.MINING_DOUBLE_DROPS); + String[] doubleDropStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.MINING_DOUBLE_DROPS); doubleDropChance = doubleDropStrings[0]; doubleDropChanceLucky = doubleDropStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java index ff81f63687..32927ddcf8 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java @@ -11,8 +11,8 @@ import com.gmail.nossr50.skills.repair.repairables.Repairable; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.Material; @@ -68,7 +68,7 @@ protected void dataCalculations(Player player, float skillValue) { // SUPER REPAIR if (canSuperRepair) { - String[] superRepairStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.REPAIR_SUPER_REPAIR); + String[] superRepairStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.REPAIR_SUPER_REPAIR); superRepairChance = superRepairStrings[0]; superRepairChanceLucky = superRepairStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java index 8b20cd6bd0..2f5a9c3cac 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java @@ -10,11 +10,9 @@ import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; -import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.gmail.nossr50.util.skills.PerksUtils; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.util.text.StringUtils; import com.gmail.nossr50.util.text.TextComponentFactory; diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java index 27b10b7c63..297662e106 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java @@ -5,8 +5,8 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -46,7 +46,7 @@ protected void dataCalculations(Player player, float skillValue) { // SECOND SMELT if (canSecondSmelt) { - String[] secondSmeltStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.SMELTING_SECOND_SMELT); + String[] secondSmeltStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.SMELTING_SECOND_SMELT); str_secondSmeltChance = secondSmeltStrings[0]; str_secondSmeltChanceLucky = secondSmeltStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java index bb4975059f..b59eae4c29 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java @@ -6,10 +6,9 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillUtils; -import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -39,7 +38,7 @@ public SwordsCommand() { protected void dataCalculations(Player player, float skillValue) { // SWORDS_COUNTER_ATTACK if (canCounter) { - String[] counterStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.SWORDS_COUNTER_ATTACK); + String[] counterStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.SWORDS_COUNTER_ATTACK); counterChance = counterStrings[0]; counterChanceLucky = counterStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java index 729901f212..fc6fd2e46c 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java @@ -5,7 +5,7 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.skills.taming.Taming; import com.gmail.nossr50.util.Permissions; -import com.gmail.nossr50.util.skills.SkillUtils; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.EntityType; @@ -35,7 +35,7 @@ public TamingCommand() { @Override protected void dataCalculations(Player player, float skillValue) { if (canGore) { - String[] goreStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.TAMING_GORE); + String[] goreStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.TAMING_GORE); goreChance = goreStrings[0]; goreChanceLucky = goreStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java index 1092ff415c..554eca6b30 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java @@ -5,9 +5,9 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -40,7 +40,7 @@ public UnarmedCommand() { protected void dataCalculations(Player player, float skillValue) { // UNARMED_ARROW_DEFLECT if (canDeflect) { - String[] deflectStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.UNARMED_ARROW_DEFLECT); + String[] deflectStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.UNARMED_ARROW_DEFLECT); deflectChance = deflectStrings[0]; deflectChanceLucky = deflectStrings[1]; } @@ -54,7 +54,7 @@ protected void dataCalculations(Player player, float skillValue) { // UNARMED_DISARM if (canDisarm) { - String[] disarmStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.UNARMED_DISARM); + String[] disarmStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.UNARMED_DISARM); disarmChance = disarmStrings[0]; disarmChanceLucky = disarmStrings[1]; } @@ -66,7 +66,7 @@ protected void dataCalculations(Player player, float skillValue) { // IRON GRIP if (canIronGrip) { - String[] ironGripStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.UNARMED_IRON_GRIP); + String[] ironGripStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.UNARMED_IRON_GRIP); ironGripChance = ironGripStrings[0]; ironGripChanceLucky = ironGripStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java index 55a407b6de..1dd4beeb05 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java @@ -5,8 +5,8 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -41,7 +41,7 @@ protected void dataCalculations(Player player, float skillValue) { //Clean Cuts if(canTripleDrop) { - String[] tripleDropStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.WOODCUTTING_CLEAN_CUTS); + String[] tripleDropStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.WOODCUTTING_CLEAN_CUTS); tripleDropChance = tripleDropStrings[0]; tripleDropChanceLucky = tripleDropStrings[1]; } @@ -55,7 +55,7 @@ protected void dataCalculations(Player player, float skillValue) { } private void setDoubleDropClassicChanceStrings(Player player) { - String[] doubleDropStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER); + String[] doubleDropStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER); doubleDropChance = doubleDropStrings[0]; doubleDropChanceLucky = doubleDropStrings[1]; } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java index eb165ebb03..40285c48e7 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java @@ -15,10 +15,9 @@ import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.random.Probability; -import com.gmail.nossr50.util.random.ProbabilityImpl; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.PerksUtils; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; @@ -129,7 +128,7 @@ public void addStats(TextComponent.Builder componentBuilder, Player player) { float skillValue = playerProfile.getSkillLevel(getPrimarySkill()); boolean isLucky = Permissions.lucky(player, getPrimarySkill()); - String[] rollStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.ACROBATICS_ROLL); + String[] rollStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.ACROBATICS_ROLL); rollChance = rollStrings[0]; rollChanceLucky = rollStrings[1]; @@ -137,8 +136,8 @@ public void addStats(TextComponent.Builder componentBuilder, Player player) { * Graceful is double the odds of a normal roll */ Probability probability = getRollProbability(player); - Probability gracefulProbability = Probability.ofPercentageValue(probability.getValue() * 2); - String[] gracefulRollStrings = SkillUtils.getRNGDisplayValues(gracefulProbability); + Probability gracefulProbability = Probability.ofPercent(probability.getValue() * 2); + String[] gracefulRollStrings = ProbabilityUtil.getRNGDisplayValues(gracefulProbability); gracefulRollChance = gracefulRollStrings[0]; gracefulRollChanceLucky = gracefulRollStrings[1]; @@ -171,7 +170,7 @@ public void addStats(TextComponent.Builder componentBuilder, Player player) { @NotNull private Probability getRollProbability(Player player) { - return SkillUtils.getSubSkillProbability(SubSkillType.ACROBATICS_ROLL, player); + return ProbabilityUtil.getSubSkillProbability(SubSkillType.ACROBATICS_ROLL, player); } @Override @@ -210,7 +209,7 @@ private double rollCheck(Player player, McMMOPlayer mcMMOPlayer, double damage) double modifiedDamage = calculateModifiedRollDamage(damage, mcMMO.p.getAdvancedConfig().getRollDamageThreshold()); if (!isFatal(player, modifiedDamage) - && SkillUtils.isSkillRNGSuccessful(SubSkillType.ACROBATICS_ROLL, player)) { + && ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.ACROBATICS_ROLL, player)) { NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Acrobatics.Roll.Text"); SoundManager.sendCategorizedSound(player, player.getLocation(), SoundType.ROLL_ACTIVATED, SoundCategory.PLAYERS); //player.sendMessage(LocaleLoader.getString("Acrobatics.Roll.Text")); @@ -247,12 +246,12 @@ private int getActivationChance(McMMOPlayer mcMMOPlayer) { private double gracefulRollCheck(Player player, McMMOPlayer mcMMOPlayer, double damage, int skillLevel) { double modifiedDamage = calculateModifiedRollDamage(damage, mcMMO.p.getAdvancedConfig().getRollDamageThreshold() * 2); - double gracefulOdds = SkillUtils.getSubSkillProbability(subSkillType, player).getValue() * 2; - Probability gracefulProbability = Probability.ofPercentageValue(gracefulOdds); + double gracefulOdds = ProbabilityUtil.getSubSkillProbability(subSkillType, player).getValue() * 2; + Probability gracefulProbability = Probability.ofPercent(gracefulOdds); if (!isFatal(player, modifiedDamage) //TODO: Graceful isn't sending out an event - && SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.ACROBATICS, player, gracefulProbability)) + && ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.ACROBATICS, player, gracefulProbability)) { NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Acrobatics.Ability.Proc"); SoundManager.sendCategorizedSound(player, player.getLocation(), SoundType.ROLL_ACTIVATED, SoundCategory.PLAYERS,0.5F); @@ -421,10 +420,10 @@ public String getMechanics() { @Override public Double[] getStats(Player player) { - double playerChanceRoll = SkillUtils.getSubSkillProbability(subSkillType, player).getValue(); + double playerChanceRoll = ProbabilityUtil.getSubSkillProbability(subSkillType, player).getValue(); double playerChanceGrace = playerChanceRoll * 2; - double gracefulOdds = SkillUtils.getSubSkillProbability(subSkillType, player).getValue() * 2; + double gracefulOdds = ProbabilityUtil.getSubSkillProbability(subSkillType, player).getValue() * 2; return new Double[]{ playerChanceRoll, playerChanceGrace }; } diff --git a/src/main/java/com/gmail/nossr50/datatypes/treasure/Treasure.java b/src/main/java/com/gmail/nossr50/datatypes/treasure/Treasure.java index 16d4ac20a5..78b1adef04 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/treasure/Treasure.java +++ b/src/main/java/com/gmail/nossr50/datatypes/treasure/Treasure.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.datatypes.treasure; import com.gmail.nossr50.util.random.Probability; -import com.gmail.nossr50.util.random.ProbabilityImpl; import com.google.common.base.Objects; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; @@ -17,7 +16,7 @@ public Treasure(ItemStack drop, int xp, double dropChance, int dropLevel) { this.drop = drop; this.xp = xp; this.dropChance = dropChance; - this.dropProbability = Probability.ofPercentageValue(dropChance / 100); + this.dropProbability = Probability.ofPercent(dropChance / 100); this.dropLevel = dropLevel; } @@ -47,7 +46,7 @@ public double getDropChance() { public void setDropChance(double dropChance) { this.dropChance = dropChance; - this.dropProbability = Probability.ofPercentageValue(dropChance / 100); + this.dropProbability = Probability.ofPercent(dropChance / 100); } public int getDropLevel() { diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index 85a43c8e4e..4e94185554 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -23,8 +23,8 @@ import com.gmail.nossr50.util.*; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.CombatUtils; -import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.worldguard.WorldGuardManager; import com.gmail.nossr50.worldguard.WorldGuardUtils; import org.bukkit.ChatColor; @@ -196,7 +196,7 @@ public void onProjectileLaunch(ProjectileLaunchEvent event) { return; } - if (SkillUtils.isSkillRNGSuccessful(SubSkillType.ARCHERY_ARROW_RETRIEVAL, player)) { + if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.ARCHERY_ARROW_RETRIEVAL, player)) { projectile.setMetadata(MetadataConstants.METADATA_KEY_TRACKED_ARROW, MetadataConstants.MCMMO_METADATA_VALUE); } } diff --git a/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java b/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java index c24daf9c85..6322e52c51 100644 --- a/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java @@ -14,6 +14,7 @@ import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.ParticleEffectUtils; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; @@ -93,7 +94,7 @@ public double dodgeCheck(Entity attacker, double damage) { Player player = getPlayer(); if (!isFatal(modifiedDamage) - && SkillUtils.isSkillRNGSuccessful(SubSkillType.ACROBATICS_DODGE, player)) { + && ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.ACROBATICS_DODGE, player)) { ParticleEffectUtils.playDodgeEffect(player); if (mmoPlayer.useChatNotifications()) { diff --git a/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java b/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java index a096040a95..fc8a8be28a 100644 --- a/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java +++ b/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java @@ -10,8 +10,8 @@ import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; @@ -88,7 +88,7 @@ public void retrieveArrows(LivingEntity target, Projectile projectile) { * @param defender The {@link Player} being affected by the ability */ public double daze(Player defender) { - if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.ARCHERY_DAZE, getPlayer())) { + if (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.ARCHERY_DAZE, getPlayer())) { return 0; } @@ -116,7 +116,7 @@ public double daze(Player defender) { * @param oldDamage The raw damage value of this arrow before we modify it */ public double skillShot(double oldDamage) { - if (SkillUtils.isNonRNGSkillActivationSuccessful(SubSkillType.ARCHERY_SKILL_SHOT, getPlayer())) { + if (ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.ARCHERY_SKILL_SHOT, getPlayer())) { return Archery.getSkillShotBonusDamage(getPlayer(), oldDamage); } else { return oldDamage; diff --git a/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java b/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java index 467e0b7504..d80f7292f5 100644 --- a/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java +++ b/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java @@ -11,6 +11,7 @@ import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.ParticleEffectUtils; import com.gmail.nossr50.util.skills.RankUtils; @@ -68,7 +69,7 @@ public boolean canActivateAbility() { * Handle the effects of the Axe Mastery ability */ public double axeMastery() { - if (SkillUtils.isNonRNGSkillActivationSuccessful(SubSkillType.AXES_AXE_MASTERY, getPlayer())) { + if (ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.AXES_AXE_MASTERY, getPlayer())) { return Axes.getAxeMasteryBonusDamage(getPlayer()); } @@ -82,7 +83,7 @@ public double axeMastery() { * @param damage The amount of damage initially dealt by the event */ public double criticalHit(LivingEntity target, double damage) { - if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.AXES_CRITICAL_STRIKES, getPlayer())) { + if (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.AXES_CRITICAL_STRIKES, getPlayer())) { return 0; } @@ -117,7 +118,7 @@ public void impactCheck(@NotNull LivingEntity target) { for (ItemStack armor : target.getEquipment().getArmorContents()) { if (armor != null && ItemUtils.isArmor(armor)) { - if (SkillUtils.isSkillRNGSuccessful(SubSkillType.AXES_ARMOR_IMPACT, getPlayer())) { + if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.AXES_ARMOR_IMPACT, getPlayer())) { SkillUtils.handleArmorDurabilityChange(armor, durabilityDamage, 1); } } @@ -135,7 +136,7 @@ public double getImpactDurabilityDamage() { */ public double greaterImpact(@NotNull LivingEntity target) { //static chance (3rd param) - if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.AXES_GREATER_IMPACT, getPlayer())) { + if (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.AXES_GREATER_IMPACT, getPlayer())) { return 0; } diff --git a/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java b/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java index 6af8684c22..b487553f8e 100644 --- a/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java +++ b/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java @@ -10,6 +10,7 @@ import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.Location; @@ -40,10 +41,10 @@ public void excavationBlockCheck(BlockState blockState) { for (ExcavationTreasure treasure : treasures) { if (skillLevel >= treasure.getDropLevel() - && SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.EXCAVATION, getPlayer(), treasure.getDropProbability())) { + && ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.EXCAVATION, getPlayer(), treasure.getDropProbability())) { //Spawn Vanilla XP orbs if a dice roll succeeds - if(SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.EXCAVATION, getPlayer(), getArchaelogyExperienceOrbChance())) { + if(ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.EXCAVATION, getPlayer(), getArchaelogyExperienceOrbChance())) { Misc.spawnExperienceOrb(location, getExperienceOrbsReward()); } diff --git a/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java b/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java index f724259a7a..bc9e73c4a1 100644 --- a/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java @@ -18,6 +18,7 @@ import com.gmail.nossr50.util.*; import com.gmail.nossr50.util.compat.layers.skills.MasterAnglerCompatibilityLayer; import com.gmail.nossr50.util.player.NotificationManager; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; @@ -477,7 +478,7 @@ public Location getHookLocation() { * @param target The {@link LivingEntity} affected by the ability */ public void shakeCheck(@NotNull LivingEntity target) { - if (SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.FISHING, getPlayer(), getShakeChance())) { + if (ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.FISHING, getPlayer(), getShakeChance())) { List possibleDrops = Fishing.findPossibleDrops(target); if (possibleDrops == null || possibleDrops.isEmpty()) { diff --git a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java b/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java index ed09b12866..509c6e36c8 100644 --- a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java +++ b/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java @@ -20,6 +20,7 @@ import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.*; import com.gmail.nossr50.util.player.NotificationManager; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.sounds.SoundManager; @@ -655,7 +656,7 @@ private boolean checkDoubleDrop(BlockState blockState) * @return true if the ability was successful, false otherwise */ public boolean processGreenThumbBlocks(BlockState blockState) { - if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.HERBALISM_GREEN_THUMB, getPlayer())) { + if (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.HERBALISM_GREEN_THUMB, getPlayer())) { NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE_FAILED, "Herbalism.Ability.GTh.Fail"); return false; } @@ -670,7 +671,7 @@ public boolean processGreenThumbBlocks(BlockState blockState) { * @return true if the ability was successful, false otherwise */ public boolean processHylianLuck(BlockState blockState) { - if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.HERBALISM_HYLIAN_LUCK, getPlayer())) { + if (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.HERBALISM_HYLIAN_LUCK, getPlayer())) { return false; } @@ -689,7 +690,7 @@ public boolean processHylianLuck(BlockState blockState) { for (HylianTreasure treasure : treasures) { if (skillLevel >= treasure.getDropLevel() - && SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.HERBALISM, player, treasure.getDropChance())) { + && ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.HERBALISM, player, treasure.getDropChance())) { if (!EventUtils.simulateBlockBreak(blockState.getBlock(), player, false)) { return false; } @@ -726,7 +727,7 @@ public boolean processShroomThumb(BlockState blockState) { playerInventory.removeItem(new ItemStack(Material.RED_MUSHROOM)); player.updateInventory(); - if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.HERBALISM_SHROOM_THUMB, player)) { + if (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.HERBALISM_SHROOM_THUMB, player)) { NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Herbalism.Ability.ShroomThumb.Fail"); return false; } @@ -806,7 +807,7 @@ private boolean processGreenThumbPlants(BlockState blockState, BlockBreakEvent b return false; } - if (!greenTerra && !SkillUtils.isSkillRNGSuccessful(SubSkillType.HERBALISM_GREEN_THUMB, player)) { + if (!greenTerra && !ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.HERBALISM_GREEN_THUMB, player)) { return false; } diff --git a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java index 6ad6f958ed..91197cc03d 100644 --- a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java +++ b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java @@ -13,6 +13,7 @@ import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.*; import com.gmail.nossr50.util.player.NotificationManager; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; import org.apache.commons.lang.math.RandomUtils; @@ -114,7 +115,7 @@ public void miningBlockCheck(BlockState blockState) { private boolean processTripleDrops(@NotNull BlockState blockState) { //TODO: Make this readable - if (SkillUtils.isSkillRNGSuccessful(SubSkillType.MINING_MOTHER_LODE, getPlayer())) { + if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.MINING_MOTHER_LODE, getPlayer())) { BlockUtils.markDropsAsBonus(blockState, 2); return true; } else { @@ -124,7 +125,7 @@ private boolean processTripleDrops(@NotNull BlockState blockState) { private void processDoubleDrops(@NotNull BlockState blockState) { //TODO: Make this readable - if (SkillUtils.isSkillRNGSuccessful(SubSkillType.MINING_DOUBLE_DROPS, getPlayer())) { + if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.MINING_DOUBLE_DROPS, getPlayer())) { boolean useTriple = mmoPlayer.getAbilityMode(SuperAbilityType.SUPER_BREAKER) && mcMMO.p.getAdvancedConfig().getAllowMiningTripleDrops(); BlockUtils.markDropsAsBonus(blockState, useTriple); } diff --git a/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java b/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java index dca8b59dc1..a684da64eb 100644 --- a/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java +++ b/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java @@ -14,6 +14,7 @@ import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.sounds.SoundManager; @@ -318,7 +319,7 @@ private boolean checkPlayerProcRepair() { if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.REPAIR_SUPER_REPAIR)) return false; - if (SkillUtils.isSkillRNGSuccessful(SubSkillType.REPAIR_SUPER_REPAIR, getPlayer())) { + if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.REPAIR_SUPER_REPAIR, getPlayer())) { NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Repair.Skills.FeltEasy"); return true; } @@ -369,10 +370,10 @@ private void addEnchants(ItemStack item) { Enchantment enchantment = enchant.getKey(); - if (SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.REPAIR, getPlayer(), getKeepEnchantChance())) { + if (ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.REPAIR, getPlayer(), getKeepEnchantChance())) { if (ArcaneForging.arcaneForgingDowngrades && enchantLevel > 1 - && (!SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.REPAIR, getPlayer(), 100 - getDowngradeEnchantChance()))) { + && (!ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.REPAIR, getPlayer(), 100 - getDowngradeEnchantChance()))) { item.addUnsafeEnchantment(enchantment, enchantLevel - 1); downgraded = true; } diff --git a/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java b/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java index a8333d75c9..7546b1c99e 100644 --- a/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java +++ b/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java @@ -14,6 +14,7 @@ import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.sounds.SoundManager; @@ -119,7 +120,7 @@ public void handleSalvage(Location location, ItemStack item) { for(int x = 0; x < potentialSalvageYield-1; x++) { - if(SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.SALVAGE, player, chanceOfSuccess)) { + if(ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.SALVAGE, player, chanceOfSuccess)) { chanceOfSuccess-=3; chanceOfSuccess = Math.max(chanceOfSuccess, 90); @@ -250,12 +251,12 @@ private ItemStack arcaneSalvageCheck(Map enchants) { if (!Salvage.arcaneSalvageEnchantLoss || Permissions.hasSalvageEnchantBypassPerk(player) - || SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.SALVAGE, player, getExtractFullEnchantChance())) { + || ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.SALVAGE, player, getExtractFullEnchantChance())) { enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel, true); } else if (enchantLevel > 1 && Salvage.arcaneSalvageDowngrades - && SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.SALVAGE, player, getExtractPartialEnchantChance())) { + && ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.SALVAGE, player, getExtractPartialEnchantChance())) { enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel - 1, true); downgraded = true; } else { diff --git a/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java b/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java index d77e7c0e27..9bb4a6e398 100644 --- a/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java @@ -8,8 +8,8 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.block.Furnace; import org.bukkit.event.inventory.FurnaceBurnEvent; import org.bukkit.event.inventory.FurnaceSmeltEvent; @@ -24,7 +24,7 @@ public SmeltingManager(McMMOPlayer mcMMOPlayer) { public boolean isSecondSmeltSuccessful() { return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.SMELTING_SECOND_SMELT) - && SkillUtils.isSkillRNGSuccessful(SubSkillType.SMELTING_SECOND_SMELT, getPlayer()); + && ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.SMELTING_SECOND_SMELT, getPlayer()); } /** diff --git a/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java b/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java index d6d5f0e079..7ab2536d1f 100644 --- a/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java @@ -14,11 +14,9 @@ import com.gmail.nossr50.util.MetadataConstants; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; -import com.gmail.nossr50.util.random.RandomChanceUtil; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; -import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; @@ -78,7 +76,7 @@ public void processRupture(@NotNull LivingEntity target) { } double ruptureOdds = mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(getRuptureRank()); - if (SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.SWORDS, this.getPlayer(), ruptureOdds)) { + if (ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.SWORDS, this.getPlayer(), ruptureOdds)) { if (target instanceof Player defender) { @@ -144,7 +142,7 @@ else if(ItemUtils.isStoneTool(itemStack)) */ public void counterAttackChecks(@NotNull LivingEntity attacker, double damage) { - if (SkillUtils.isSkillRNGSuccessful(SubSkillType.SWORDS_COUNTER_ATTACK, getPlayer())) { + if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.SWORDS_COUNTER_ATTACK, getPlayer())) { CombatUtils.dealDamage(attacker, damage / Swords.counterAttackModifier, getPlayer()); NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Countered"); diff --git a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java index 9051360676..22c56f76c8 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java @@ -15,9 +15,9 @@ import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.ParticleEffectUtils; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; import com.gmail.nossr50.util.text.StringUtils; @@ -143,7 +143,7 @@ public void awardTamingXP(@NotNull LivingEntity entity) { * @param damage The damage being absorbed by the wolf */ public void fastFoodService(@NotNull Wolf wolf, double damage) { - if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.TAMING_FAST_FOOD_SERVICE, getPlayer())) { + if (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.TAMING_FAST_FOOD_SERVICE, getPlayer())) { return; } @@ -262,7 +262,7 @@ public void pummel(LivingEntity target, Wolf wolf) { if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_PUMMEL)) return; - if(!SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.TAMING, getPlayer(), mcMMO.p.getAdvancedConfig().getPummelChance())) + if(!ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.TAMING, getPlayer(), mcMMO.p.getAdvancedConfig().getPummelChance())) return; ParticleEffectUtils.playGreaterImpactEffect(target); diff --git a/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java b/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java index f05d6051fd..dbc8060efb 100644 --- a/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java +++ b/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java @@ -12,8 +12,8 @@ import com.gmail.nossr50.util.*; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.entity.Item; @@ -67,7 +67,7 @@ public boolean canUseBlockCracker() { } public boolean blockCrackerCheck(@NotNull BlockState blockState) { - if (!SkillUtils.isNonRNGSkillActivationSuccessful(SubSkillType.UNARMED_BLOCK_CRACKER, getPlayer())) { + if (!ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.UNARMED_BLOCK_CRACKER, getPlayer())) { return false; } @@ -98,7 +98,7 @@ public boolean blockCrackerCheck(@NotNull BlockState blockState) { * @param defender The defending player */ public void disarmCheck(@NotNull Player defender) { - if (SkillUtils.isSkillRNGSuccessful(SubSkillType.UNARMED_DISARM, getPlayer()) && !hasIronGrip(defender)) { + if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.UNARMED_DISARM, getPlayer()) && !hasIronGrip(defender)) { if (EventUtils.callDisarmEvent(defender).isCancelled()) { return; } @@ -121,7 +121,7 @@ public void disarmCheck(@NotNull Player defender) { * Check for arrow deflection. */ public boolean deflectCheck() { - if (SkillUtils.isSkillRNGSuccessful(SubSkillType.UNARMED_ARROW_DEFLECT, getPlayer())) { + if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.UNARMED_ARROW_DEFLECT, getPlayer())) { NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Combat.ArrowDeflect"); return true; } @@ -144,7 +144,7 @@ public double berserkDamage(double damage) { * Handle the effects of the Iron Arm ability */ public double calculateSteelArmStyleDamage() { - if (SkillUtils.isNonRNGSkillActivationSuccessful(SubSkillType.UNARMED_STEEL_ARM_STYLE, getPlayer())) { + if (ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.UNARMED_STEEL_ARM_STYLE, getPlayer())) { return getSteelArmStyleDamage(); } @@ -178,7 +178,7 @@ public double getSteelArmStyleDamage() { private boolean hasIronGrip(@NotNull Player defender) { if (!Misc.isNPCEntityExcludingVillagers(defender) && Permissions.isSubSkillEnabled(defender, SubSkillType.UNARMED_IRON_GRIP) - && SkillUtils.isSkillRNGSuccessful(SubSkillType.UNARMED_IRON_GRIP, defender)) { + && ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.UNARMED_IRON_GRIP, defender)) { NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, "Unarmed.Ability.IronGrip.Defender"); NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Unarmed.Ability.IronGrip.Attacker"); diff --git a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java index c7b27d6114..3643d9ce3c 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java @@ -13,10 +13,9 @@ import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.*; import com.gmail.nossr50.util.player.NotificationManager; -import com.gmail.nossr50.util.random.RandomChanceUtil; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -71,14 +70,14 @@ public boolean canUseTreeFeller(ItemStack heldItem) { private boolean checkHarvestLumberActivation(Material material) { return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER) && RankUtils.hasReachedRank(1, getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER) - && SkillUtils.isSkillRNGSuccessful(SubSkillType.WOODCUTTING_HARVEST_LUMBER, getPlayer()) + && ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.WOODCUTTING_HARVEST_LUMBER, getPlayer()) && mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, material); } private boolean checkCleanCutsActivation(Material material) { return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER) && RankUtils.hasReachedRank(1, getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER) - && SkillUtils.isSkillRNGSuccessful(SubSkillType.WOODCUTTING_CLEAN_CUTS, getPlayer()) + && ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.WOODCUTTING_CLEAN_CUTS, getPlayer()) && mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, material); } @@ -330,7 +329,7 @@ private void dropTreeFellerLootFromBlocks(@NotNull Set treeFellerBlo if(RankUtils.hasReachedRank(2, player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) { if(mcMMO.p.getAdvancedConfig().isKnockOnWoodXPOrbEnabled()) { //TODO: Test the results of this RNG, should be 10% - if(SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.WOODCUTTING, player, 10)) { + if(ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.WOODCUTTING, player, 10)) { int randOrbCount = Math.max(1, Misc.getRandom().nextInt(100)); Misc.spawnExperienceOrb(blockState.getLocation(), randOrbCount); } diff --git a/src/main/java/com/gmail/nossr50/util/BlockUtils.java b/src/main/java/com/gmail/nossr50/util/BlockUtils.java index 3e51492ab6..2fe25e401d 100644 --- a/src/main/java/com/gmail/nossr50/util/BlockUtils.java +++ b/src/main/java/com/gmail/nossr50/util/BlockUtils.java @@ -7,7 +7,7 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.repair.Repair; import com.gmail.nossr50.skills.salvage.Salvage; -import com.gmail.nossr50.util.skills.SkillUtils; +import com.gmail.nossr50.util.random.ProbabilityUtil; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; @@ -67,7 +67,7 @@ public static void markDropsAsBonus(BlockState blockState, int amount) { */ public static boolean checkDoubleDrops(Player player, BlockState blockState, PrimarySkillType skillType, SubSkillType subSkillType) { if (mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(skillType, blockState.getType()) && Permissions.isSubSkillEnabled(player, subSkillType)) { - return SkillUtils.isSkillRNGSuccessful(subSkillType, player); + return ProbabilityUtil.isSkillRNGSuccessful(subSkillType, player); } return false; diff --git a/src/main/java/com/gmail/nossr50/util/random/Probability.java b/src/main/java/com/gmail/nossr50/util/random/Probability.java index d2b16fd5f0..b792ad64ac 100644 --- a/src/main/java/com/gmail/nossr50/util/random/Probability.java +++ b/src/main/java/com/gmail/nossr50/util/random/Probability.java @@ -1,12 +1,9 @@ package com.gmail.nossr50.util.random; -import com.gmail.nossr50.datatypes.player.McMMOPlayer; -import com.gmail.nossr50.datatypes.skills.SubSkillType; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.player.UserManager; -import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.VisibleForTesting; + +import java.util.concurrent.ThreadLocalRandom; public interface Probability { /** @@ -20,52 +17,38 @@ public interface Probability { */ double getValue(); - static @NotNull Probability ofSubSkill(@Nullable Player player, - @NotNull SubSkillType subSkillType, - @NotNull SkillProbabilityType skillProbabilityType) { - - switch (skillProbabilityType) { - case DYNAMIC_CONFIGURABLE: - double probabilityCeiling; - double xCeiling; - double xPos; - - if (player != null) { - McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - if(mmoPlayer != null) - xPos = mmoPlayer.getSkillLevel(subSkillType.getParentSkill()); - else - xPos = 0; - } else { - xPos = 0; - } + static @NotNull Probability ofPercent(double percentageValue) { + return new ProbabilityImpl(percentageValue); + } - //Probability ceiling is configurable in this type - probabilityCeiling = mcMMO.p.getAdvancedConfig().getMaximumProbability(subSkillType); - //The xCeiling is configurable in this type - xCeiling = mcMMO.p.getAdvancedConfig().getMaxBonusLevel(subSkillType); - return new ProbabilityImpl(xPos, xCeiling, probabilityCeiling); - case STATIC_CONFIGURABLE: - try { - return ofPercentageValue(getStaticRandomChance(subSkillType)); - } catch (InvalidStaticChance invalidStaticChance) { - invalidStaticChance.printStackTrace(); - } - default: - throw new RuntimeException("No case in switch statement for Skill Probability Type!"); - } + /** + * Simulates a "roll of the dice" + * If the value passed is higher than the "random" value, than it is a successful roll + * + * @param probabilityValue probability value + * @return true for succeeding, false for failing + */ + static private boolean isSuccessfulRoll(double probabilityValue) { + return probabilityValue >= ThreadLocalRandom.current().nextDouble(100D); } - static @NotNull Probability ofPercentageValue(double percentageValue) { - return new ProbabilityImpl(percentageValue / 100); + /** + * Simulate an outcome on a probability and return true or false for the result of that outcome + * + * @return true if the probability succeeded, false if it failed + */ + default boolean evaluate() { + return isSuccessfulRoll(getValue()); } - static double getStaticRandomChance(@NotNull SubSkillType subSkillType) throws InvalidStaticChance { - return switch (subSkillType) { - case AXES_ARMOR_IMPACT -> mcMMO.p.getAdvancedConfig().getImpactChance(); - case AXES_GREATER_IMPACT -> mcMMO.p.getAdvancedConfig().getGreaterImpactChance(); - case TAMING_FAST_FOOD_SERVICE -> mcMMO.p.getAdvancedConfig().getFastFoodChance(); - default -> throw new InvalidStaticChance(); - }; + /** + * Modify and then Simulate an outcome on a probability and return true or false for the result of that outcome + * + * @param probabilityMultiplier probability will be multiplied by this before success is checked + * @return true if the probability succeeded, false if it failed + */ + default boolean evaluate(double probabilityMultiplier) { + double probabilityValue = getValue() * probabilityMultiplier; + return isSuccessfulRoll(probabilityValue); } } diff --git a/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java b/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java index 09b46fefc0..4898058070 100644 --- a/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java +++ b/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java @@ -20,7 +20,7 @@ public class ProbabilityImpl implements Probability { probabilityValue = staticProbability; } - public ProbabilityImpl(double xPos, double xCeiling, double probabilityCeiling) throws ValueOutOfBoundsException { + ProbabilityImpl(double xPos, double xCeiling, double probabilityCeiling) throws ValueOutOfBoundsException { if(probabilityCeiling > 100) { throw new ValueOutOfBoundsException("Probability Ceiling should never be above 100!"); } else if (probabilityCeiling < 0) { diff --git a/src/main/java/com/gmail/nossr50/util/random/ProbabilityUtil.java b/src/main/java/com/gmail/nossr50/util/random/ProbabilityUtil.java new file mode 100644 index 0000000000..a625260fda --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/random/ProbabilityUtil.java @@ -0,0 +1,226 @@ +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.events.skills.secondaryabilities.SubSkillEvent; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.EventUtils; +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.jetbrains.annotations.Nullable; + +import java.text.DecimalFormat; + +public class ProbabilityUtil { + public static final @NotNull DecimalFormat percent = new DecimalFormat("##0.00%"); + public static final double LUCKY_MODIFIER = 1.333D; + + /** + * Return a chance of success in "percentage" format, show to the player in UI elements + * + * @param player target player + * @param subSkillType target subskill + * @param isLucky whether to apply luck modifiers + * + * @return "percentage" representation of success + */ + public static double chanceOfSuccessPercentage(@NotNull Player player, + @NotNull SubSkillType subSkillType, + boolean isLucky) { + Probability probability = getSubSkillProbability(subSkillType, player); + //Probability values are on a 0-1 scale and need to be "transformed" into a 1-100 scale + double percentageValue = probability.getValue(); //Doesn't need to be scaled + + //Apply lucky modifier + if(isLucky) { + percentageValue *= LUCKY_MODIFIER; + } + + return percentageValue; + } + + public static double chanceOfSuccessPercentage(@NotNull Probability probability, boolean isLucky) { + //Probability values are on a 0-1 scale and need to be "transformed" into a 1-100 scale + double percentageValue = probability.getValue(); + + //Apply lucky modifier + if(isLucky) { + percentageValue *= LUCKY_MODIFIER; + } + + return percentageValue; + } + + static double getStaticRandomChance(@NotNull SubSkillType subSkillType) throws InvalidStaticChance { + return switch (subSkillType) { + case AXES_ARMOR_IMPACT -> mcMMO.p.getAdvancedConfig().getImpactChance(); + case AXES_GREATER_IMPACT -> mcMMO.p.getAdvancedConfig().getGreaterImpactChance(); + case TAMING_FAST_FOOD_SERVICE -> mcMMO.p.getAdvancedConfig().getFastFoodChance(); + default -> throw new InvalidStaticChance(); + }; + } + + static SkillProbabilityType getProbabilityType(@NotNull SubSkillType subSkillType) { + SkillProbabilityType skillProbabilityType = SkillProbabilityType.DYNAMIC_CONFIGURABLE; + + if(subSkillType == SubSkillType.TAMING_FAST_FOOD_SERVICE + || subSkillType == SubSkillType.AXES_ARMOR_IMPACT + || subSkillType == SubSkillType.AXES_GREATER_IMPACT) + skillProbabilityType = SkillProbabilityType.STATIC_CONFIGURABLE; + + return skillProbabilityType; + } + + static @NotNull Probability ofSubSkill(@Nullable Player player, + @NotNull SubSkillType subSkillType) { + switch (getProbabilityType(subSkillType)) { + case DYNAMIC_CONFIGURABLE: + double probabilityCeiling; + double xCeiling; + double xPos; + + if (player != null) { + McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + if(mmoPlayer != null) + xPos = mmoPlayer.getSkillLevel(subSkillType.getParentSkill()); + else + xPos = 0; + } else { + xPos = 0; + } + + //Probability ceiling is configurable in this type + probabilityCeiling = mcMMO.p.getAdvancedConfig().getMaximumProbability(subSkillType); + //The xCeiling is configurable in this type + xCeiling = mcMMO.p.getAdvancedConfig().getMaxBonusLevel(subSkillType); + return new ProbabilityImpl(xPos, xCeiling, probabilityCeiling); + case STATIC_CONFIGURABLE: + try { + return Probability.ofPercent(getStaticRandomChance(subSkillType)); + } catch (InvalidStaticChance invalidStaticChance) { + invalidStaticChance.printStackTrace(); + } + default: + throw new RuntimeException("No case in switch statement for Skill Probability Type!"); + } + } + + /** + * This is one of several Skill RNG check methods + * This helper method is for specific {@link SubSkillType}, which help mcMMO understand where the RNG values used in our calculations come from this {@link SubSkillType} + *

+ * 1) Determine where the RNG values come from for the passed {@link SubSkillType} + * NOTE: In the config file, there are values which are static and which are more dynamic, this is currently a bit hardcoded and will need to be updated manually + *

+ * 2) Determine whether to use Lucky multiplier and influence the outcome + *

+ * 3) Creates a {@link Probability} and pipes it to {@link ProbabilityUtil} which processes the result and returns it + *

+ * This also calls a {@link SubSkillEvent} which can be cancelled, if it is cancelled this will return false + * The outcome of the probability can also be modified by this event that is called + * + * @param subSkillType target subskill + * @param player target player, can be null (null players are given odds equivalent to a player with no levels or luck) + * @return true if the Skill RNG succeeds, false if it fails + */ + public static boolean isSkillRNGSuccessful(@NotNull SubSkillType subSkillType, @NotNull Player player) { + //Process probability + Probability probability = getSubSkillProbability(subSkillType, player); + + //Send out event + SubSkillEvent subSkillEvent = EventUtils.callSubSkillEvent(player, subSkillType); + + if(subSkillEvent.isCancelled()) { + return false; //Event got cancelled so this doesn't succeed + } + + //Result modifier + double resultModifier = subSkillEvent.getResultModifier(); + + //Mutate probability + if(resultModifier != 1.0D) + probability = Probability.ofPercent(probability.getValue() * resultModifier); + + //Luck + boolean isLucky = Permissions.lucky(player, subSkillType.getParentSkill()); + + if(isLucky) { + return probability.evaluate(LUCKY_MODIFIER); + } else { + return probability.evaluate(); + } + } + + /** + * This is one of several Skill RNG check methods + * This helper method is specific to static value RNG, which can be influenced by a player's Luck + * + * @param primarySkillType the related primary skill + * @param player the target player, can be null (null players have the worst odds) + * @param probabilityPercentage the probability of this player succeeding in "percentage" format (0-100 inclusive) + * @return true if the RNG succeeds, false if it fails + */ + public static boolean isStaticSkillRNGSuccessful(@NotNull PrimarySkillType primarySkillType, @Nullable Player player, double probabilityPercentage) { + //Grab a probability converted from a "percentage" value + Probability probability = Probability.ofPercent(probabilityPercentage); + + return isStaticSkillRNGSuccessful(primarySkillType, player, probability); + } + + /** + * This is one of several Skill RNG check methods + * This helper method is specific to static value RNG, which can be influenced by a player's Luck + * + * @param primarySkillType the related primary skill + * @param player the target player, can be null (null players have the worst odds) + * @param probability the probability of this player succeeding + * @return true if the RNG succeeds, false if it fails + */ + public static boolean isStaticSkillRNGSuccessful(@NotNull PrimarySkillType primarySkillType, @Nullable Player player, @NotNull Probability probability) { + boolean isLucky = player != null && Permissions.lucky(player, primarySkillType); + + if(isLucky) { + return probability.evaluate(LUCKY_MODIFIER); + } else { + return probability.evaluate(); + } + } + + /** + * Skills activate without RNG, this allows other plugins to prevent that activation + * @param subSkillType target subskill + * @param player target player + * @return true if the skill succeeds (wasn't cancelled by any other plugin) + */ + public static boolean isNonRNGSkillActivationSuccessful(@NotNull SubSkillType subSkillType, @NotNull Player player) { + return !EventUtils.callSubSkillEvent(player, subSkillType).isCancelled(); + } + + /** + * Grab the {@link Probability} for a specific {@link SubSkillType} for a specific {@link Player} + * + * @param subSkillType target subskill + * @param player target player + * @return the Probability of this skill succeeding + */ + public static @NotNull Probability getSubSkillProbability(@NotNull SubSkillType subSkillType, @Nullable Player player) { + return ProbabilityUtil.ofSubSkill(player, subSkillType); + } + + public static @NotNull String[] getRNGDisplayValues(@NotNull Player player, @NotNull SubSkillType subSkill) { + double firstValue = chanceOfSuccessPercentage(player, subSkill, false); + double secondValue = chanceOfSuccessPercentage(player, subSkill, true); + + return new String[]{percent.format(firstValue), percent.format(secondValue)}; + } + + public static @NotNull String[] getRNGDisplayValues(@NotNull Probability probability) { + double firstValue = chanceOfSuccessPercentage(probability, false); + double secondValue = chanceOfSuccessPercentage(probability, true); + + return new String[]{percent.format(firstValue), percent.format(secondValue)}; + } +} diff --git a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java deleted file mode 100644 index f47e4e8acd..0000000000 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.gmail.nossr50.util.random; - -import com.gmail.nossr50.datatypes.skills.SubSkillType; -import com.gmail.nossr50.util.skills.SkillUtils; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.VisibleForTesting; - -import java.text.DecimalFormat; -import java.util.concurrent.ThreadLocalRandom; - -public class RandomChanceUtil { - public static final @NotNull DecimalFormat percent = new DecimalFormat("##0.00%"); - public static final double LUCKY_MODIFIER = 1.333D; - - /** - * Simulate an outcome on a probability and return true or false for the result of that outcome - * - * @param probability target probability - * @return true if the probability succeeded, false if it failed - */ - public static boolean processProbability(@NotNull Probability probability) { - return isSuccessfulRoll(probability.getValue()); - } - - /** - * Modify and then Simulate an outcome on a probability and return true or false for the result of that outcome - * - * @param probability target probability - * @param probabilityMultiplier probability will be multiplied by this before success is checked - * @return true if the probability succeeded, false if it failed - */ - public static boolean processProbability(@NotNull Probability probability, double probabilityMultiplier) { - double probabilityValue = probability.getValue() * probabilityMultiplier; - return isSuccessfulRoll(probabilityValue); - } - - /** - * Simulates a "roll of the dice" - * If the value passed is higher than the "random" value, than it is a successful roll - * - * @param probabilityValue probability value - * @return true for succeeding, false for failing - */ - @VisibleForTesting - static boolean isSuccessfulRoll(double probabilityValue) { - return probabilityValue >= ThreadLocalRandom.current().nextDouble(100D); - } - - /** - * Return a chance of success in "percentage" format, show to the player in UI elements - * - * @param player target player - * @param subSkillType target subskill - * @param isLucky whether to apply luck modifiers - * - * @return "percentage" representation of success - */ - public static double chanceOfSuccessPercentage(@NotNull Player player, @NotNull SubSkillType subSkillType, boolean isLucky) { - Probability probability = SkillUtils.getSubSkillProbability(subSkillType, player); - //Probability values are on a 0-1 scale and need to be "transformed" into a 1-100 scale - double percentageValue = probability.getValue(); //Doesn't need to be scaled - - //Apply lucky modifier - if(isLucky) { - percentageValue *= LUCKY_MODIFIER; - } - - return percentageValue; - } - - public static double chanceOfSuccessPercentage(@NotNull Probability probability, boolean isLucky) { - //Probability values are on a 0-1 scale and need to be "transformed" into a 1-100 scale - double percentageValue = probability.getValue(); - - //Apply lucky modifier - if(isLucky) { - percentageValue *= LUCKY_MODIFIER; - } - - return percentageValue; - } - -} diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java index 9108e3e9c1..d685d231a2 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java @@ -8,17 +8,13 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; -import com.gmail.nossr50.events.skills.secondaryabilities.SubSkillEvent; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.metadata.ItemMetadataService; -import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.Misc; -import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; -import com.gmail.nossr50.util.random.*; import com.gmail.nossr50.util.text.StringUtils; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -356,127 +352,4 @@ public static int getRepairAndSalvageQuantities(Material itemMaterial, Material return quantity; } - - /** - * This is one of several Skill RNG check methods - * This helper method is for specific {@link SubSkillType}, which help mcMMO understand where the RNG values used in our calculations come from from this {@link SubSkillType} - * - * 1) Determine where the RNG values come from for the passed {@link SubSkillType} - * NOTE: In the config file, there are values which are static and which are more dynamic, this is currently a bit hardcoded and will need to be updated manually - * - * 2) Determine whether or not to use Lucky multiplier and influence the outcome - * - * 3) Creates a {@link Probability} and pipes it to {@link RandomChanceUtil} which processes the result and returns it - * - * This also calls a {@link SubSkillEvent} which can be cancelled, if it is cancelled this will return false - * The outcome of the probability can also be modified by this event that is called - * - * @param subSkillType target subskill - * @param player target player, can be null (null players are given odds equivalent to a player with no levels or luck) - * @return true if the Skill RNG succeeds, false if it fails - */ - public static boolean isSkillRNGSuccessful(@NotNull SubSkillType subSkillType, @NotNull Player player) { - //Process probability - Probability probability = getSubSkillProbability(subSkillType, player); - - //Send out event - SubSkillEvent subSkillEvent = EventUtils.callSubSkillEvent(player, subSkillType); - - if(subSkillEvent.isCancelled()) { - return false; //Event got cancelled so this doesn't succeed - } - - //Result modifier - double resultModifier = subSkillEvent.getResultModifier(); - - //Mutate probability - if(resultModifier != 1.0D) - probability = Probability.ofPercentageValue(probability.getValue() * resultModifier); - - //Luck - boolean isLucky = Permissions.lucky(player, subSkillType.getParentSkill()); - - if(isLucky) { - return RandomChanceUtil.processProbability(probability, RandomChanceUtil.LUCKY_MODIFIER); - } else { - return RandomChanceUtil.processProbability(probability); - } - } - - /** - * This is one of several Skill RNG check methods - * This helper method is specific to static value RNG, which can be influenced by a player's Luck - * - * @param primarySkillType the related primary skill - * @param player the target player, can be null (null players have the worst odds) - * @param probabilityPercentage the probability of this player succeeding in "percentage" format (0-100 inclusive) - * @return true if the RNG succeeds, false if it fails - */ - public static boolean isStaticSkillRNGSuccessful(@NotNull PrimarySkillType primarySkillType, @Nullable Player player, double probabilityPercentage) { - //Grab a probability converted from a "percentage" value - Probability probability = Probability.ofPercentageValue(probabilityPercentage); - - return isStaticSkillRNGSuccessful(primarySkillType, player, probability); - } - - /** - * This is one of several Skill RNG check methods - * This helper method is specific to static value RNG, which can be influenced by a player's Luck - * - * @param primarySkillType the related primary skill - * @param player the target player, can be null (null players have the worst odds) - * @param probability the probability of this player succeeding - * @return true if the RNG succeeds, false if it fails - */ - public static boolean isStaticSkillRNGSuccessful(@NotNull PrimarySkillType primarySkillType, @Nullable Player player, @NotNull Probability probability) { - boolean isLucky = player != null && Permissions.lucky(player, primarySkillType); - - if(isLucky) { - return RandomChanceUtil.processProbability(probability, RandomChanceUtil.LUCKY_MODIFIER); - } else { - return RandomChanceUtil.processProbability(probability); - } - } - - /** - * Skills activate without RNG, this allows other plugins to prevent that activation - * @param subSkillType target subskill - * @param player target player - * @return true if the skill succeeds (wasn't cancelled by any other plugin) - */ - public static boolean isNonRNGSkillActivationSuccessful(@NotNull SubSkillType subSkillType, @NotNull Player player) { - return !EventUtils.callSubSkillEvent(player, subSkillType).isCancelled(); - } - - /** - * Grab the {@link Probability} for a specific {@link SubSkillType} for a specific {@link Player} - * - * @param subSkillType target subskill - * @param player target player - * @return the Probability of this skill succeeding - * @throws InvalidStaticChance when a skill that does not have a hard coded static chance and it is asked for - * @throws RuntimeException - */ - public static @NotNull Probability getSubSkillProbability(@NotNull SubSkillType subSkillType, @Nullable Player player) { - SkillProbabilityType skillProbabilityType = SkillProbabilityType.DYNAMIC_CONFIGURABLE; - - if(subSkillType == SubSkillType.TAMING_FAST_FOOD_SERVICE || subSkillType == SubSkillType.AXES_ARMOR_IMPACT || subSkillType == SubSkillType.AXES_GREATER_IMPACT) - skillProbabilityType = SkillProbabilityType.STATIC_CONFIGURABLE; - - return Probability.ofSubSkill(player, subSkillType, skillProbabilityType); - } - - public static @NotNull String[] getRNGDisplayValues(@NotNull Player player, @NotNull SubSkillType subSkill) { - double firstValue = RandomChanceUtil.chanceOfSuccessPercentage(player, subSkill, false); - double secondValue = RandomChanceUtil.chanceOfSuccessPercentage(player, subSkill, true); - - return new String[]{RandomChanceUtil.percent.format(firstValue), RandomChanceUtil.percent.format(secondValue)}; - } - - public static @NotNull String[] getRNGDisplayValues(@NotNull Probability probability) { - double firstValue = RandomChanceUtil.chanceOfSuccessPercentage(probability, false); - double secondValue = RandomChanceUtil.chanceOfSuccessPercentage(probability, true); - - return new String[]{RandomChanceUtil.percent.format(firstValue), RandomChanceUtil.percent.format(secondValue)}; - } } diff --git a/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java b/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java index 41e8834651..ac551df40d 100644 --- a/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java +++ b/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java @@ -1,13 +1,15 @@ package com.gmail.nossr50.util.random; +import org.bukkit.entity.Player; +import org.junit.jupiter.api.BeforeEach; 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 org.mockito.Mockito; import java.util.stream.Stream; -import static com.gmail.nossr50.util.random.RandomChanceUtil.processProbability; import static org.junit.jupiter.api.Assertions.*; class ProbabilityTest { @@ -30,42 +32,62 @@ private static Stream provideProbabilitiesForWithinExpectations() { Arguments.of(new ProbabilityImpl(1000), 100) ); } - @Test - void testIsSuccessfulRollSucceeds() { - Probability probability = new ProbabilityImpl(100); + private static Stream 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(processProbability(probability)); + assertTrue(new ProbabilityImpl(100).evaluate()); } } @Test - void testIsSuccessfulRollFails() { - Probability probability = new ProbabilityImpl(0); - + void testAlwaysLoseConstructor() { for (int i = 0; i < 100000; i++) { - assertFalse(processProbability(probability)); + assertFalse(new ProbabilityImpl(0).evaluate()); } } @Test - void testIsSuccessfulRollFailsOfPercentage() { - Probability probability = Probability.ofPercentageValue(100); + 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(processProbability(probability)); + assertFalse(Probability.ofPercent(0).evaluate()); } } @ParameterizedTest @MethodSource("provideProbabilitiesForWithinExpectations") - void testProcessProbabilityWithinExpectations(Probability probability, double expectedWinPercent) { + void testOddsExpectationsImplConstructor(Probability probability, double expectedWinPercent) { // Probabilities are tested 200,000,000 times with a margin of error of 0.01% int iterations = 200000000; double winCount = 0; for (int i = 0; i < iterations; i++) { - if(processProbability(probability)) { + if(probability.evaluate()) { winCount++; } } @@ -75,11 +97,21 @@ void testProcessProbabilityWithinExpectations(Probability probability, double ex assertEquals(expectedWinPercent, successPercent, 0.01D); } - @Test - void ofPercentageValue() { - } + @ParameterizedTest + @MethodSource("provideOfPercentageProbabilitiesForWithinExpectations") + void testOddsExpectationsOfPercent(Probability probability, double expectedWinPercent) { + // Probabilities are tested 200,000,000 times with a margin of error of 0.01% + int iterations = 200000000; + double winCount = 0; - @Test - void ofSubSkill() { + 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.01D); } -} \ No newline at end of file +} diff --git a/src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java b/src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java new file mode 100644 index 0000000000..63844bb248 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java @@ -0,0 +1,22 @@ +package com.gmail.nossr50.util.random; + +import org.bukkit.entity.Player; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +class ProbabilityUtilTest { + + // Mocks + Player player; + + @BeforeEach + public void setupMocks() { + this.player = Mockito.mock(Player.class); + } + + @Test + public void testChanceOfSuccessPercentage() { + + } +} \ No newline at end of file diff --git a/src/test/java/com/gmail/nossr50/util/skills/SkillToolsTest.java b/src/test/java/com/gmail/nossr50/util/skills/SkillToolsTest.java deleted file mode 100644 index 4a295d5d31..0000000000 --- a/src/test/java/com/gmail/nossr50/util/skills/SkillToolsTest.java +++ /dev/null @@ -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 { -// -//} \ No newline at end of file From 4a5e3542ef1b0c23e093ee6f4417cdfa43153014 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 18 Dec 2022 16:49:30 -0800 Subject: [PATCH 20/75] Add static chance skills to probability unit tests --- .../nossr50/util/random/ProbabilityUtil.java | 10 ++-- .../nossr50/util/random/ProbabilityTest.java | 4 +- .../util/random/ProbabilityUtilTest.java | 58 ++++++++++++++++--- 3 files changed, 57 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/util/random/ProbabilityUtil.java b/src/main/java/com/gmail/nossr50/util/random/ProbabilityUtil.java index a625260fda..55d6950b62 100644 --- a/src/main/java/com/gmail/nossr50/util/random/ProbabilityUtil.java +++ b/src/main/java/com/gmail/nossr50/util/random/ProbabilityUtil.java @@ -54,11 +54,11 @@ public static double chanceOfSuccessPercentage(@NotNull Probability probability, return percentageValue; } - static double getStaticRandomChance(@NotNull SubSkillType subSkillType) throws InvalidStaticChance { + static Probability getStaticRandomChance(@NotNull SubSkillType subSkillType) throws InvalidStaticChance { return switch (subSkillType) { - case AXES_ARMOR_IMPACT -> mcMMO.p.getAdvancedConfig().getImpactChance(); - case AXES_GREATER_IMPACT -> mcMMO.p.getAdvancedConfig().getGreaterImpactChance(); - case TAMING_FAST_FOOD_SERVICE -> mcMMO.p.getAdvancedConfig().getFastFoodChance(); + case AXES_ARMOR_IMPACT -> Probability.ofPercent(mcMMO.p.getAdvancedConfig().getImpactChance()); + case AXES_GREATER_IMPACT -> Probability.ofPercent(mcMMO.p.getAdvancedConfig().getGreaterImpactChance()); + case TAMING_FAST_FOOD_SERVICE -> Probability.ofPercent(mcMMO.p.getAdvancedConfig().getFastFoodChance()); default -> throw new InvalidStaticChance(); }; } @@ -99,7 +99,7 @@ static SkillProbabilityType getProbabilityType(@NotNull SubSkillType subSkillTyp return new ProbabilityImpl(xPos, xCeiling, probabilityCeiling); case STATIC_CONFIGURABLE: try { - return Probability.ofPercent(getStaticRandomChance(subSkillType)); + return getStaticRandomChance(subSkillType); } catch (InvalidStaticChance invalidStaticChance) { invalidStaticChance.printStackTrace(); } diff --git a/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java b/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java index ac551df40d..a454d5b204 100644 --- a/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java +++ b/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java @@ -100,8 +100,8 @@ void testOddsExpectationsImplConstructor(Probability probability, double expecte @ParameterizedTest @MethodSource("provideOfPercentageProbabilitiesForWithinExpectations") void testOddsExpectationsOfPercent(Probability probability, double expectedWinPercent) { - // Probabilities are tested 200,000,000 times with a margin of error of 0.01% - int iterations = 200000000; + // Probabilities are tested 2.0 x 10^9 with a margin of error of 0.01% + double iterations = 2.0e9; double winCount = 0; for (int i = 0; i < iterations; i++) { diff --git a/src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java b/src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java index 63844bb248..9bb78fcf04 100644 --- a/src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java +++ b/src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java @@ -1,22 +1,64 @@ package com.gmail.nossr50.util.random; -import org.bukkit.entity.Player; +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.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mockito; +import java.util.stream.Stream; + +import static com.gmail.nossr50.datatypes.skills.SubSkillType.*; +import static org.junit.jupiter.api.Assertions.assertEquals; + class ProbabilityUtilTest { - // Mocks - Player player; + 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() { - this.player = Mockito.mock(Player.class); + public void setupMocks() throws NoSuchFieldException, IllegalAccessException { + this.mmoInstance = Mockito.mock(mcMMO.class); + mcMMO.class.getField("p").set(null, mmoInstance); + this.advancedConfig = Mockito.mock(AdvancedConfig.class); + Mockito.when(mmoInstance.getAdvancedConfig()).thenReturn(advancedConfig); + Mockito.when(advancedConfig.getImpactChance()).thenReturn(impactChance); + Mockito.when(advancedConfig.getGreaterImpactChance()).thenReturn(greaterImpactChance); + Mockito.when(advancedConfig.getFastFoodChance()).thenReturn(fastFoodChance); } - @Test - public void testChanceOfSuccessPercentage() { + private static Stream 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 { + // Probabilities are tested 2.0 x 10^9 with a margin of error of 0.01% + double iterations = 2.0e9; + double winCount = 0; + + Probability staticRandomChance = ProbabilityUtil.getStaticRandomChance(subSkillType); + for (int i = 0; i < iterations; i++) { + if(staticRandomChance.evaluate()) { + winCount++; + } + } + double successPercent = (winCount / iterations) * 100; + System.out.println(successPercent + ", " + expectedWinPercent); + assertEquals(expectedWinPercent, successPercent, 0.01D); } } \ No newline at end of file From 12fb4a367987df26f6bb23d27893c1cfa41639de Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 18 Dec 2022 17:08:36 -0800 Subject: [PATCH 21/75] Refactor probability tests a little bit --- .../skills/subskills/acrobatics/Roll.java | 13 +++++-- .../nossr50/util/random/ProbabilityTest.java | 26 ++++---------- .../util/random/ProbabilityUtilTest.java | 34 +++++++++++-------- 3 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java index 40285c48e7..bc6ca79881 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java @@ -33,6 +33,7 @@ import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.VisibleForTesting; import java.util.Locale; @@ -198,7 +199,8 @@ private boolean canRoll(Player player) { * @param damage The amount of damage initially dealt by the event * @return the modified event damage if the ability was successful, the original event damage otherwise */ - private double rollCheck(Player player, McMMOPlayer mcMMOPlayer, double damage) { + @VisibleForTesting + public double rollCheck(Player player, McMMOPlayer mcMMOPlayer, double damage) { int skillLevel = mcMMOPlayer.getSkillLevel(getPrimarySkill()); @@ -246,8 +248,7 @@ private int getActivationChance(McMMOPlayer mcMMOPlayer) { private double gracefulRollCheck(Player player, McMMOPlayer mcMMOPlayer, double damage, int skillLevel) { double modifiedDamage = calculateModifiedRollDamage(damage, mcMMO.p.getAdvancedConfig().getRollDamageThreshold() * 2); - double gracefulOdds = ProbabilityUtil.getSubSkillProbability(subSkillType, player).getValue() * 2; - Probability gracefulProbability = Probability.ofPercent(gracefulOdds); + Probability gracefulProbability = getGracefulProbability(player); if (!isFatal(player, modifiedDamage) //TODO: Graceful isn't sending out an event @@ -271,6 +272,12 @@ else if (!isFatal(player, damage)) { return damage; } + @NotNull + public static Probability getGracefulProbability(Player player) { + double gracefulOdds = ProbabilityUtil.getSubSkillProbability(SubSkillType.ACROBATICS_ROLL, player).getValue() * 2; + return Probability.ofPercent(gracefulOdds); + } + /** * Check if the player is "farming" Acrobatics XP using * exploits in the game. diff --git a/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java b/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java index a454d5b204..d401827347 100644 --- a/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java +++ b/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java @@ -1,12 +1,9 @@ package com.gmail.nossr50.util.random; -import org.bukkit.entity.Player; -import org.junit.jupiter.api.BeforeEach; 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 org.mockito.Mockito; import java.util.stream.Stream; @@ -82,26 +79,17 @@ void testAlwaysLoseOfPercent() { @ParameterizedTest @MethodSource("provideProbabilitiesForWithinExpectations") void testOddsExpectationsImplConstructor(Probability probability, double expectedWinPercent) { - // Probabilities are tested 200,000,000 times with a margin of error of 0.01% - int iterations = 200000000; - 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.01D); + assertExpectations(probability, expectedWinPercent); } @ParameterizedTest @MethodSource("provideOfPercentageProbabilitiesForWithinExpectations") void testOddsExpectationsOfPercent(Probability probability, double expectedWinPercent) { - // Probabilities are tested 2.0 x 10^9 with a margin of error of 0.01% - double iterations = 2.0e9; + 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++) { @@ -112,6 +100,6 @@ void testOddsExpectationsOfPercent(Probability probability, double expectedWinPe double successPercent = (winCount / iterations) * 100; System.out.println(successPercent + ", " + expectedWinPercent); - assertEquals(expectedWinPercent, successPercent, 0.01D); + assertEquals(expectedWinPercent, successPercent, 0.05D); } } diff --git a/src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java b/src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java index 9bb78fcf04..1a12913de7 100644 --- a/src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java +++ b/src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java @@ -1,18 +1,22 @@ package com.gmail.nossr50.util.random; import com.gmail.nossr50.config.AdvancedConfig; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.mcMMO; +import org.bukkit.entity.Player; import org.junit.jupiter.api.BeforeEach; +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 org.mockito.Mockito; 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 { @@ -25,13 +29,13 @@ class ProbabilityUtilTest { @BeforeEach public void setupMocks() throws NoSuchFieldException, IllegalAccessException { - this.mmoInstance = Mockito.mock(mcMMO.class); + this.mmoInstance = mock(mcMMO.class); mcMMO.class.getField("p").set(null, mmoInstance); - this.advancedConfig = Mockito.mock(AdvancedConfig.class); - Mockito.when(mmoInstance.getAdvancedConfig()).thenReturn(advancedConfig); - Mockito.when(advancedConfig.getImpactChance()).thenReturn(impactChance); - Mockito.when(advancedConfig.getGreaterImpactChance()).thenReturn(greaterImpactChance); - Mockito.when(advancedConfig.getFastFoodChance()).thenReturn(fastFoodChance); + 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 staticChanceSkills() { @@ -46,19 +50,21 @@ private static Stream staticChanceSkills() { @ParameterizedTest @MethodSource("staticChanceSkills") void testStaticChanceSkills(SubSkillType subSkillType, double expectedWinPercent) throws InvalidStaticChance { - // Probabilities are tested 2.0 x 10^9 with a margin of error of 0.01% - double iterations = 2.0e9; - double winCount = 0; - 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(staticRandomChance.evaluate()) { + if(probability.evaluate()) { winCount++; } } double successPercent = (winCount / iterations) * 100; System.out.println(successPercent + ", " + expectedWinPercent); - assertEquals(expectedWinPercent, successPercent, 0.01D); + assertEquals(expectedWinPercent, successPercent, 0.05D); } -} \ No newline at end of file +} From e4470fd0614194a2032ebcfa327368f04a145622 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sat, 18 Feb 2023 23:44:01 -0800 Subject: [PATCH 22/75] More work on end game skills --- Changelog.txt | 33 ++++++++----------- .../commands/skills/HerbalismCommand.java | 7 ++++ .../commands/skills/MiningCommand.java | 9 +++-- .../datatypes/skills/SubSkillType.java | 4 +-- .../nossr50/skills/mining/MiningManager.java | 2 +- .../gmail/nossr50/util/skills/RankUtils.java | 5 ++- src/main/resources/advanced.yml | 11 +++++-- .../resources/locale/locale_en_US.properties | 9 +++-- src/main/resources/plugin.yml | 4 +-- src/main/resources/skillranks.yml | 10 ++++++ 10 files changed, 57 insertions(+), 37 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index adacbc2e81..49e7d1422f 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,29 +1,16 @@ Version 2.2.000 - Updated Adventure (our text dependency) fixes some errors when using color codes in party/admin chat (thanks TheBusyBiscuit) - Added some support for negative Y values in anticipation of 1.17 world height changes (thanks t00thpick1) (API) 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 Treasure drop rate from Shake, Fishing, Hylian, and Excavation now benefit from the Luck perk - Added a setting to chat.yml to toggle sending party or admin chat messages to console + Added 'Send_To_Console' settings to chat.yml to toggle sending party or admin chat messages to console Added a set of "mastery" subskills meant for end game progression Added the mastery subskill 'Mother Lode' to Mining Added the mastery subskill 'Clean Cuts' to Woodcutting + Added the mastery subskill 'Verdant Bounty' to Herbalism + All new skills have had settings added to advanced.yml Added /mmopower command (aliases /mmopowerlevel /powerlevel) Added 'mcmmo.commands.mmopower' permission node - Added 'mcmmo.ability.acrobatics.mastery' permission node - Added 'mcmmo.ability.alchemy.mastery' permission node - Added 'mcmmo.ability.archery.mastery' permission node - Added 'mcmmo.ability.axes.mastery' permission node - Added 'mcmmo.ability.excavation.mastery' permission node - Added 'mcmmo.ability.fishing.mastery' permission node - Added 'mcmmo.ability.herbalism.mastery' permission node + Added 'mcmmo.ability.herbalism.verdantbounty' permission node Added 'mcmmo.ability.mining.motherlode' permission node - Added 'mcmmo.ability.repair.mastery' permission node - Added 'mcmmo.ability.salvage.mastery' permission node - Added 'mcmmo.ability.smelting.mastery' permission node - Added 'mcmmo.ability.salvage.mastery' permission node - Added 'mcmmo.ability.swords.mastery' permission node - Added 'mcmmo.ability.taming.mastery' permission node - Added 'mcmmo.ability.unarmed.mastery' permission node Added 'mcmmo.ability.woodcutting.cleancuts' permission node Added 'Mining.SubSkill.MotherLode.Name' to locale Added 'Mining.SubSkill.MotherLode.Stat' to locale @@ -31,9 +18,12 @@ Version 2.2.000 Added 'Woodcutting.SubSkill.CleanCuts.Name' to locale Added 'Woodcutting.SubSkill.CleanCuts.Stat' to locale Added 'Woodcutting.SubSkill.CleanCuts.Description' to locale - (Codebase) Major refactoring for how random chance was handled in the code + Added 'Herbalism.SubSkill.VerdantBounty.Name' to locale + Added 'Herbalism.SubSkill.VerdantBounty.Stat' to locale + Added 'Herbalism.SubSkill.VerdantBounty.Description' to locale + (Codebase) Major rewrite for how random chance was handled in the code - Added 'General.PowerLevel.Skill_Mastery.Enabled' to config.yml which is used to enable or disable the mastery skills (will also disable the new power level command) + Added 'General.PowerLevel.Skill_Mastery.Enabled' to config.yml which is used to enable or disable the mastery skills wholesale (will also disable the new power level command) NOTES: The goal of this update is to provide a small benefit to each skill and a reason to grind past the "maximum", ideally for a long while. @@ -47,12 +37,15 @@ Version 2.2.000 Mastery Skills Mining / Mother Lode: With default settings, when players hit level 1,000 they will unlock this sub-skill, it will add a 1% chance to get triple drops while mining (this can be edited in advanced.yml), this skill maxes out at 10.0% chance at level 10,000. This skill respects double drop settings from the config files. - Double Drops only occur if the Triple Drops fail, these two skills do not stack. + Double drops will only get checked if the Triple Drops fail for players that have Mother Lode unlocked, these two skills do not stack. Woodcutting / Clean Cuts: With default settings, when players hit level 1,000 they will unlock this sub-skill, it will add a 1% chance to get triple drops while woodcutting or using Tree Feller (this can be edited in advanced.yml), this skill maxes out at 10.0% chance at level 10,000. This skill respects double drop settings from the config files. Double Drops (Harvest Lumber) will only get checked if the Triple Drops fail for players that have Clean Cuts unlocked, these two skills do not stack. + Herbalism / Verdant Bounty: With default settings, when players hit level 1,000 they will unlock this sub-skill, it will add a 1% chance to get triple drops when harvesting crops (this can be edited in advanced.yml), this skill maxes out at 10.0% chance at level 10,000. + This skill respects double drop settings from the config files. + Double Drops only occur if the Triple Drops fail, these two skills do not stack. New Power Level Command This power level command gives you a view of all your current masteries, it also provides a summary of your power level. diff --git a/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java index 3df385974b..eeb1bdd59f 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java @@ -35,6 +35,7 @@ public class HerbalismCommand extends SkillCommand { private boolean canGreenThumbBlocks; private boolean canFarmersDiet; private boolean canDoubleDrop; + private boolean canTripleDrop; private boolean canShroomThumb; public HerbalismCommand() { @@ -50,6 +51,12 @@ protected void dataCalculations(Player player, float skillValue) { doubleDropChance = doubleDropStrings[0]; doubleDropChanceLucky = doubleDropStrings[1]; } + + if (canTripleDrop) { + String[] tripleDropStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.HERBALISM_VERDANT_BOUNTY); + doubleDropChance = tripleDropStrings[0]; + doubleDropChanceLucky = tripleDropStrings[1]; + } // FARMERS DIET if (canFarmersDiet) { diff --git a/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java index 72be89643d..b756dd2823 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java @@ -32,7 +32,7 @@ public class MiningCommand extends SkillCommand { private boolean canSuperBreaker; private boolean canDoubleDrop; - private boolean canMotherLode; + private boolean canTripleDrop; private boolean canBlast; private boolean canBiggerBombs; private boolean canDemoExpert; @@ -56,7 +56,7 @@ protected void dataCalculations(Player player, float skillValue) { } // Mastery TRIPLE DROPS - if (canMotherLode) { + if (canTripleDrop) { String[] masteryTripleDropStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.MINING_MOTHER_LODE); tripleDropChance = masteryTripleDropStrings[0]; tripleDropChanceLucky = masteryTripleDropStrings[1]; @@ -83,7 +83,7 @@ protected void permissionsCheck(Player player) { canBlast = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_BLAST_MINING) && Permissions.remoteDetonation(player); canDemoExpert = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_DEMOLITIONS_EXPERTISE) && Permissions.demolitionsExpertise(player); canDoubleDrop = Permissions.canUseSubSkill(player, SubSkillType.MINING_DOUBLE_DROPS); - canMotherLode = Permissions.canUseSubSkill(player, SubSkillType.MINING_MOTHER_LODE); + canTripleDrop = Permissions.canUseSubSkill(player, SubSkillType.MINING_MOTHER_LODE); canSuperBreaker = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_SUPER_BREAKER) && Permissions.superBreaker(player); } @@ -112,12 +112,11 @@ protected List statsDisplay(Player player, float skillValue, boolean has //messages.add(LocaleLoader.getString("Mining.Effect.DropChance", doubleDropChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", doubleDropChanceLucky) : "")); } - if(canMotherLode) { + if(canTripleDrop) { messages.add(getStatMessage(SubSkillType.MINING_MOTHER_LODE, tripleDropChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", tripleDropChanceLucky) : "")); } - if (canSuperBreaker) { messages.add(getStatMessage(SubSkillType.MINING_SUPER_BREAKER, superBreakerLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", superBreakerLengthEndurance) : "")); diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java index c5d95445a5..c8f4cc9260 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java @@ -38,7 +38,6 @@ public enum SubSkillType { /* Excavation */ EXCAVATION_ARCHAEOLOGY(8), EXCAVATION_GIGA_DRILL_BREAKER(1), - EXCAVATION_MASTERY(1), /* Fishing */ FISHING_FISHERMANS_DIET(5), @@ -51,6 +50,7 @@ public enum SubSkillType { /* Herbalism */ HERBALISM_DOUBLE_DROPS(1), + HERBALISM_VERDANT_BOUNTY(1), HERBALISM_FARMERS_DIET(5), HERBALISM_GREEN_TERRA(1), HERBALISM_GREEN_THUMB(4), @@ -147,7 +147,7 @@ public int getNumRanks() /** * !!! This relies on the immutable lists in PrimarySkillType being populated !!! * If we add skills, those immutable lists need to be updated - * @return + * @return the parent skill of this subskill */ public PrimarySkillType getParentSkill() { return mcMMO.p.getSkillTools().getPrimarySkillBySubSkill(this); } diff --git a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java index 91197cc03d..a9e6e3b824 100644 --- a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java +++ b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java @@ -35,7 +35,7 @@ public class MiningManager extends SkillManager { public static final String BUDDING_AMETHYST = "budding_amethyst"; - public MiningManager(McMMOPlayer mcMMOPlayer) { + public MiningManager(@NotNull McMMOPlayer mcMMOPlayer) { super(mcMMOPlayer, PrimarySkillType.MINING); } diff --git a/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java b/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java index c36821cc72..6d8b310669 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java @@ -24,7 +24,7 @@ public class RankUtils { * * @param plugin plugin instance ref * @param mcMMOPlayer target player - * @param primarySkillType + * @param primarySkillType the skill to check * @param newLevel the new level of this skill */ public static void executeSkillUnlockNotifications(Plugin plugin, McMMOPlayer mcMMOPlayer, PrimarySkillType primarySkillType, int newLevel) @@ -55,6 +55,9 @@ public static void executeSkillUnlockNotifications(Plugin plugin, McMMOPlayer mc } } + /** + * Reset the interval between skill unlock notifications + */ public static void resetUnlockDelayTimer() { count = 0; diff --git a/src/main/resources/advanced.yml b/src/main/resources/advanced.yml index 3fe4585de5..087445f52a 100644 --- a/src/main/resources/advanced.yml +++ b/src/main/resources/advanced.yml @@ -257,6 +257,11 @@ Skills: MaxBonusLevel: Standard: 100 RetroMode: 1000 + VerdantBounty: + ChanceMax: 15.0 + MaxBonusLevel: + Standard: 1000 + RetroMode: 10000 HylianLuck: # ChanceMax: Maximum chance of Hylian Luck when on or higher @@ -281,7 +286,7 @@ Skills: MaxBonusLevel: Standard: 1000 RetroMode: 10000 - ChanceMax: 10.0 + ChanceMax: 15.0 SuperBreaker: AllowTripleDrops: true DoubleDrops: @@ -606,9 +611,9 @@ Skills: # Triple Drops CleanCuts: - # ChanceMax: Maximum chance of receiving double drops (100 = 100%) + # ChanceMax: Maximum chance of receiving triple drops (100 = 100%) # MaxBonusLevel: Level when the maximum chance of receiving double drops is reached - ChanceMax: 10.0 + ChanceMax: 15.0 MaxBonusLevel: Standard: 1000 RetroMode: 10000 diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 6b0886b12a..35ec18c3cd 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -285,8 +285,11 @@ Herbalism.SubSkill.FarmersDiet.Name=Farmer's Diet Herbalism.SubSkill.FarmersDiet.Description=Improves hunger restored from farmed foods Herbalism.SubSkill.FarmersDiet.Stat=Farmer's Diet: &aRank {0} Herbalism.SubSkill.DoubleDrops.Name=Double Drops -Herbalism.SubSkill.DoubleDrops.Description=Double the normal loot +Herbalism.SubSkill.DoubleDrops.Description=Skillfully harvest double the loot Herbalism.SubSkill.DoubleDrops.Stat=Double Drop Chance +Herbalism.SubSkill.VerdantBounty.Name=Verdant Bounty +Herbalism.SubSkill.VerdantBounty.Description=Masterfully harvest triple the loot +Herbalism.SubSkill.VerdantBounty.Stat=Triple Drop Chance Herbalism.SubSkill.HylianLuck.Name=Hylian Luck Herbalism.SubSkill.HylianLuck.Description=Gives a small chance of finding rare items Herbalism.SubSkill.HylianLuck.Stat=Hylian Luck Chance @@ -311,10 +314,10 @@ Mining.SubSkill.SuperBreaker.Name=Super Breaker Mining.SubSkill.SuperBreaker.Description=Speed+, Triple Drop Chance Mining.SubSkill.SuperBreaker.Stat=Super Breaker Length Mining.SubSkill.DoubleDrops.Name=Double Drops -Mining.SubSkill.DoubleDrops.Description=Double the normal loot +Mining.SubSkill.DoubleDrops.Description=Skillfully mine double the loot Mining.SubSkill.DoubleDrops.Stat=Double Drop Chance Mining.SubSkill.MotherLode.Name=Mother Lode -Mining.SubSkill.MotherLode.Description=Triple the normal loot +Mining.SubSkill.MotherLode.Description=Masterfully mine triple the loot Mining.SubSkill.MotherLode.Stat=Triple Drop Chance Mining.SubSkill.BlastMining.Name=Blast Mining Mining.SubSkill.BlastMining.Description=Bonuses to mining with TNT diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index b6b190b66f..41bfa187a5 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -397,8 +397,8 @@ permissions: mcmmo.ability.herbalism.greenthumb.all: true mcmmo.ability.herbalism.hylianluck: true mcmmo.ability.herbalism.shroomthumb: true - mcmmo.ability.herbalism.mastery: true - mcmmo.ability.herbalism.mastery: + mcmmo.ability.herbalism.verdantbounty: true + mcmmo.ability.herbalism.verdantbounty: description: Allows access to end game progression for Herbalism mcmmo.ability.herbalism.doubledrops: description: Allows double drop chance from Herbalism diff --git a/src/main/resources/skillranks.yml b/src/main/resources/skillranks.yml index df742e81a2..fa300973b9 100644 --- a/src/main/resources/skillranks.yml +++ b/src/main/resources/skillranks.yml @@ -413,6 +413,11 @@ Herbalism: Rank_1: 1 RetroMode: Rank_1: 1 + VerdantBounty: + Standard: + Rank_1: 100 + RetroMode: + Rank_1: 1000 GreenTerra: Standard: Rank_1: 5 @@ -688,6 +693,11 @@ Woodcutting: Rank_1: 1 RetroMode: Rank_1: 1 + CleanCuts: + Standard: + Rank_1: 100 + RetroMode: + Rank_1: 1000 KnockOnWood: Standard: Rank_1: 30 From 36adde7b3dc1cf98020eb65b061f04638f8b5aed Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 19 Mar 2023 20:18:17 -0700 Subject: [PATCH 23/75] Added some unit tests for double drops, fixed bug with bonus drops --- .../nossr50/commands/CommandManager.java | 3 +- .../java/com/gmail/nossr50/config/Config.java | 605 ------------------ .../gmail/nossr50/config/GeneralConfig.java | 2 + .../skills/subskills/acrobatics/Roll.java | 2 +- .../woodcutting/WoodcuttingManager.java | 9 +- .../com/gmail/nossr50/util/Permissions.java | 1 - .../nossr50/util/random/Probability.java | 2 +- .../nossr50/util/random/ProbabilityUtil.java | 5 +- .../util/text/TextComponentFactory.java | 62 +- .../woodcutting/WoodcuttingManagerTest.java | 218 +++++++ 10 files changed, 262 insertions(+), 647 deletions(-) delete mode 100644 src/main/java/com/gmail/nossr50/config/Config.java create mode 100644 src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManagerTest.java diff --git a/src/main/java/com/gmail/nossr50/commands/CommandManager.java b/src/main/java/com/gmail/nossr50/commands/CommandManager.java index b1bb5abf4a..0fe58d12fc 100644 --- a/src/main/java/com/gmail/nossr50/commands/CommandManager.java +++ b/src/main/java/com/gmail/nossr50/commands/CommandManager.java @@ -7,7 +7,6 @@ import com.gmail.nossr50.commands.chat.PartyChatCommand; import com.gmail.nossr50.commands.skills.PowerLevelCommand; import com.gmail.nossr50.config.ChatConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.chat.ChatChannel; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; @@ -48,7 +47,7 @@ private void registerCommands() { } private void registerSkillCommands() { - if(Config.getInstance().isMasterySystemEnabled()) { + if(mcMMO.p.getGeneralConfig().isMasterySystemEnabled()) { bukkitCommandManager.registerCommand(new PowerLevelCommand(pluginRef)); } } diff --git a/src/main/java/com/gmail/nossr50/config/Config.java b/src/main/java/com/gmail/nossr50/config/Config.java deleted file mode 100644 index 9e43be65c8..0000000000 --- a/src/main/java/com/gmail/nossr50/config/Config.java +++ /dev/null @@ -1,605 +0,0 @@ -package com.gmail.nossr50.config; - -import com.gmail.nossr50.database.SQLDatabaseManager.PoolIdentifier; -import com.gmail.nossr50.datatypes.MobHealthbarType; -import com.gmail.nossr50.datatypes.party.PartyFeature; -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -import com.gmail.nossr50.datatypes.skills.SuperAbilityType; -import com.gmail.nossr50.util.text.StringUtils; -import org.bukkit.Material; -import org.bukkit.block.data.BlockData; -import org.bukkit.configuration.ConfigurationSection; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.Set; - -public class Config extends AutoUpdateConfigLoader { - private static Config instance; - - private Config() { - super("config.yml"); - validate(); - } - - public static Config getInstance() { - if (instance == null) { - instance = new Config(); - } - - return instance; - } - - @Override - protected void loadKeys() { - - } - - @Override - protected boolean validateKeys() { - // Validate all the settings! - List reason = new ArrayList<>(); - - /* General Settings */ - if (getSaveInterval() <= 0) { - reason.add("General.Save_Interval should be greater than 0!"); - } - - /* MySQL Settings */ - for (PoolIdentifier identifier : PoolIdentifier.values()) { - if (getMySQLMaxConnections(identifier) <= 0) { - reason.add("MySQL.Database.MaxConnections." + StringUtils.getCapitalized(identifier.toString()) + " should be greater than 0!"); - } - if (getMySQLMaxPoolSize(identifier) <= 0) { - reason.add("MySQL.Database.MaxPoolSize." + StringUtils.getCapitalized(identifier.toString()) + " should be greater than 0!"); - } - } - - /* Mob Healthbar */ - if (getMobHealthbarTime() == 0) { - reason.add("Mob_Healthbar.Display_Time cannot be 0! Set to -1 to disable or set a valid value."); - } - - /* Scoreboards */ - /*if (getRankScoreboardTime() != -1 && getRankScoreboardTime() <= 0) { - reason.add("Scoreboard.Types.Rank.Display_Time should be greater than 0, or -1!"); - } - - if (getStatsScoreboardTime() != -1 && getStatsScoreboardTime() <= 0) { - reason.add("Scoreboard.Types.Stats.Display_Time should be greater than 0, or -1!"); - } - - if (getTopScoreboardTime() != -1 && getTopScoreboardTime() <= 0) { - reason.add("Scoreboard.Types.Top.Display_Time should be greater than 0, or -1!"); - } - - if (getInspectScoreboardTime() != -1 && getInspectScoreboardTime() <= 0) { - reason.add("Scoreboard.Types.Inspect.Display_Time should be greater than 0, or -1!"); - } - - if (getSkillScoreboardTime() != -1 && getSkillScoreboardTime() <= 0) { - reason.add("Scoreboard.Types.Skill.Display_Time should be greater than 0, or -1!"); - } - - if (getSkillLevelUpTime() != -1 && getSkillScoreboardTime() <= 0) { - reason.add("Scoreboard.Types.Skill.Display_Time should be greater than 0, or -1!"); - } - - if (!(getRankUseChat() || getRankUseBoard())) { - reason.add("Either Board or Print in Scoreboard.Types.Rank must be true!"); - } - - if (!(getTopUseChat() || getTopUseBoard())) { - reason.add("Either Board or Print in Scoreboard.Types.Top must be true!"); - } - - if (!(getStatsUseChat() || getStatsUseBoard())) { - reason.add("Either Board or Print in Scoreboard.Types.Stats must be true!"); - } - - if (!(getInspectUseChat() || getInspectUseBoard())) { - reason.add("Either Board or Print in Scoreboard.Types.Inspect must be true!"); - }*/ - - /* Database Purging */ - if (getPurgeInterval() < -1) { - reason.add("Database_Purging.Purge_Interval should be greater than, or equal to -1!"); - } - - if (getOldUsersCutoff() != -1 && getOldUsersCutoff() <= 0) { - reason.add("Database_Purging.Old_User_Cutoff should be greater than 0 or -1!"); - } - - /* Hardcore Mode */ - if (getHardcoreDeathStatPenaltyPercentage() < 0.01 || getHardcoreDeathStatPenaltyPercentage() > 100) { - reason.add("Hardcore.Death_Stat_Loss.Penalty_Percentage only accepts values from 0.01 to 100!"); - } - - if (getHardcoreVampirismStatLeechPercentage() < 0.01 || getHardcoreVampirismStatLeechPercentage() > 100) { - reason.add("Hardcore.Vampirism.Leech_Percentage only accepts values from 0.01 to 100!"); - } - - /* Items */ - if (getChimaeraUseCost() < 1 || getChimaeraUseCost() > 64) { - reason.add("Items.Chimaera_Wing.Use_Cost only accepts values from 1 to 64!"); - } - - if (getChimaeraRecipeCost() < 1 || getChimaeraRecipeCost() > 9) { - reason.add("Items.Chimaera_Wing.Recipe_Cost only accepts values from 1 to 9!"); - } - - if (getChimaeraItem() == null) { - reason.add("Items.Chimaera_Wing.Item_Name is invalid!"); - } - - /* Particles */ - if (getLevelUpEffectsTier() < 1) { - reason.add("Particles.LevelUp_Tier should be at least 1!"); - } - - /* PARTY SETTINGS */ - if (getAutoPartyKickInterval() < -1) { - reason.add("Party.AutoKick_Interval should be at least -1!"); - } - - if (getAutoPartyKickTime() < 0) { - reason.add("Party.Old_Party_Member_Cutoff should be at least 0!"); - } - - if (getPartyShareBonusBase() <= 0) { - reason.add("Party.Sharing.ExpShare_bonus_base should be greater than 0!"); - } - - if (getPartyShareBonusIncrease() < 0) { - reason.add("Party.Sharing.ExpShare_bonus_increase should be at least 0!"); - } - - if (getPartyShareBonusCap() <= 0) { - reason.add("Party.Sharing.ExpShare_bonus_cap should be greater than 0!"); - } - - if (getPartyShareRange() <= 0) { - reason.add("Party.Sharing.Range should be greater than 0!"); - } - - if (getPartyXpCurveMultiplier() < 1) { - reason.add("Party.Leveling.Xp_Curve_Modifier should be at least 1!"); - } - - for (PartyFeature partyFeature : PartyFeature.values()) { - if (getPartyFeatureUnlockLevel(partyFeature) < 0) { - reason.add("Party.Leveling." + StringUtils.getPrettyPartyFeatureString(partyFeature).replace(" ", "") + "_UnlockLevel should be at least 0!"); - } - } - - /* Inspect command distance */ - if (getInspectDistance() <= 0) { - reason.add("Commands.inspect.Max_Distance should be greater than 0!"); - } - - if (getTreeFellerThreshold() <= 0) { - reason.add("Abilities.Limits.Tree_Feller_Threshold should be greater than 0!"); - } - - if (getFishingLureModifier() < 0) { - reason.add("Abilities.Fishing.Lure_Modifier should be at least 0!"); - } - - if (getRepairAnvilMaterial() == null) { - reason.add("Skills.Repair.Anvil_Type is invalid!!"); - } - - if (getSalvageAnvilMaterial() == null) { - reason.add("Skills.Repair.Salvage_Anvil_Type is invalid!"); - } - - if (getRepairAnvilMaterial() == getSalvageAnvilMaterial()) { - reason.add("Cannot use the same item for Repair and Salvage anvils!"); - } - -// if (getTamingCOTWMaterial(EntityType.WOLF) == null) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Item_Material is invalid!!"); -// } -// -// if (getTamingCOTWMaterial(EntityType.OCELOT) == null) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Item_Material is invalid!!"); -// } -// -// if (getTamingCOTWMaterial(EntityType.HORSE) == null) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Item_Material is invalid!!"); -// } -// -// if (getTamingCOTWCost(EntityType.WOLF) <= 0) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Item_Amount should be greater than 0!"); -// } -// -// if (getTamingCOTWCost(EntityType.OCELOT) <= 0) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Item_Amount should be greater than 0!"); -// } -// -// if (getTamingCOTWCost(EntityType.HORSE) <= 0) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Item_Amount should be greater than 0!"); -// } -// -// if (getTamingCOTWAmount(EntityType.WOLF) <= 0) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Summon_Amount should be greater than 0!"); -// } -// -// if (getTamingCOTWAmount(EntityType.OCELOT) <= 0) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Summon_Amount should be greater than 0!"); -// } -// -// if (getTamingCOTWAmount(EntityType.HORSE) <= 0) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Summon_Amount should be greater than 0!"); -// } - - return noErrorsInConfig(reason); - } - - /* - * GENERAL SETTINGS - */ - - public boolean isAprilFoolsAllowed() { return config.getBoolean("General.AprilFoolsEvent", true); } - - /* General Settings */ - public boolean getIsMetricsEnabled() { return config.getBoolean("Metrics.bstats", true); } - - //Retro mode will default the value to true if the config file doesn't contain the entry (server is from a previous mcMMO install) - public boolean getIsRetroMode() { return config.getBoolean("General.RetroMode.Enabled", true); } - - public String getLocale() { return config.getString("General.Locale", "en_us"); } - public boolean getMOTDEnabled() { return config.getBoolean("General.MOTD_Enabled", true); } - public boolean getShowProfileLoadedMessage() { return config.getBoolean("General.Show_Profile_Loaded", true); } - public boolean getDonateMessageEnabled() { return config.getBoolean("Commands.mcmmo.Donate_Message", true); } - public int getSaveInterval() { return config.getInt("General.Save_Interval", 10); } - public boolean getStatsTrackingEnabled() { return config.getBoolean("General.Stats_Tracking", true); } - public boolean getUpdateCheckEnabled() { return config.getBoolean("General.Update_Check", true); } - public boolean getPreferBeta() { return config.getBoolean("General.Prefer_Beta", false); } - public boolean getVerboseLoggingEnabled() { return config.getBoolean("General.Verbose_Logging", false); } - - - public boolean getMatchOfflinePlayers() { return config.getBoolean("Commands.Generic.Match_OfflinePlayers", false); } - public long getDatabasePlayerCooldown() { return config.getLong("Commands.Database.Player_Cooldown", 1750); } - - public boolean getLevelUpSoundsEnabled() { return config.getBoolean("General.LevelUp_Sounds", true); } - public boolean getRefreshChunksEnabled() { return config.getBoolean("General.Refresh_Chunks", false); } - - public boolean getMobHealthbarEnabled() { return config.getBoolean("Mob_Healthbar.Enabled", true); } - - /* Mob Healthbar */ - public MobHealthbarType getMobHealthbarDefault() { - try { - return MobHealthbarType.valueOf(config.getString("Mob_Healthbar.Display_Type", "HEARTS").toUpperCase(Locale.ENGLISH).trim()); - } - catch (IllegalArgumentException ex) { - return MobHealthbarType.HEARTS; - } - } - - public int getMobHealthbarTime() { return config.getInt("Mob_Healthbar.Display_Time", 3); } - - /* Scoreboards */ - public boolean getScoreboardsEnabled() { return config.getBoolean("Scoreboard.UseScoreboards", true); } - public boolean getPowerLevelTagsEnabled() { return config.getBoolean("Scoreboard.Power_Level_Tags", false); } - public boolean getAllowKeepBoard() { return config.getBoolean("Scoreboard.Allow_Keep", true); } - public int getTipsAmount() { return config.getInt("Scoreboard.Tips_Amount", 5); } - public boolean getShowStatsAfterLogin() { return config.getBoolean("Scoreboard.Show_Stats_After_Login", false); } - public boolean getScoreboardRainbows() { return config.getBoolean("Scoreboard.Rainbows", false); } - public boolean getShowAbilityNames() { return config.getBoolean("Scoreboard.Ability_Names", true); } - - public boolean getRankUseChat() { return config.getBoolean("Scoreboard.Types.Rank.Print", false); } - public boolean getRankUseBoard() { return config.getBoolean("Scoreboard.Types.Rank.Board", true); } - public int getRankScoreboardTime() { return config.getInt("Scoreboard.Types.Rank.Display_Time", 10); } - - public boolean getTopUseChat() { return config.getBoolean("Scoreboard.Types.Top.Print", true); } - public boolean getTopUseBoard() { return config.getBoolean("Scoreboard.Types.Top.Board", true); } - public int getTopScoreboardTime() { return config.getInt("Scoreboard.Types.Top.Display_Time", 15); } - - public boolean getStatsUseChat() { return config.getBoolean("Scoreboard.Types.Stats.Print", true); } - public boolean getStatsUseBoard() { return config.getBoolean("Scoreboard.Types.Stats.Board", true); } - public int getStatsScoreboardTime() { return config.getInt("Scoreboard.Types.Stats.Display_Time", 10); } - - public boolean getInspectUseChat() { return config.getBoolean("Scoreboard.Types.Inspect.Print", true); } - public boolean getInspectUseBoard() { return config.getBoolean("Scoreboard.Types.Inspect.Board", true); } - public int getInspectScoreboardTime() { return config.getInt("Scoreboard.Types.Inspect.Display_Time", 25); } - - public boolean getCooldownUseChat() { return config.getBoolean("Scoreboard.Types.Cooldown.Print", false); } - public boolean getCooldownUseBoard() { return config.getBoolean("Scoreboard.Types.Cooldown.Board", true); } - public int getCooldownScoreboardTime() { return config.getInt("Scoreboard.Types.Cooldown.Display_Time", 41); } - - public boolean getSkillUseBoard() { return config.getBoolean("Scoreboard.Types.Skill.Board", true); } - public int getSkillScoreboardTime() { return config.getInt("Scoreboard.Types.Skill.Display_Time", 30); } - public boolean getSkillLevelUpBoard() { return config.getBoolean("Scoreboard.Types.Skill.LevelUp_Board", true); } - public int getSkillLevelUpTime() { return config.getInt("Scoreboard.Types.Skill.LevelUp_Time", 5); } - - /* Database Purging */ - public int getPurgeInterval() { return config.getInt("Database_Purging.Purge_Interval", -1); } - public int getOldUsersCutoff() { return config.getInt("Database_Purging.Old_User_Cutoff", 6); } - - /* Backups */ - public boolean getBackupsEnabled() { return config.getBoolean("Backups.Enabled", true); } - public boolean getKeepLast24Hours() { return config.getBoolean("Backups.Keep.Last_24_Hours", true); } - public boolean getKeepDailyLastWeek() { return config.getBoolean("Backups.Keep.Daily_Last_Week", true); } - public boolean getKeepWeeklyPastMonth() { return config.getBoolean("Backups.Keep.Weekly_Past_Months", true); } - - /* mySQL */ - public boolean getUseMySQL() { return config.getBoolean("MySQL.Enabled", false); } - public String getMySQLTablePrefix() { return config.getString("MySQL.Database.TablePrefix", "mcmmo_"); } - public String getMySQLDatabaseName() { return getStringIncludingInts("MySQL.Database.Name"); } - public String getMySQLUserName() { return getStringIncludingInts("MySQL.Database.User_Name"); } - public int getMySQLServerPort() { return config.getInt("MySQL.Server.Port", 3306); } - public String getMySQLServerName() { return config.getString("MySQL.Server.Address", "localhost"); } - public String getMySQLUserPassword() { return getStringIncludingInts("MySQL.Database.User_Password"); } - public int getMySQLMaxConnections(PoolIdentifier identifier) { return config.getInt("MySQL.Database.MaxConnections." + StringUtils.getCapitalized(identifier.toString()), 30); } - public int getMySQLMaxPoolSize(PoolIdentifier identifier) { return config.getInt("MySQL.Database.MaxPoolSize." + StringUtils.getCapitalized(identifier.toString()), 10); } - public boolean getMySQLSSL() { return config.getBoolean("MySQL.Server.SSL", true); } - public boolean getMySQLDebug() { return config.getBoolean("MySQL.Debug", false); } - - private String getStringIncludingInts(String key) { - String str = config.getString(key); - - if (str == null) { - str = String.valueOf(config.getInt(key)); - } - - if (str.equals("0")) { - str = "No value set for '" + key + "'"; - } - return str; - } - - /* Hardcore Mode */ - public boolean getHardcoreStatLossEnabled(PrimarySkillType primarySkillType) { return config.getBoolean("Hardcore.Death_Stat_Loss.Enabled." + StringUtils.getCapitalized(primarySkillType.toString()), false); } - public void setHardcoreStatLossEnabled(PrimarySkillType primarySkillType, boolean enabled) { config.set("Hardcore.Death_Stat_Loss.Enabled." + StringUtils.getCapitalized(primarySkillType.toString()), enabled); } - - public double getHardcoreDeathStatPenaltyPercentage() { return config.getDouble("Hardcore.Death_Stat_Loss.Penalty_Percentage", 75.0D); } - public void setHardcoreDeathStatPenaltyPercentage(double value) { config.set("Hardcore.Death_Stat_Loss.Penalty_Percentage", value); } - - public int getHardcoreDeathStatPenaltyLevelThreshold() { return config.getInt("Hardcore.Death_Stat_Loss.Level_Threshold", 0); } - - public boolean getHardcoreVampirismEnabled(PrimarySkillType primarySkillType) { return config.getBoolean("Hardcore.Vampirism.Enabled." + StringUtils.getCapitalized(primarySkillType.toString()), false); } - public void setHardcoreVampirismEnabled(PrimarySkillType primarySkillType, boolean enabled) { config.set("Hardcore.Vampirism.Enabled." + StringUtils.getCapitalized(primarySkillType.toString()), enabled); } - - public double getHardcoreVampirismStatLeechPercentage() { return config.getDouble("Hardcore.Vampirism.Leech_Percentage", 5.0D); } - public void setHardcoreVampirismStatLeechPercentage(double value) { config.set("Hardcore.Vampirism.Leech_Percentage", value); } - - public int getHardcoreVampirismLevelThreshold() { return config.getInt("Hardcore.Vampirism.Level_Threshold", 0); } - - /* SMP Mods */ - public boolean getToolModsEnabled() { return config.getBoolean("Mods.Tool_Mods_Enabled", false); } - public boolean getArmorModsEnabled() { return config.getBoolean("Mods.Armor_Mods_Enabled", false); } - public boolean getBlockModsEnabled() { return config.getBoolean("Mods.Block_Mods_Enabled", false); } - public boolean getEntityModsEnabled() { return config.getBoolean("Mods.Entity_Mods_Enabled", false); } - - /* Items */ - public int getChimaeraUseCost() { return config.getInt("Items.Chimaera_Wing.Use_Cost", 1); } - public int getChimaeraRecipeCost() { return config.getInt("Items.Chimaera_Wing.Recipe_Cost", 5); } - public Material getChimaeraItem() { return Material.matchMaterial(config.getString("Items.Chimaera_Wing.Item_Name", "Feather")); } - public boolean getChimaeraEnabled() { return config.getBoolean("Items.Chimaera_Wing.Enabled", true); } - public boolean getChimaeraPreventUseUnderground() { return config.getBoolean("Items.Chimaera_Wing.Prevent_Use_Underground", true); } - public boolean getChimaeraUseBedSpawn() { return config.getBoolean("Items.Chimaera_Wing.Use_Bed_Spawn", true); } - public int getChimaeraCooldown() { return config.getInt("Items.Chimaera_Wing.Cooldown", 240); } - public int getChimaeraWarmup() { return config.getInt("Items.Chimaera_Wing.Warmup", 5); } - public int getChimaeraRecentlyHurtCooldown() { return config.getInt("Items.Chimaera_Wing.RecentlyHurt_Cooldown", 60); } - public boolean getChimaeraSoundEnabled() { return config.getBoolean("Items.Chimaera_Wing.Sound_Enabled", true); } - - public boolean getFluxPickaxeSoundEnabled() { return config.getBoolean("Items.Flux_Pickaxe.Sound_Enabled", true); } - - /* Particles */ - public boolean getAbilityActivationEffectEnabled() { return config.getBoolean("Particles.Ability_Activation", true); } - public boolean getAbilityDeactivationEffectEnabled() { return config.getBoolean("Particles.Ability_Deactivation", true); } - public boolean getBleedEffectEnabled() { return config.getBoolean("Particles.Bleed", true); } - public boolean getDodgeEffectEnabled() { return config.getBoolean("Particles.Dodge", true); } - public boolean getFluxEffectEnabled() { return config.getBoolean("Particles.Flux", true); } - public boolean getGreaterImpactEffectEnabled() { return config.getBoolean("Particles.Greater_Impact", true); } - public boolean getCallOfTheWildEffectEnabled() { return config.getBoolean("Particles.Call_of_the_Wild", true); } - public boolean getLevelUpEffectsEnabled() { return config.getBoolean("Particles.LevelUp_Enabled", true); } - public int getLevelUpEffectsTier() { return config.getInt("Particles.LevelUp_Tier", 100); } -// public boolean getLargeFireworks() { return config.getBoolean("Particles.LargeFireworks", true); } - - /* PARTY SETTINGS */ - public boolean getPartyFriendlyFire() { return config.getBoolean("Party.FriendlyFire", false);} - public int getPartyMaxSize() {return config.getInt("Party.MaxSize", -1); } - public int getAutoPartyKickInterval() { return config.getInt("Party.AutoKick_Interval", 12); } - public int getAutoPartyKickTime() { return config.getInt("Party.Old_Party_Member_Cutoff", 7); } - - public double getPartyShareBonusBase() { return config.getDouble("Party.Sharing.ExpShare_bonus_base", 1.1D); } - public double getPartyShareBonusIncrease() { return config.getDouble("Party.Sharing.ExpShare_bonus_increase", 0.05D); } - public double getPartyShareBonusCap() { return config.getDouble("Party.Sharing.ExpShare_bonus_cap", 1.5D); } - public double getPartyShareRange() { return config.getDouble("Party.Sharing.Range", 75.0D); } - - public int getPartyLevelCap() { - int cap = config.getInt("Party.Leveling.Level_Cap", 10); - return (cap <= 0) ? Integer.MAX_VALUE : cap; - } - - public int getPartyXpCurveMultiplier() { return config.getInt("Party.Leveling.Xp_Curve_Modifier", 3); } - public boolean getPartyXpNearMembersNeeded() { return config.getBoolean("Party.Leveling.Near_Members_Needed", false); } - public boolean getPartyInformAllMembers() { return config.getBoolean("Party.Leveling.Inform_All_Party_Members_On_LevelUp", false); } - - public int getPartyFeatureUnlockLevel(PartyFeature partyFeature) { return config.getInt("Party.Leveling." + StringUtils.getPrettyPartyFeatureString(partyFeature).replace(" ", "") + "_UnlockLevel", 0); } - - /* Party Teleport Settings */ - public int getPTPCommandCooldown() { return config.getInt("Commands.ptp.Cooldown", 120); } - public int getPTPCommandWarmup() { return config.getInt("Commands.ptp.Warmup", 5); } - public int getPTPCommandRecentlyHurtCooldown() { return config.getInt("Commands.ptp.RecentlyHurt_Cooldown", 60); } - public int getPTPCommandTimeout() { return config.getInt("Commands.ptp.Request_Timeout", 300); } - public boolean getPTPCommandConfirmRequired() { return config.getBoolean("Commands.ptp.Accept_Required", true); } - public boolean getPTPCommandWorldPermissions() { return config.getBoolean("Commands.ptp.World_Based_Permissions", false); } - - /* Inspect command distance */ - public double getInspectDistance() { return config.getDouble("Commands.inspect.Max_Distance", 30.0D); } - - /* - * ABILITY SETTINGS - */ - - /* General Settings */ - public boolean getUrlLinksEnabled() { return config.getBoolean("Commands.Skills.URL_Links"); } - public boolean getAbilityMessagesEnabled() { return config.getBoolean("Abilities.Messages", true); } - public boolean getAbilitiesEnabled() { return config.getBoolean("Abilities.Enabled", true); } - public boolean getAbilitiesOnlyActivateWhenSneaking() { return config.getBoolean("Abilities.Activation.Only_Activate_When_Sneaking", false); } - public boolean getAbilitiesGateEnabled() { return config.getBoolean("Abilities.Activation.Level_Gate_Abilities"); } - - public int getCooldown(SuperAbilityType ability) { return config.getInt("Abilities.Cooldowns." + ability.toString()); } - public int getMaxLength(SuperAbilityType ability) { return config.getInt("Abilities.Max_Seconds." + ability.toString()); } - - /* Durability Settings */ - public int getAbilityToolDamage() { return config.getInt("Abilities.Tools.Durability_Loss", 1); } - - /* Thresholds */ - public int getTreeFellerThreshold() { return config.getInt("Abilities.Limits.Tree_Feller_Threshold", 1000); } - - /* - * SKILL SETTINGS - */ - public boolean getDoubleDropsEnabled(PrimarySkillType skill, Material material) { - //TODO: Temporary measure to fix an exploit caused by a yet to be fixed Spigot bug (as of 7/3/2020) - if(material.toString().equalsIgnoreCase("LILY_PAD")) - return false; - - return config.getBoolean("Bonus_Drops." + StringUtils.getCapitalized(skill.toString()) + "." + StringUtils.getPrettyItemString(material).replace(" ", "_")); - } - - public boolean getDoubleDropsDisabled(PrimarySkillType skill) { - String skillName = StringUtils.getCapitalized(skill.toString()); - ConfigurationSection section = config.getConfigurationSection("Bonus_Drops." + skillName); - if (section == null) - return false; - Set keys = section.getKeys(false); - boolean disabled = true; - - for (String key : keys) { - if (config.getBoolean("Bonus_Drops." + skillName + "." + key)) { - disabled = false; - break; - } - } - - return disabled; - } - - /* Axes */ - public int getAxesGate() { return config.getInt("Skills.Axes.Ability_Activation_Level_Gate", 10); } - - /* Acrobatics */ - public boolean getDodgeLightningDisabled() { return config.getBoolean("Skills.Acrobatics.Prevent_Dodge_Lightning", false); } - public int getXPAfterTeleportCooldown() { return config.getInt("Skills.Acrobatics.XP_After_Teleport_Cooldown", 5); } - - /* Alchemy */ - public boolean getEnabledForHoppers() { return config.getBoolean("Skills.Alchemy.Enabled_for_Hoppers", true); } - public boolean getPreventHopperTransferIngredients() { return config.getBoolean("Skills.Alchemy.Prevent_Hopper_Transfer_Ingredients", false); } - public boolean getPreventHopperTransferBottles() { return config.getBoolean("Skills.Alchemy.Prevent_Hopper_Transfer_Bottles", false); } - - /* Fishing */ - public boolean getFishingDropsEnabled() { return config.getBoolean("Skills.Fishing.Drops_Enabled", true); } - public boolean getFishingOverrideTreasures() { return config.getBoolean("Skills.Fishing.Override_Vanilla_Treasures", true); } - public boolean getFishingExtraFish() { return config.getBoolean("Skills.Fishing.Extra_Fish", true); } - public double getFishingLureModifier() { return config.getDouble("Skills.Fishing.Lure_Modifier", 4.0D); } - - /* Mining */ - public Material getDetonatorItem() { return Material.matchMaterial(config.getString("Skills.Mining.Detonator_Name", "FLINT_AND_STEEL")); } - - /* Excavation */ - public int getExcavationGate() { return config.getInt("Skills.Excavation.Ability_Activation_Level_Gate", 10); } - - /* Repair */ - public boolean getRepairAnvilMessagesEnabled() { return config.getBoolean("Skills.Repair.Anvil_Messages", true); } - public boolean getRepairAnvilPlaceSoundsEnabled() { return config.getBoolean("Skills.Repair.Anvil_Placed_Sounds", true); } - public boolean getRepairAnvilUseSoundsEnabled() { return config.getBoolean("Skills.Repair.Anvil_Use_Sounds", true); } - public @Nullable Material getRepairAnvilMaterial() { return Material.matchMaterial(config.getString("Skills.Repair.Anvil_Material", "IRON_BLOCK")); } - public boolean getRepairConfirmRequired() { return config.getBoolean("Skills.Repair.Confirm_Required", true); } - public boolean getAllowVanillaInventoryRepair() { return config.getBoolean("Skills.Repair.Allow_Vanilla_Anvil_Repair", false); } - public boolean getAllowVanillaAnvilRepair() { return config.getBoolean("Skills.Repair.Allow_Vanilla_Inventory_Repair", false); } - public boolean getAllowVanillaGrindstoneRepair() { return config.getBoolean("Skills.Repair.Allow_Vanilla_Grindstone_Repair", false); } - - /* Salvage */ - public boolean getSalvageAnvilMessagesEnabled() { return config.getBoolean("Skills.Salvage.Anvil_Messages", true); } - public boolean getSalvageAnvilPlaceSoundsEnabled() { return config.getBoolean("Skills.Salvage.Anvil_Placed_Sounds", true); } - public boolean getSalvageAnvilUseSoundsEnabled() { return config.getBoolean("Skills.Salvage.Anvil_Use_Sounds", true); } - public @Nullable Material getSalvageAnvilMaterial() { return Material.matchMaterial(config.getString("Skills.Salvage.Anvil_Material", "GOLD_BLOCK")); } - public boolean getSalvageConfirmRequired() { return config.getBoolean("Skills.Salvage.Confirm_Required", true); } - - /* Unarmed */ - public boolean getUnarmedBlockCrackerSmoothbrickToCracked() { return config.getBoolean("Skills.Unarmed.Block_Cracker.SmoothBrick_To_CrackedBrick", true); } - public boolean getUnarmedItemPickupDisabled() { return config.getBoolean("Skills.Unarmed.Item_Pickup_Disabled_Full_Inventory", true); } - public boolean getUnarmedItemsAsUnarmed() { return config.getBoolean("Skills.Unarmed.Items_As_Unarmed", false); } - public int getUnarmedGate() { return config.getInt("Skills.Unarmed.Ability_Activation_Level_Gate", 10); } - - /* Swords */ - public int getSwordsGate() { return config.getInt("Skills.Swords.Ability_Activation_Level_Gate", 10); } - - /* Taming */ -// public Material getTamingCOTWMaterial(EntityType type) { return Material.matchMaterial(config.getString("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type) + ".Item_Material")); } -// public int getTamingCOTWCost(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type) + ".Item_Amount"); } -// public int getTamingCOTWAmount(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type) + ".Summon_Amount"); } -// public int getTamingCOTWLength(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type)+ ".Summon_Length"); } -// public int getTamingCOTWMaxAmount(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type)+ ".Summon_Max_Amount"); } - - public Material getTamingCOTWMaterial(String cotwEntity) { return Material.matchMaterial(config.getString("Skills.Taming.Call_Of_The_Wild." + cotwEntity + ".Item_Material")); } - public int getTamingCOTWCost(String cotwEntity) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + cotwEntity + ".Item_Amount"); } - public int getTamingCOTWAmount(String cotwEntity) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + cotwEntity + ".Summon_Amount"); } - public int getTamingCOTWLength(String cotwEntity) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + cotwEntity+ ".Summon_Length"); } - public int getTamingCOTWMaxAmount(String cotwEntity) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + cotwEntity+ ".Per_Player_Limit", 1); } - - /* Woodcutting */ - public boolean getWoodcuttingDoubleDropsEnabled(BlockData material) { return config.getBoolean("Bonus_Drops.Woodcutting." + StringUtils.getFriendlyConfigBlockDataString(material)); } - public boolean getTreeFellerSoundsEnabled() { return config.getBoolean("Skills.Woodcutting.Tree_Feller_Sounds", true); } - public int getWoodcuttingGate() { return config.getInt("Skills.Woodcutting.Ability_Activation_Level_Gate", 10); } - - /* AFK Leveling */ - public boolean getHerbalismPreventAFK() { return config.getBoolean("Skills.Herbalism.Prevent_AFK_Leveling", true); } - - /* Level Caps */ - public int getPowerLevelCap() { - int cap = config.getInt("General.Power_Level_Cap", 0); - return (cap <= 0) ? Integer.MAX_VALUE : cap; - } - - public int getLevelCap(PrimarySkillType skill) { - int cap = config.getInt("Skills." + StringUtils.getCapitalized(skill.toString()) + ".Level_Cap"); - return (cap <= 0) ? Integer.MAX_VALUE : cap; - } - - - /*public int isSuperAbilityUnlocked(PrimarySkillType skill) { - return config.getInt("Skills." + StringUtils.getCapitalized(skill.toString()) + ".Ability_Activation_Level_Gate"); - }*/ - - public boolean getTruncateSkills() { return config.getBoolean("General.TruncateSkills", false); } - - /* PVP & PVE Settings */ - public boolean getPVPEnabled(PrimarySkillType skill) { return config.getBoolean("Skills." + StringUtils.getCapitalized(skill.toString()) + ".Enabled_For_PVP", true); } - public boolean getPVEEnabled(PrimarySkillType skill) { return config.getBoolean("Skills." + StringUtils.getCapitalized(skill.toString()) + ".Enabled_For_PVE", true); } - - //public float getMasterVolume() { return (float) config.getDouble("Sounds.MasterVolume", 1.0); } - - public boolean broadcastEventMessages() { return config.getBoolean("General.EventBroadcasts", true);} - public boolean playerJoinEventInfo() { return config.getBoolean("General.EventInfoOnPlayerJoin", true);} - public boolean adminNotifications() { return config.getBoolean("General.AdminNotifications", true);} - - public boolean shouldLevelUpBroadcasts() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Enabled", true); } - public boolean shouldLevelUpBroadcastToConsole() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Send_To_Console", true); } - public boolean isLevelUpBroadcastsPartyMembersOnly() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Only_Party_Members", false); } - public boolean isLevelUpBroadcastsSameWorldOnly() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Only_Same_World", false); } - public boolean shouldLevelUpBroadcastsRestrictDistance() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Distance_Restrictions.Restrict_Distance", false); } - public int getLevelUpBroadcastRadius() { return config.getInt("General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Distance_Restrictions.Restricted_Radius", 100); } - public int getLevelUpBroadcastInterval() { return config.getInt("General.Level_Up_Chat_Broadcasts.Milestone_Interval", 100); } - - public boolean shouldPowerLevelUpBroadcasts() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Enabled", true); } - public boolean shouldPowerLevelUpBroadcastToConsole() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Broadcast_Targets.Send_To_Console", true); } - public boolean isPowerLevelUpBroadcastsPartyMembersOnly() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Broadcast_Targets.Only_Party_Members", false); } - public boolean isPowerLevelUpBroadcastsSameWorldOnly() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Broadcast_Targets.Only_Same_World", false); } - public boolean shouldPowerLevelUpBroadcastsRestrictDistance() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Broadcast_Targets.Distance_Restrictions.Restrict_Distance", false); } - public int getPowerLevelUpBroadcastRadius() { return config.getInt("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Broadcast_Targets.Distance_Restrictions.Restricted_Radius", 100); } - public int getPowerLevelUpBroadcastInterval() { return config.getInt("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Milestone_Interval", 100); } - - public boolean isMasterySystemEnabled() { return config.getBoolean( "General.PowerLevel.Skill_Mastery.Enabled"); } - public boolean isGreenThumbReplantableCrop(@NotNull Material material) { - return config.getBoolean("Green_Thumb_Replanting_Crops." + StringUtils.getCapitalized(material.toString()), true); - } -} diff --git a/src/main/java/com/gmail/nossr50/config/GeneralConfig.java b/src/main/java/com/gmail/nossr50/config/GeneralConfig.java index fb86a42f41..f0ae3cd1cf 100644 --- a/src/main/java/com/gmail/nossr50/config/GeneralConfig.java +++ b/src/main/java/com/gmail/nossr50/config/GeneralConfig.java @@ -1005,4 +1005,6 @@ public int getPowerLevelUpBroadcastInterval() { public boolean isGreenThumbReplantableCrop(@NotNull Material material) { return config.getBoolean("Green_Thumb_Replanting_Crops." + StringUtils.getCapitalized(material.toString()), true); } + + public boolean isMasterySystemEnabled() { return config.getBoolean( "General.PowerLevel.Skill_Mastery.Enabled"); } } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java index bc6ca79881..15ea49679e 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java @@ -111,7 +111,7 @@ public String getPermissionNode() { */ @Override public boolean hasPermission(Player player) { - return Permissions.isSubSkillEnabled(player, this); + return Permissions.isSubSkillEnabled(player, getSubSkillType()); } /** diff --git a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java index 3643d9ce3c..fe0ae14ce6 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.skills.woodcutting; import com.gmail.nossr50.api.ItemSpawnReason; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.interactions.NotificationType; @@ -88,7 +87,7 @@ private boolean checkCleanCutsActivation(Material material) { */ public void processBonusDropCheck(@NotNull BlockState blockState) { //TODO: Why isn't this using the item drop event? Potentially because of Tree Feller? This should be adjusted either way. - if(Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, blockState.getType())) { + if(mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, blockState.getType())) { //Mastery enabled for player if(Permissions.canUseSubSkill(getPlayer(), SubSkillType.WOODCUTTING_CLEAN_CUTS)) { if(checkCleanCutsActivation(blockState.getType())) { @@ -406,6 +405,10 @@ protected static int getExperienceFromLog(BlockState blockState) { * @param blockState Block being broken */ protected void spawnHarvestLumberBonusDrops(@NotNull BlockState blockState) { - Misc.spawnItemsFromCollection(getPlayer(), Misc.getBlockCenter(blockState), blockState.getBlock().getDrops(getPlayer().getInventory().getItemInMainHand()), ItemSpawnReason.BONUS_DROPS); + Misc.spawnItemsFromCollection( + getPlayer(), + Misc.getBlockCenter(blockState), + blockState.getBlock().getDrops(getPlayer().getInventory().getItemInMainHand()), + ItemSpawnReason.BONUS_DROPS); } } diff --git a/src/main/java/com/gmail/nossr50/util/Permissions.java b/src/main/java/com/gmail/nossr50/util/Permissions.java index d7fdb90856..93c27fea34 100644 --- a/src/main/java/com/gmail/nossr50/util/Permissions.java +++ b/src/main/java/com/gmail/nossr50/util/Permissions.java @@ -170,7 +170,6 @@ public static boolean customXpBoost(Permissible permissible, PrimarySkillType sk public static boolean skillEnabled(Permissible permissible, PrimarySkillType skill) {return permissible.hasPermission("mcmmo.skills." + skill.toString().toLowerCase(Locale.ENGLISH)); } public static boolean vanillaXpBoost(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.ability." + skill.toString().toLowerCase(Locale.ENGLISH) + ".vanillaxpboost"); } public static boolean isSubSkillEnabled(Permissible permissible, SubSkillType subSkillType) { return permissible.hasPermission(subSkillType.getPermissionNodeAddress()); } - public static boolean isSubSkillEnabled(Permissible permissible, AbstractSubSkill abstractSubSkill) { return permissible.hasPermission(abstractSubSkill.getPermissionNode()); } /* ACROBATICS */ public static boolean dodge(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.acrobatics.dodge"); } diff --git a/src/main/java/com/gmail/nossr50/util/random/Probability.java b/src/main/java/com/gmail/nossr50/util/random/Probability.java index b792ad64ac..a4d8c848c8 100644 --- a/src/main/java/com/gmail/nossr50/util/random/Probability.java +++ b/src/main/java/com/gmail/nossr50/util/random/Probability.java @@ -29,7 +29,7 @@ public interface Probability { * @return true for succeeding, false for failing */ static private boolean isSuccessfulRoll(double probabilityValue) { - return probabilityValue >= ThreadLocalRandom.current().nextDouble(100D); + return (probabilityValue * 100) >= ThreadLocalRandom.current().nextDouble(100D); } /** diff --git a/src/main/java/com/gmail/nossr50/util/random/ProbabilityUtil.java b/src/main/java/com/gmail/nossr50/util/random/ProbabilityUtil.java index 55d6950b62..ba3ce84e14 100644 --- a/src/main/java/com/gmail/nossr50/util/random/ProbabilityUtil.java +++ b/src/main/java/com/gmail/nossr50/util/random/ProbabilityUtil.java @@ -84,10 +84,11 @@ static SkillProbabilityType getProbabilityType(@NotNull SubSkillType subSkillTyp if (player != null) { McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - if(mmoPlayer != null) + if(mmoPlayer != null) { xPos = mmoPlayer.getSkillLevel(subSkillType.getParentSkill()); - else + } else { xPos = 0; + } } else { xPos = 0; } diff --git a/src/main/java/com/gmail/nossr50/util/text/TextComponentFactory.java b/src/main/java/com/gmail/nossr50/util/text/TextComponentFactory.java index 5506b66856..708fab805c 100644 --- a/src/main/java/com/gmail/nossr50/util/text/TextComponentFactory.java +++ b/src/main/java/com/gmail/nossr50/util/text/TextComponentFactory.java @@ -88,7 +88,7 @@ public static void sendPlayerUrlHeader(Player player) { TextComponent emptySpace = Component.space(); - mcMMO.getAudiences().player(player).sendMessage(Identity.nil(),TextComponent.ofChildren( + mcMMO.getAudiences().player(player).sendMessage(Identity.nil(),Component.textOfChildren( prefix, getWebLinkTextComponent(McMMOWebLinks.WEBSITE), emptySpace, @@ -138,40 +138,38 @@ private static Component getWebLinkTextComponent(McMMOWebLinks webLinks) { TextComponent.Builder webTextComponent; - switch(webLinks) - { - case WEBSITE: + switch (webLinks) { + case WEBSITE -> { webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL")); TextUtils.addChildWebComponent(webTextComponent, "Web"); webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlWebsite)); - break; - case SPIGOT: + } + case SPIGOT -> { webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL")); TextUtils.addChildWebComponent(webTextComponent, "Spigot"); webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlSpigot)); - break; - case DISCORD: + } + case DISCORD -> { webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL")); TextUtils.addChildWebComponent(webTextComponent, "Discord"); webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlDiscord)); - break; - case PATREON: + } + case PATREON -> { webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL")); TextUtils.addChildWebComponent(webTextComponent, "Patreon"); webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlPatreon)); - break; - case WIKI: + } + case WIKI -> { webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL")); TextUtils.addChildWebComponent(webTextComponent, "Wiki"); webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlWiki)); - break; - case HELP_TRANSLATE: + } + case HELP_TRANSLATE -> { webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL")); TextUtils.addChildWebComponent(webTextComponent, "Lang"); webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlTranslate)); - break; - default: - webTextComponent = Component.text().content("NOT DEFINED"); + } + default -> webTextComponent = Component.text().content("NOT DEFINED"); } TextUtils.addNewHoverComponentToTextComponent(webTextComponent, getUrlHoverEvent(webLinks)); @@ -184,46 +182,46 @@ private static Component getUrlHoverEvent(McMMOWebLinks webLinks) { TextComponent.Builder componentBuilder = Component.text().content(webLinks.getNiceTitle()); - switch(webLinks) - { - case WEBSITE: + switch (webLinks) { + case WEBSITE -> { addUrlHeaderHover(webLinks, componentBuilder); componentBuilder.append(Component.newline()).append(Component.newline()); componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN)); componentBuilder.append(Component.text("\nDev Blogs, and information related to mcMMO can be found here", NamedTextColor.GRAY)); - break; - case SPIGOT: + } + case SPIGOT -> { addUrlHeaderHover(webLinks, componentBuilder); componentBuilder.append(Component.newline()).append(Component.newline()); componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN)); componentBuilder.append(Component.text("\nI post regularly in the discussion thread here!", NamedTextColor.GRAY)); - break; - case PATREON: + } + case PATREON -> { addUrlHeaderHover(webLinks, componentBuilder); componentBuilder.append(Component.newline()).append(Component.newline()); componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN)); componentBuilder.append(Component.newline()); componentBuilder.append(Component.text("Show support by buying me a coffee :)", NamedTextColor.GRAY)); - break; - case WIKI: + } + case WIKI -> { addUrlHeaderHover(webLinks, componentBuilder); componentBuilder.append(Component.newline()).append(Component.newline()); componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN)); componentBuilder.append(Component.newline()); componentBuilder.append(Component.text("I'm looking for more wiki staff, contact me on our discord!", NamedTextColor.DARK_GRAY)); - break; - case DISCORD: + } + case DISCORD -> { addUrlHeaderHover(webLinks, componentBuilder); componentBuilder.append(Component.newline()).append(Component.newline()); componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN)); - break; - case HELP_TRANSLATE: + } + case HELP_TRANSLATE -> { addUrlHeaderHover(webLinks, componentBuilder); componentBuilder.append(Component.newline()).append(Component.newline()); componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN)); componentBuilder.append(Component.newline()); componentBuilder.append(Component.text("You can use this website to help translate mcMMO into your language!" + - "\nIf you want to know more contact me in discord.", NamedTextColor.DARK_GRAY)); + "\nIf you want to know more contact me in discord.", NamedTextColor.DARK_GRAY)); + } } return componentBuilder.build(); @@ -510,7 +508,7 @@ public static void getSubSkillTextComponents(Player player, List text { if(abstractSubSkill.getPrimarySkill() == parentSkill) { - if(Permissions.isSubSkillEnabled(player, abstractSubSkill)) + if(Permissions.isSubSkillEnabled(player, abstractSubSkill.getSubSkillType())) textComponents.add(TextComponentFactory.getSubSkillTextComponent(player, abstractSubSkill)); } } diff --git a/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManagerTest.java b/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManagerTest.java new file mode 100644 index 0000000000..abeadaa212 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManagerTest.java @@ -0,0 +1,218 @@ +package com.gmail.nossr50.skills.woodcutting; + +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.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.mcMMO; +import com.gmail.nossr50.util.EventUtils; +import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.TransientEntityTracker; +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.block.Block; +import org.bukkit.block.BlockState; +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.junit.jupiter.api.Test; +import org.bukkit.entity.Player; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import java.util.UUID; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; + +class WoodcuttingManagerTest { + private static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(WoodcuttingManagerTest.class.getName()); + private MockedStatic mockedMcMMO; + private MockedStatic mockedChatConfig; + private MockedStatic mockedPermissions; + private MockedStatic mockedRankUtils; + private MockedStatic mockedUserManager; + private MockedStatic mockedMisc; + private MockedStatic mockedSkillTools; + private MockedStatic mockedEventUtils; + private TransientEntityTracker transientEntityTracker; + private AdvancedConfig advancedConfig; + private GeneralConfig generalConfig; + private RankConfig rankConfig; + private SkillTools skillTools; + private Server server; + private PluginManager pluginManager; + private World world; + + private WoodcuttingManager woodcuttingManager; + + /* Mocks */ + Player player; + + UUID playerUUID = UUID.randomUUID(); + ItemStack itemInMainHand; + + PlayerInventory playerInventory; + PlayerProfile playerProfile; + McMMOPlayer mmoPlayer; + String playerName = "testPlayer"; + + @BeforeEach + void setUp() { + mockedMcMMO = Mockito.mockStatic(mcMMO.class); + mcMMO.p = Mockito.mock(mcMMO.class); + Mockito.when(mcMMO.p.getLogger()).thenReturn(logger); + + // chat config + mockedChatConfig = Mockito.mockStatic(ChatConfig.class); + Mockito.when(ChatConfig.getInstance()).thenReturn(Mockito.mock(ChatConfig.class)); + + // general config + generalConfig = Mockito.mock(GeneralConfig.class); + Mockito.when(generalConfig.getTreeFellerThreshold()).thenReturn(100); + Mockito.when(generalConfig.getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, Material.OAK_LOG)).thenReturn(true); + Mockito.when(generalConfig.getLocale()).thenReturn("en_US"); + Mockito.when(mcMMO.p.getGeneralConfig()).thenReturn(generalConfig); + + // rank config + rankConfig = Mockito.mock(RankConfig.class); + Mockito.when(rankConfig.getSubSkillUnlockLevel(SubSkillType.WOODCUTTING_HARVEST_LUMBER, 1)).thenReturn(1); + + // wire advanced config + this.advancedConfig = Mockito.mock(AdvancedConfig.class); + 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(mcMMO.p.getAdvancedConfig()).thenReturn(advancedConfig); + + // wire skill tools + this.skillTools = new SkillTools(mcMMO.p); + Mockito.when(mcMMO.p.getSkillTools()).thenReturn(skillTools); + + this.transientEntityTracker = new TransientEntityTracker(); + Mockito.when(mcMMO.getTransientEntityTracker()).thenReturn(transientEntityTracker); + + mockedPermissions = Mockito.mockStatic(Permissions.class); + Mockito.when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); + Mockito.when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn(true); + Mockito.when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); + Mockito.when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn(true); + Mockito.when(Permissions.lucky(player, PrimarySkillType.WOODCUTTING)).thenReturn(false); // player is not lucky + + mockedRankUtils = Mockito.mockStatic(RankUtils.class); + 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); + + // wire server + this.server = Mockito.mock(Server.class); + Mockito.when(mcMMO.p.getServer()).thenReturn(server); + + // wire plugin manager + this.pluginManager = Mockito.mock(PluginManager.class); + Mockito.when(server.getPluginManager()).thenReturn(pluginManager); + + // wire world + this.world = Mockito.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 = 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); + + // 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); + Mockito.when(UserManager.getPlayer(player)).thenReturn(mmoPlayer); + + // Set up spy for WoodcuttingManager + woodcuttingManager = Mockito.spy(new WoodcuttingManager(mmoPlayer)); + } + + @AfterEach + void tearDown() { + // Clean up resources here if needed. + if (mockedMcMMO != null) { + mockedMcMMO.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(); + } + } + + @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 + 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); + } +} From 6845fb4c44f88ecce312b5a882cf23a9bc3aa2d4 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 26 Mar 2023 13:41:31 -0700 Subject: [PATCH 24/75] Fix some bugs with new Probability type and unit tests --- .../nossr50/util/random/Probability.java | 24 ++++++++++++++----- .../nossr50/util/random/ProbabilityImpl.java | 9 +++---- .../nossr50/util/random/ProbabilityTest.java | 2 +- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/util/random/Probability.java b/src/main/java/com/gmail/nossr50/util/random/Probability.java index a4d8c848c8..52131dac30 100644 --- a/src/main/java/com/gmail/nossr50/util/random/Probability.java +++ b/src/main/java/com/gmail/nossr50/util/random/Probability.java @@ -9,16 +9,28 @@ public interface Probability { /** * The value of this Probability * Should return a result between 0 and 1 (inclusive) - * 1 should represent something that will always succeed - * 0.5 should represent something that succeeds around half the time - * etc + * A value of 1 or greater represents something that will always succeed + * A value of around 0.5 represents something that succeeds around half the time + * A value of 0 represents something that will always fail * * @return the value of probability */ double getValue(); - static @NotNull Probability ofPercent(double percentageValue) { - return new ProbabilityImpl(percentageValue); + /** + * Create a new Probability with the given value + * A value of 100 would represent 100% chance of success + * A value of 50 would represent 50% chance of success + * A value of 0 would represent 0% chance of success + * A value of 1 would represent 1% chance of success + * A value of 0.5 would represent 0.5% chance of success + * A value of 0.01 would represent 0.01% chance of success + * + * @param percentage the value of the probability + * @return a new Probability with the given value + */ + static @NotNull Probability ofPercent(double percentage) { + return new ProbabilityImpl(percentage); } /** @@ -29,7 +41,7 @@ public interface Probability { * @return true for succeeding, false for failing */ static private boolean isSuccessfulRoll(double probabilityValue) { - return (probabilityValue * 100) >= ThreadLocalRandom.current().nextDouble(100D); + return (probabilityValue) >= ThreadLocalRandom.current().nextDouble(1D); } /** diff --git a/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java b/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java index 4898058070..e240f2f072 100644 --- a/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java +++ b/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java @@ -10,14 +10,15 @@ public class ProbabilityImpl implements Probability { /** * Create a probability with a static value * - * @param staticProbability the value to assign to this probability + * @param percentage the percentage value of the probability */ - ProbabilityImpl(double staticProbability) throws ValueOutOfBoundsException { - if (staticProbability < 0) { + ProbabilityImpl(double percentage) throws ValueOutOfBoundsException { + if (percentage < 0) { throw new ValueOutOfBoundsException("Value should never be negative for Probability! This suggests a coding mistake, contact the devs!"); } - probabilityValue = staticProbability; + // Convert to a 0-1 floating point representation + probabilityValue = percentage / 100.0D; } ProbabilityImpl(double xPos, double xCeiling, double probabilityCeiling) throws ValueOutOfBoundsException { diff --git a/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java b/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java index d401827347..a2b6cc416e 100644 --- a/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java +++ b/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java @@ -78,7 +78,7 @@ void testAlwaysLoseOfPercent() { @ParameterizedTest @MethodSource("provideProbabilitiesForWithinExpectations") - void testOddsExpectationsImplConstructor(Probability probability, double expectedWinPercent) { + void testOddsExpectationsConstructor(Probability probability, double expectedWinPercent) { assertExpectations(probability, expectedWinPercent); } From 02c5aa4628c4f4badd8cdc3a6181bceb251a17b3 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 3 Apr 2023 16:53:57 -0700 Subject: [PATCH 25/75] Remove unused config values --- .../datatypes/skills/SubSkillType.java | 13 ---- src/main/resources/skillranks.yml | 65 ------------------- 2 files changed, 78 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java index c8f4cc9260..3fc3af77b5 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java @@ -12,19 +12,16 @@ public enum SubSkillType { /* ACROBATICS */ ACROBATICS_DODGE(1), ACROBATICS_ROLL, - ACROBATICS_MASTERY(1), /* ALCHEMY */ ALCHEMY_CATALYSIS(1), ALCHEMY_CONCOCTIONS(8), - ALCHEMY_MASTERY(1), /* ARCHERY */ ARCHERY_ARROW_RETRIEVAL(1), ARCHERY_DAZE, ARCHERY_SKILL_SHOT(20), ARCHERY_ARCHERY_LIMIT_BREAK(10), - ARCHERY_MASTERY(1), /* Axes */ AXES_ARMOR_IMPACT(20), @@ -33,7 +30,6 @@ public enum SubSkillType { AXES_CRITICAL_STRIKES(1), AXES_GREATER_IMPACT(1), AXES_SKULL_SPLITTER(1), - AXES_MASTERY(1), /* Excavation */ EXCAVATION_ARCHAEOLOGY(8), @@ -46,7 +42,6 @@ public enum SubSkillType { FISHING_MASTER_ANGLER(8), FISHING_TREASURE_HUNTER(8), FISHING_SHAKE(1), - FISHING_MASTERY(1), /* Herbalism */ HERBALISM_DOUBLE_DROPS(1), @@ -56,7 +51,6 @@ public enum SubSkillType { HERBALISM_GREEN_THUMB(4), HERBALISM_HYLIAN_LUCK, HERBALISM_SHROOM_THUMB, - HERBALISM_MASTERY(1), /* Mining */ MINING_BIGGER_BOMBS(1), @@ -70,7 +64,6 @@ public enum SubSkillType { REPAIR_ARCANE_FORGING(8), REPAIR_REPAIR_MASTERY(1), REPAIR_SUPER_REPAIR(1), - REPAIR_MASTERY(1), /* Salvage */ SALVAGE_SCRAP_COLLECTOR(8), @@ -87,7 +80,6 @@ public enum SubSkillType { SWORDS_SERRATED_STRIKES(1), SWORDS_STAB(2), SWORDS_SWORDS_LIMIT_BREAK(10), - SWORDS_MASTERY(1), /* Taming */ TAMING_BEAST_LORE(1), @@ -100,7 +92,6 @@ public enum SubSkillType { TAMING_SHARPENED_CLAWS(1), TAMING_SHOCK_PROOF(1), TAMING_THICK_FUR(1), - TAMING_MASTERY(1), /* Unarmed */ UNARMED_ARROW_DEFLECT(1), @@ -110,15 +101,11 @@ public enum SubSkillType { UNARMED_STEEL_ARM_STYLE(20), UNARMED_IRON_GRIP(1), UNARMED_UNARMED_LIMIT_BREAK(10), - UNARMED_MASTERY(1), /* Woodcutting */ -/* WOODCUTTING_BARK_SURGEON(3),*/ WOODCUTTING_KNOCK_ON_WOOD(2), WOODCUTTING_HARVEST_LUMBER(1), WOODCUTTING_LEAF_BLOWER(1), -/* WOODCUTTING_NATURES_BOUNTY(3), - WOODCUTTING_SPLINTER(3),*/ WOODCUTTING_TREE_FELLER(1), WOODCUTTING_CLEAN_CUTS(1); diff --git a/src/main/resources/skillranks.yml b/src/main/resources/skillranks.yml index fa300973b9..f5980b8d4d 100644 --- a/src/main/resources/skillranks.yml +++ b/src/main/resources/skillranks.yml @@ -6,11 +6,6 @@ # Retro Mode has 10x faster leveling and 10x higher skill requirements, if you do the math you can see its the same as Standard and only cosmetic!. ### Alchemy: - Mastery: - Standard: - Rank_1: 100 - RetroMode: - Rank_1: 1000 Catalysis: Standard: Rank_1: 0 @@ -36,11 +31,6 @@ Alchemy: Rank_7: 900 Rank_8: 1000 Archery: - Mastery: - Standard: - Rank_1: 100 - RetroMode: - Rank_1: 1000 ArcheryLimitBreak: Standard: Rank_1: 10 @@ -113,22 +103,12 @@ Archery: Rank_19: 950 Rank_20: 1000 Acrobatics: - Mastery: - Standard: - Rank_1: 100 - RetroMode: - Rank_1: 1000 Dodge: Standard: Rank_1: 1 RetroMode: Rank_1: 1 Axes: - Mastery: - Standard: - Rank_1: 100 - RetroMode: - Rank_1: 1000 AxesLimitBreak: Standard: Rank_1: 10 @@ -222,11 +202,6 @@ Axes: Rank_3: 150 Rank_4: 200 Taming: - Mastery: - Standard: - Rank_1: 100 - RetroMode: - Rank_1: 1000 BeastLore: Standard: Rank_1: 1 @@ -278,11 +253,6 @@ Taming: RetroMode: Rank_1: 750 Smelting: - Mastery: - Standard: - Rank_1: 100 - RetroMode: - Rank_1: 1000 FuelEfficiency: Standard: Rank_1: 10 @@ -312,11 +282,6 @@ Smelting: Rank_7: 850 Rank_8: 1000 Salvage: - Mastery: - Standard: - Rank_1: 100 - RetroMode: - Rank_1: 1000 ScrapCollector: Standard: Rank_1: 1 @@ -403,11 +368,6 @@ Mining: Rank_7: 850 Rank_8: 1000 Herbalism: - Mastery: - Standard: - Rank_1: 100 - RetroMode: - Rank_1: 1000 DoubleDrops: Standard: Rank_1: 1 @@ -520,11 +480,6 @@ Fishing: Rank_7: 850 Rank_8: 1000 Swords: - Mastery: - Standard: - Rank_1: 100 - RetroMode: - Rank_1: 1000 SwordsLimitBreak: Standard: Rank_1: 10 @@ -577,11 +532,6 @@ Swords: RetroMode: Rank_1: 50 Unarmed: - Mastery: - Standard: - Rank_1: 100 - RetroMode: - Rank_1: 1000 UnarmedLimitBreak: Standard: Rank_1: 10 @@ -670,11 +620,6 @@ Unarmed: Rank_20: 1000 Woodcutting: - Mastery: - Standard: - Rank_1: 100 - RetroMode: - Rank_1: 1000 TreeFeller: Standard: Rank_1: 5 @@ -715,11 +660,6 @@ Woodcutting: Rank_2: 350 Rank_3: 650 Excavation: - Mastery: - Standard: - Rank_1: 100 - RetroMode: - Rank_1: 1000 GigaDrillBreaker: Standard: Rank_1: 5 @@ -745,11 +685,6 @@ Excavation: Rank_7: 850 Rank_8: 1000 Repair: - Mastery: - Standard: - Rank_1: 100 - RetroMode: - Rank_1: 1000 RepairMastery: Standard: Rank_1: 1 From 8bb50fb53cb4c90032fc47384337835fef60ae54 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 3 Apr 2023 17:57:33 -0700 Subject: [PATCH 26/75] Add Tridents/Xbows (WIP) --- .../commands/skills/CrossbowsCommand.java | 51 +++++++++++++++++++ .../commands/skills/PowerLevelCommand.java | 1 - .../gmail/nossr50/config/BukkitConfig.java | 5 +- .../database/FlatFileDatabaseManager.java | 18 ++++++- .../nossr50/datatypes/player/McMMOPlayer.java | 7 +++ .../datatypes/skills/PrimarySkillType.java | 2 + .../datatypes/skills/SubSkillType.java | 3 ++ .../datatypes/skills/SuperAbilityType.java | 14 +++++ .../nossr50/datatypes/skills/ToolType.java | 8 ++- .../nossr50/listeners/BlockListener.java | 1 - .../nossr50/listeners/InventoryListener.java | 1 - .../nossr50/listeners/WorldListener.java | 3 -- src/main/java/com/gmail/nossr50/mcMMO.java | 1 - .../runnables/skills/AwardCombatXpTask.java | 1 - .../skills/crossbows/CrossbowsManager.java | 11 ++++ .../nossr50/skills/mining/MiningManager.java | 1 - .../skills/tridents/TridentsManager.java | 11 ++++ .../com/gmail/nossr50/util/EventUtils.java | 2 - .../com/gmail/nossr50/util/ItemUtils.java | 5 +- .../gmail/nossr50/util/MaterialMapStore.java | 12 +++-- .../com/gmail/nossr50/util/Permissions.java | 3 +- .../commands/CommandRegistrationManager.java | 6 +++ .../nossr50/util/random/Probability.java | 1 - src/main/resources/experience.yml | 8 +++ .../resources/locale/locale_en_US.properties | 11 ++++ src/main/resources/plugin.yml | 36 ------------- src/main/resources/skillranks.yml | 6 +++ .../database/FlatFileDatabaseManagerTest.java | 9 ++-- .../woodcutting/WoodcuttingManagerTest.java | 2 +- .../util/random/ProbabilityUtilTest.java | 3 -- src/test/resources/healthydb.users | 6 +-- src/test/resources/olderdb.users | 3 ++ 32 files changed, 183 insertions(+), 69 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java create mode 100644 src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java create mode 100644 src/main/java/com/gmail/nossr50/skills/tridents/TridentsManager.java create mode 100644 src/test/resources/olderdb.users diff --git a/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java new file mode 100644 index 0000000000..c9556c98be --- /dev/null +++ b/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java @@ -0,0 +1,51 @@ +package com.gmail.nossr50.commands.skills; + +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.skills.RankUtils; +import com.gmail.nossr50.util.text.TextComponentFactory; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +public class CrossbowsCommand extends SkillCommand { + private boolean canSSG; + + public CrossbowsCommand() { + super(PrimarySkillType.CROSSBOWS); + } + + @Override + protected void dataCalculations(Player player, float skillValue) { + // TODO: Implement data calculations + } + + @Override + protected void permissionsCheck(Player player) { + canSSG = RankUtils.hasUnlockedSubskill(player, SubSkillType.CROSSBOWS_SUPER_SHOTGUN) + && Permissions.superShotgun(player); + } + + @Override + protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { + List messages = new ArrayList<>(); + + if (canSSG) { + //TODO: Implement SSG + } + + return messages; + } + + @Override + protected List getTextComponents(Player player) { + List textComponents = new ArrayList<>(); + + TextComponentFactory.getSubSkillTextComponents(player, textComponents, PrimarySkillType.CROSSBOWS); + + return textComponents; + } +} diff --git a/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java index 425dc1604c..42e9a2c13f 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java @@ -7,7 +7,6 @@ import co.aikar.commands.annotation.Conditions; import co.aikar.commands.annotation.Default; import com.gmail.nossr50.commands.CommandManager; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.player.UserManager; diff --git a/src/main/java/com/gmail/nossr50/config/BukkitConfig.java b/src/main/java/com/gmail/nossr50/config/BukkitConfig.java index e1bd830cdf..5e7b82c901 100644 --- a/src/main/java/com/gmail/nossr50/config/BukkitConfig.java +++ b/src/main/java/com/gmail/nossr50/config/BukkitConfig.java @@ -5,10 +5,9 @@ import org.bukkit.configuration.file.YamlConfiguration; import org.jetbrains.annotations.NotNull; -import java.io.*; -import java.util.HashSet; +import java.io.File; +import java.io.IOException; import java.util.List; -import java.util.Set; public abstract class BukkitConfig { public static final String CONFIG_PATCH_PREFIX = "ConfigPatchVersion:"; diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index 7325f61fe4..216cb3d9a9 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -79,8 +79,14 @@ public final class FlatFileDatabaseManager implements DatabaseManager { public static final int SCOREBOARD_TIPS = 42; public static final int COOLDOWN_CHIMAERA_WING = 43; public static final int OVERHAUL_LAST_LOGIN = 44; + public static final int EXP_CROSSBOWS = 45; + public static final int SKILLS_CROSSBOWS = 46; + public static final int EXP_TRIDENTS = 47; + public static final int SKILLS_TRIDENTS = 48; + public static final int COOLDOWN_SUPER_SHOTGUN = 49; + public static final int COOLDOWN_TRIDENTS = 50; - public static final int DATA_ENTRY_COUNT = OVERHAUL_LAST_LOGIN + 1; //Update this everytime new data is added + public static final int DATA_ENTRY_COUNT = COOLDOWN_TRIDENTS + 1; //Update this everytime new data is added protected FlatFileDatabaseManager(@NotNull File usersFile, @NotNull Logger logger, long purgeTime, int startingLevel, boolean testing) { this.usersFile = usersFile; @@ -465,6 +471,10 @@ public void writeUserToLine(@NotNull PlayerProfile profile, @NotNull Appendable appendable.append(String.valueOf(profile.getScoreboardTipsShown())).append(":"); appendable.append(String.valueOf(profile.getUniqueData(UniqueDataType.CHIMAERA_WING_DATS))).append(":"); appendable.append(String.valueOf(profile.getLastLogin())).append(":"); //overhaul last login + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.CROSSBOWS))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.CROSSBOWS))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.TRIDENTS))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.TRIDENTS))).append(":"); appendable.append("\r\n"); } @@ -1222,6 +1232,8 @@ private PlayerProfile loadFromLine(@NotNull String[] character) { tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.ACROBATICS, EXP_ACROBATICS, username); tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.FISHING, EXP_FISHING, username); tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.ALCHEMY, EXP_ALCHEMY, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.CROSSBOWS, EXP_CROSSBOWS, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.TRIDENTS, EXP_TRIDENTS, username); // Taming - Unused tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SUPER_BREAKER, COOLDOWN_SUPER_BREAKER, username); @@ -1235,6 +1247,8 @@ private PlayerProfile loadFromLine(@NotNull String[] character) { tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SKULL_SPLITTER, COOLDOWN_SKULL_SPLITTER, username); // Acrobatics - Unused tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.BLAST_MINING, COOLDOWN_BLAST_MINING, username); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SUPER_SHOTGUN, COOLDOWN_SUPER_SHOTGUN, username); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.TRIDENT_ABILITY, COOLDOWN_TRIDENTS, username); UUID uuid; try { @@ -1315,6 +1329,8 @@ private void tryLoadSkillIntValuesFromRawData(@NotNull Map bows; private final @NotNull HashSet crossbows; private final @NotNull HashSet tools; - private final @NotNull HashSet enchantables; private final @NotNull HashSet ores; @@ -819,6 +815,14 @@ public boolean isCrossbow(@NotNull String id) { return crossbows.contains(id); } + public boolean isTrident(@NotNull Material material) { + return isTrident(material.getKey().getKey()); + } + + public boolean isTrident(@NotNull String id) { + return tridents.contains(id); + } + public boolean isLeatherArmor(@NotNull Material material) { return isLeatherArmor(material.getKey().getKey()); } diff --git a/src/main/java/com/gmail/nossr50/util/Permissions.java b/src/main/java/com/gmail/nossr50/util/Permissions.java index 93c27fea34..a923ce6e15 100644 --- a/src/main/java/com/gmail/nossr50/util/Permissions.java +++ b/src/main/java/com/gmail/nossr50/util/Permissions.java @@ -5,7 +5,6 @@ import com.gmail.nossr50.datatypes.skills.MaterialType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; -import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.skills.RankUtils; import org.bukkit.Material; @@ -226,6 +225,8 @@ public static boolean customXpBoost(Permissible permissible, PrimarySkillType sk /* WOODCUTTING */ public static boolean treeFeller(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.woodcutting.treefeller"); } + /* CROSSBOWS */ + public static boolean superShotgun(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.crossbows.supershotgun"); } /* * PARTY diff --git a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java index 83d3054868..146858c319 100644 --- a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java +++ b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java @@ -61,6 +61,9 @@ private static void registerSkillCommands() { case AXES: command.setExecutor(new AxesCommand()); break; + case CROSSBOWS: + command.setExecutor(new CrossbowsCommand()); + break; case EXCAVATION: command.setExecutor(new ExcavationCommand()); @@ -97,6 +100,9 @@ private static void registerSkillCommands() { case TAMING: command.setExecutor(new TamingCommand()); break; + case TRIDENTS: + // TODO: Implement + break; case UNARMED: command.setExecutor(new UnarmedCommand()); diff --git a/src/main/java/com/gmail/nossr50/util/random/Probability.java b/src/main/java/com/gmail/nossr50/util/random/Probability.java index 52131dac30..4bb9dacc95 100644 --- a/src/main/java/com/gmail/nossr50/util/random/Probability.java +++ b/src/main/java/com/gmail/nossr50/util/random/Probability.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.util.random; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.VisibleForTesting; import java.util.concurrent.ThreadLocalRandom; diff --git a/src/main/resources/experience.yml b/src/main/resources/experience.yml index 88a3150dd4..c59d1508e7 100644 --- a/src/main/resources/experience.yml +++ b/src/main/resources/experience.yml @@ -77,6 +77,10 @@ Experience_Bars: Enable: true Color: BLUE BarStyle: SEGMENTED_6 + Crossbows: + Enable: true + Color: BLUE + BarStyle: SEGMENTED_6 Excavation: Enable: true Color: YELLOW @@ -113,6 +117,10 @@ Experience_Bars: Enable: true Color: RED BarStyle: SEGMENTED_6 + Tridents: + Enable: true + Color: BLUE + BarStyle: SEGMENTED_6 Unarmed: Enable: true Color: BLUE diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 35ec18c3cd..08ecdc9425 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -410,6 +410,17 @@ Salvage.Skills.Lottery.Perfect=&a&lPerfect!&r&6 You salvaged &3{1}&6 effortlessl Salvage.Skills.Lottery.Untrained=&7You aren't properly trained in salvaging. You were only able to recover &c{0}&7 materials from &a{1}&7. #Anvil (Shared between SALVAGE and REPAIR) Anvil.Unbreakable=This item is unbreakable! +#CROSSBOWS +Crossbows.Ability.Lower=&7You lower your crossbow. +Crossbows.Ability.Ready=&3You &6ready&3 your Crossbow. +Crossbows.Skills.SSG.Refresh=&aYour &eSuper Shotgun &aability is refreshed! +Crossbows.Skills.SSG.Other.On=&a{0}&2 used &Super Shotgun! +#TRIDENTS +Tridents.Ability.Lower=&7You lower your trident. +Tridents.Ability.Ready=&3You &6ready&3 your Trident. +Tridents.Skills.TA.Refresh=&aYour &eSuper &aability is refreshed! +Tridents.Skills.TA.Other.On=&a{0}&2 used Trident &Super! + #SWORDS Swords.Ability.Lower=&7You lower your sword. Swords.Ability.Ready=&3You &6ready&3 your Sword. diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 41bfa187a5..f5a0b46cce 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -258,9 +258,6 @@ permissions: children: mcmmo.ability.acrobatics.dodge: true mcmmo.ability.acrobatics.roll: true - mcmmo.ability.acrobatics.mastery: true - mcmmo.ability.acrobatics.mastery: - description: Allows access to end game progression for Acrobatics mcmmo.ability.acrobatics.dodge: description: Allows access to the Dodge ability mcmmo.ability.acrobatics.roll: @@ -275,9 +272,6 @@ permissions: children: mcmmo.ability.alchemy.catalysis: true mcmmo.ability.alchemy.concoctions: true - mcmmo.ability.alchemy.mastery: true - mcmmo.ability.alchemy.mastery: - description: Allows access to end game progression for Alchemy mcmmo.ability.alchemy.catalysis: description: Allows access to the Catalysis ability mcmmo.ability.alchemy.concoctions: @@ -294,9 +288,6 @@ permissions: mcmmo.ability.archery.daze: true mcmmo.ability.archery.arrowretrieval: true mcmmo.ability.archery.archerylimitbreak: true - mcmmo.ability.archery.mastery: true - mcmmo.ability.archery.mastery: - description: Allows access to end game progression for Archery mcmmo.ability.archery.archerylimitbreak: description: Adds damage to bows and crossbows mcmmo.ability.archery.skillshot: @@ -319,9 +310,6 @@ permissions: mcmmo.ability.axes.armorimpact: true mcmmo.ability.axes.skullsplitter: true mcmmo.ability.axes.axeslimitbreak: true - mcmmo.ability.axes.mastery: true - mcmmo.ability.axes.mastery: - description: Allows access to end game progression for Axes mcmmo.ability.axes.axeslimitbreak: description: Adds damage to axes mcmmo.ability.axes.axemastery: @@ -344,9 +332,6 @@ permissions: children: mcmmo.ability.excavation.gigadrillbreaker: true mcmmo.ability.excavation.archaeology: true - mcmmo.ability.excavation.mastery: true - mcmmo.ability.excavation.mastery: - description: Allows access to end game progression for Excavation mcmmo.ability.excavation.gigadrillbreaker: description: Allows access to the Giga Drill Breaker ability mcmmo.ability.excavation.archaeology: @@ -366,9 +351,6 @@ permissions: mcmmo.ability.fishing.shake: true mcmmo.ability.fishing.treasurehunter: true mcmmo.ability.fishing.vanillaxpboost: true - mcmmo.ability.fishing.mastery: true - mcmmo.ability.fishing.mastery: - description: Allows access to end game progression for Fishing mcmmo.ability.fishing.fishermansdiet: description: Allows access to the Fishermans's Diet ability mcmmo.ability.fishing.icefishing: @@ -528,9 +510,6 @@ permissions: mcmmo.ability.repair.stringrepair: true mcmmo.ability.repair.toolrepair: true mcmmo.ability.repair.woodrepair: true - mcmmo.ability.repair.mastery: true - mcmmo.ability.repair.mastery: - description: Allows access to end game progression for Repair mcmmo.ability.repair.arcaneforging: description: Allows access to the Arcane Forging ability mcmmo.ability.repair.armorrepair: @@ -583,9 +562,6 @@ permissions: mcmmo.ability.salvage.stringsalvage: true mcmmo.ability.salvage.toolsalvage: true mcmmo.ability.salvage.woodsalvage: true - mcmmo.ability.salvage.mastery: true - mcmmo.ability.salvage.mastery: - description: Allows access to end game progression for Salvage mcmmo.ability.salvage.scrapcollector: description: Allows access to the Scrap Collector ability mcmmo.ability.salvage.arcanesalvage: @@ -626,9 +602,6 @@ permissions: mcmmo.ability.smelting.fluxmining: true mcmmo.ability.smelting.fuelefficiency: true mcmmo.ability.smelting.vanillaxpboost: true - mcmmo.ability.smelting.mastery: true - mcmmo.ability.smelting.mastery: - description: Allows access to end game progression for Smelting mcmmo.ability.smelting.fluxmining: description: Allows access to the Flux Mining ability mcmmo.ability.smelting.fuelefficiency: @@ -650,9 +623,6 @@ permissions: mcmmo.ability.swords.counterattack: true mcmmo.ability.swords.serratedstrikes: true mcmmo.ability.swords.swordslimitbreak: true - mcmmo.ability.swords.mastery: true - mcmmo.ability.swords.mastery: - description: Allows access to end game progression for Swords mcmmo.ability.swords.stab: description: Adds damage to swords mcmmo.ability.swords.swordslimitbreak: @@ -681,9 +651,6 @@ permissions: mcmmo.ability.taming.shockproof: true mcmmo.ability.taming.thickfur: true mcmmo.ability.taming.pummel: true - mcmmo.ability.taming.mastery: true - mcmmo.ability.taming.mastery: - description: Allows access to end game progression for Taming mcmmo.ability.taming.beastlore: description: Allows access to the Beast Lore ability mcmmo.ability.taming.callofthewild.*: @@ -734,9 +701,6 @@ permissions: mcmmo.ability.unarmed.disarm: true mcmmo.ability.unarmed.irongrip: true mcmmo.ability.unarmed.unarmedlimitbreak: true - mcmmo.ability.unarmed.mastery: true - mcmmo.ability.unarmed.mastery: - description: Allows access to end game progression for Unarmed mcmmo.ability.unarmed.unarmedlimitbreak: description: Adds damage to unarmed attacks mcmmo.ability.unarmed.berserk: diff --git a/src/main/resources/skillranks.yml b/src/main/resources/skillranks.yml index f5980b8d4d..74f9745bcb 100644 --- a/src/main/resources/skillranks.yml +++ b/src/main/resources/skillranks.yml @@ -201,6 +201,12 @@ Axes: Rank_2: 100 Rank_3: 150 Rank_4: 200 +Crossbows: + SuperShotgun: + Standard: + Rank_1: 5 + RetroMode: + Rank_1: 50 Taming: BeastLore: Standard: diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index f626002c19..a3cf1fab64 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -52,16 +52,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, + expectedSSGCd = 1111, expectedTridentSuperCd = 2222; int expectedScoreboardTips = 1111; Long expectedLastLogin = 2020L; diff --git a/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManagerTest.java b/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManagerTest.java index abeadaa212..d27f54e5d3 100644 --- a/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManagerTest.java +++ b/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManagerTest.java @@ -22,13 +22,13 @@ import org.bukkit.World; 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.bukkit.plugin.PluginManager; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.bukkit.entity.Player; import org.mockito.MockedStatic; import org.mockito.Mockito; diff --git a/src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java b/src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java index 1a12913de7..36419f9e4f 100644 --- a/src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java +++ b/src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java @@ -1,12 +1,9 @@ package com.gmail.nossr50.util.random; import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.mcMMO; -import org.bukkit.entity.Player; import org.junit.jupiter.api.BeforeEach; -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; diff --git a/src/test/resources/healthydb.users b/src/test/resources/healthydb.users index 7ce5ccbad1..bba0c6f9bf 100644 --- a/src/test/resources/healthydb.users +++ b/src/test/resources/healthydb.users @@ -1,3 +1,3 @@ -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: -mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:3030: -powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1337:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:4040: \ No newline at end of file +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: +mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:3030:0:0:0:0:0:0: +powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1337:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:4040:0:0:0:0:0:0: \ No newline at end of file diff --git a/src/test/resources/olderdb.users b/src/test/resources/olderdb.users new file mode 100644 index 0000000000..7ce5ccbad1 --- /dev/null +++ b/src/test/resources/olderdb.users @@ -0,0 +1,3 @@ +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: +mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:3030: +powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1337:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:4040: \ No newline at end of file From 2c49f8ffebfa6e9f7d303bfdc761134066881725 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sat, 8 Apr 2023 16:30:32 -0700 Subject: [PATCH 27/75] Fixed failing tests + improved support for Xbows/Tridents --- .../database/FlatFileDataProcessor.java | 6 +++ .../database/FlatFileDatabaseManager.java | 26 ++++++++++--- .../database/flatfile/FlatFileDataUtil.java | 6 +++ .../database/FlatFileDatabaseManagerTest.java | 38 ++++++++++++------- 4 files changed, 56 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java index a232d86cd9..6874434775 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java @@ -276,6 +276,8 @@ private void registerData(@NotNull FlatFileDataBuilder builder) { case SKILLS_TAMING: case SKILLS_FISHING: case SKILLS_ALCHEMY: + case SKILLS_CROSSBOWS: + case SKILLS_TRIDENTS: case COOLDOWN_BERSERK: case COOLDOWN_GIGA_DRILL_BREAKER: case COOLDOWN_TREE_FELLER: @@ -286,6 +288,8 @@ private void registerData(@NotNull FlatFileDataBuilder builder) { case COOLDOWN_BLAST_MINING: case SCOREBOARD_TIPS: case COOLDOWN_CHIMAERA_WING: + case COOLDOWN_SUPER_SHOTGUN: + case COOLDOWN_TRIDENTS: return ExpectedType.INTEGER; case EXP_MINING: case EXP_WOODCUTTING: @@ -300,6 +304,8 @@ private void registerData(@NotNull FlatFileDataBuilder builder) { case EXP_TAMING: case EXP_FISHING: case EXP_ALCHEMY: + case EXP_CROSSBOWS: + case EXP_TRIDENTS: return ExpectedType.FLOAT; case UUID_INDEX: return ExpectedType.UUID; diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index 216cb3d9a9..34c8fd705a 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -611,8 +611,7 @@ public void writeUserToLine(@NotNull PlayerProfile profile, @NotNull Appendable continue; } - - //If we couldn't find anyone + // we found the player if(playerName.equalsIgnoreCase(rawSplitData[USERNAME_INDEX])) { return loadFromLine(rawSplitData); } @@ -988,6 +987,8 @@ public List getStoredUsers() { List taming = new ArrayList<>(); List fishing = new ArrayList<>(); List alchemy = new ArrayList<>(); + List crossbows = new ArrayList<>(); + List tridents = new ArrayList<>(); BufferedReader in = null; String playerName = null; @@ -1021,6 +1022,8 @@ public List getStoredUsers() { powerLevel += putStat(taming, playerName, skills.get(PrimarySkillType.TAMING)); powerLevel += putStat(unarmed, playerName, skills.get(PrimarySkillType.UNARMED)); powerLevel += putStat(woodcutting, playerName, skills.get(PrimarySkillType.WOODCUTTING)); + powerLevel += putStat(crossbows, playerName, skills.get(PrimarySkillType.CROSSBOWS)); + powerLevel += putStat(tridents, playerName, skills.get(PrimarySkillType.TRIDENTS)); putStat(powerLevels, playerName, powerLevel); } @@ -1056,6 +1059,8 @@ public List getStoredUsers() { taming.sort(c); fishing.sort(c); alchemy.sort(c); + crossbows.sort(c); + tridents.sort(c); powerLevels.sort(c); playerStatHash.put(PrimarySkillType.MINING, mining); @@ -1071,6 +1076,8 @@ public List getStoredUsers() { playerStatHash.put(PrimarySkillType.TAMING, taming); playerStatHash.put(PrimarySkillType.FISHING, fishing); playerStatHash.put(PrimarySkillType.ALCHEMY, alchemy); + playerStatHash.put(PrimarySkillType.CROSSBOWS, crossbows); + playerStatHash.put(PrimarySkillType.TRIDENTS, tridents); return LeaderboardStatus.UPDATED; } @@ -1281,12 +1288,15 @@ private PlayerProfile loadFromLine(@NotNull String[] character) { return new PlayerProfile(username, uuid, skills, skillsXp, skillsDATS, scoreboardTipsShown, uniquePlayerDataMap, lastLogin); } - private void tryLoadSkillCooldownFromRawData(@NotNull Map cooldownMap, @NotNull String[] character, @NotNull SuperAbilityType superAbilityType, int cooldownSuperBreaker, @NotNull String userName) { + private void tryLoadSkillCooldownFromRawData(@NotNull Map cooldownMap, @NotNull String[] splitData, @NotNull SuperAbilityType superAbilityType, int index, @NotNull String userName) { try { - cooldownMap.put(superAbilityType, Integer.valueOf(character[cooldownSuperBreaker])); + cooldownMap.put(superAbilityType, Integer.valueOf(splitData[index])); + } catch (IndexOutOfBoundsException e) { + // TODO: Add debug message + // set to 0 when data not found + cooldownMap.put(superAbilityType, 0); } catch (NumberFormatException e) { - logger.severe("Data corruption when trying to load the value for skill "+superAbilityType+" for player named " + userName+ " setting value to zero"); - e.printStackTrace(); + throw new NumberFormatException("Data corruption when trying to load the cooldown for skill "+superAbilityType+" for player named " + userName); } } @@ -1305,6 +1315,10 @@ private void tryLoadSkillIntValuesFromRawData(@NotNull Map flagsFound = db.checkFileHealthAndStructure(); @@ -454,14 +453,13 @@ private void testHealthyDataProfileValues(@NotNull String playerName, @NotNull U 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 @@ -486,18 +484,22 @@ private long getExpectedSuperAbilityDATS(@NotNull SuperAbilityType superAbilityT return expectedGreenTerraCd; case SKULL_SPLITTER: return expectedSkullSplitterCd; + case SUPER_SHOTGUN: + return expectedSuperShotgunCd; case TREE_FELLER: return expectedTreeFellerCd; case SERRATED_STRIKES: return expectedSerratedStrikesCd; case BLAST_MINING: return expectedBlastMiningCd; + case TRIDENT_ABILITY: + return expectedTridentSuperCd; } - return -1; + throw new RuntimeException("Values not defined for super ability not defined please add " + + "values for " + superAbilityType.toString() + " to the test"); } - //TODO: Why is this stuff a float? private float getExpectedExperienceHealthyDBEntryOne(@NotNull PrimarySkillType primarySkillType) { switch(primarySkillType) { case ACROBATICS: @@ -508,6 +510,8 @@ private float getExpectedExperienceHealthyDBEntryOne(@NotNull PrimarySkillType p return expectedExpArchery; case AXES: return expectedExpAxes; + case CROSSBOWS: + return expectedExpCrossbows; case EXCAVATION: return expectedExpExcavation; case FISHING: @@ -525,13 +529,15 @@ private float getExpectedExperienceHealthyDBEntryOne(@NotNull PrimarySkillType p 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) { @@ -544,6 +550,8 @@ private int getExpectedLevelHealthyDBEntryOne(@NotNull PrimarySkillType primaryS return expectedLvlArchery; case AXES: return expectedLvlAxes; + case CROSSBOWS: + return expectedLvlCrossbows; case EXCAVATION: return expectedLvlExcavation; case FISHING: @@ -561,13 +569,15 @@ private int getExpectedLevelHealthyDBEntryOne(@NotNull PrimarySkillType primaryS 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 From 0db1d846bc26bfd550467134ff918e6694b600a8 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sat, 8 Apr 2023 16:36:59 -0700 Subject: [PATCH 28/75] Add missing parent definitions for Xbows/Tridents --- .../gmail/nossr50/util/skills/SkillTools.java | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java index 416926fe46..b790864ded 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java @@ -171,25 +171,19 @@ public SkillTools(@NotNull mcMMO pluginRef) { } private @NotNull PrimarySkillType getSuperAbilityParent(SuperAbilityType superAbilityType) throws InvalidSkillException { - switch(superAbilityType) { - case BERSERK: - return PrimarySkillType.UNARMED; - case GREEN_TERRA: - return PrimarySkillType.HERBALISM; - case TREE_FELLER: - return PrimarySkillType.WOODCUTTING; - case SUPER_BREAKER: - case BLAST_MINING: - return PrimarySkillType.MINING; - case SKULL_SPLITTER: - return PrimarySkillType.AXES; - case SERRATED_STRIKES: - return PrimarySkillType.SWORDS; - case GIGA_DRILL_BREAKER: - return PrimarySkillType.EXCAVATION; - default: - throw new InvalidSkillException("No parent defined for super ability! "+superAbilityType.toString()); - } + return switch (superAbilityType) { + case BERSERK -> PrimarySkillType.UNARMED; + case GREEN_TERRA -> PrimarySkillType.HERBALISM; + case TREE_FELLER -> PrimarySkillType.WOODCUTTING; + case SUPER_BREAKER, BLAST_MINING -> PrimarySkillType.MINING; + case SKULL_SPLITTER -> PrimarySkillType.AXES; + case SERRATED_STRIKES -> PrimarySkillType.SWORDS; + case GIGA_DRILL_BREAKER -> PrimarySkillType.EXCAVATION; + case SUPER_SHOTGUN -> PrimarySkillType.CROSSBOWS; + case TRIDENT_ABILITY -> PrimarySkillType.TRIDENTS; + default -> + throw new InvalidSkillException("No parent defined for super ability! " + superAbilityType.toString()); + }; } /** From 534b22233d2c281992e7f081cb833a81b1cb2536 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 11 Apr 2023 03:16:24 -0700 Subject: [PATCH 29/75] More work on Xbows/Tridents --- .../commands/skills/CrossbowsCommand.java | 1 + .../commands/skills/TridentsCommand.java | 53 ++++++ .../database/FlatFileDatabaseManager.java | 2 +- .../datatypes/skills/SubSkillType.java | 3 + .../datatypes/skills/SuperAbilityType.java | 44 ++--- .../com/gmail/nossr50/util/Permissions.java | 1 + .../gmail/nossr50/util/skills/SkillTools.java | 2 +- src/main/resources/plugin.yml | 176 +++++++++++++----- src/main/resources/skillranks.yml | 6 + .../database/FlatFileDatabaseManagerTest.java | 2 +- 10 files changed, 210 insertions(+), 80 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java diff --git a/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java index c9556c98be..05e7ecabee 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java @@ -34,6 +34,7 @@ protected List statsDisplay(Player player, float skillValue, boolean has List messages = new ArrayList<>(); if (canSSG) { + messages.add("Super Shotgun"); //TODO: Implement SSG } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java new file mode 100644 index 0000000000..7431b2bca9 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java @@ -0,0 +1,53 @@ +package com.gmail.nossr50.commands.skills; + +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.skills.RankUtils; +import com.gmail.nossr50.util.text.TextComponentFactory; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +public class TridentsCommand extends SkillCommand { + + private boolean canTridentsSuper; + + public TridentsCommand() { + super(PrimarySkillType.TRIDENTS); + } + + @Override + protected void dataCalculations(Player player, float skillValue) { + // TODO: Implement data calculations + } + + @Override + protected void permissionsCheck(Player player) { + canTridentsSuper = RankUtils.hasUnlockedSubskill(player, SubSkillType.TRIDENTS_TRIDENTS_SUPER_ABILITY) + && Permissions.superShotgun(player); + } + + @Override + protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { + List messages = new ArrayList<>(); + + if (canTridentsSuper) { + messages.add("Tridents Super Ability"); + //TODO: Implement SSG + } + + return messages; + } + + @Override + protected List getTextComponents(Player player) { + List textComponents = new ArrayList<>(); + + TextComponentFactory.getSubSkillTextComponents(player, textComponents, PrimarySkillType.TRIDENTS); + + return textComponents; + } +} diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index 34c8fd705a..cc473e13dc 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -1255,7 +1255,7 @@ private PlayerProfile loadFromLine(@NotNull String[] character) { // Acrobatics - Unused tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.BLAST_MINING, COOLDOWN_BLAST_MINING, username); tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SUPER_SHOTGUN, COOLDOWN_SUPER_SHOTGUN, username); - tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.TRIDENT_ABILITY, COOLDOWN_TRIDENTS, username); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.TRIDENTS_SUPER_ABILITY, COOLDOWN_TRIDENTS, username); UUID uuid; try { diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java index aef17730a4..ead0326ca4 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java @@ -96,6 +96,9 @@ public enum SubSkillType { TAMING_SHOCK_PROOF(1), TAMING_THICK_FUR(1), + /* Tridents */ + TRIDENTS_TRIDENTS_SUPER_ABILITY(1), + /* Unarmed */ UNARMED_ARROW_DEFLECT(1), UNARMED_BERSERK(1), diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java index 099b55bc8c..a4756c5f03 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java @@ -72,7 +72,7 @@ public enum SuperAbilityType { "Crossbows.Skills.SSG.Refresh", null, "Crossbows.SubSkill.SuperShotgun.Name"), - TRIDENT_ABILITY( + TRIDENTS_SUPER_ABILITY( "Tridents.Skills.TA.On", "Tridents.Skills.TA.Off", "Tridents.Skills.TA.Other.On", @@ -188,34 +188,20 @@ public String toString() { * @return true if the player has permissions, false otherwise */ public boolean getPermissions(Player player) { - switch (this) { - case BERSERK: - return Permissions.berserk(player); - - case BLAST_MINING: - return Permissions.remoteDetonation(player); - - case GIGA_DRILL_BREAKER: - return Permissions.gigaDrillBreaker(player); - - case GREEN_TERRA: - return Permissions.greenTerra(player); - - case SERRATED_STRIKES: - return Permissions.serratedStrikes(player); - - case SKULL_SPLITTER: - return Permissions.skullSplitter(player); - - case SUPER_BREAKER: - return Permissions.superBreaker(player); - - case TREE_FELLER: - return Permissions.treeFeller(player); - - default: - return false; - } + return switch (this) { + case BERSERK -> Permissions.berserk(player); + case BLAST_MINING -> Permissions.remoteDetonation(player); + case GIGA_DRILL_BREAKER -> Permissions.gigaDrillBreaker(player); + case GREEN_TERRA -> Permissions.greenTerra(player); + case SERRATED_STRIKES -> Permissions.serratedStrikes(player); + case SKULL_SPLITTER -> Permissions.skullSplitter(player); + case SUPER_BREAKER -> Permissions.superBreaker(player); + case SUPER_SHOTGUN -> Permissions.superShotgun(player); + case TREE_FELLER -> Permissions.treeFeller(player); + case TRIDENTS_SUPER_ABILITY -> Permissions.tridentsSuper(player); + default -> + throw new RuntimeException("Unhandled SuperAbilityType in getPermissions(), devs need to add definition for " + this + "!"); + }; } /** diff --git a/src/main/java/com/gmail/nossr50/util/Permissions.java b/src/main/java/com/gmail/nossr50/util/Permissions.java index a923ce6e15..22ea4091a9 100644 --- a/src/main/java/com/gmail/nossr50/util/Permissions.java +++ b/src/main/java/com/gmail/nossr50/util/Permissions.java @@ -227,6 +227,7 @@ public static boolean customXpBoost(Permissible permissible, PrimarySkillType sk public static boolean treeFeller(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.woodcutting.treefeller"); } /* CROSSBOWS */ public static boolean superShotgun(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.crossbows.supershotgun"); } + public static boolean tridentsSuper(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.tridents.superability"); } /* * PARTY diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java index b790864ded..55eed3a89c 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java @@ -180,7 +180,7 @@ public SkillTools(@NotNull mcMMO pluginRef) { case SERRATED_STRIKES -> PrimarySkillType.SWORDS; case GIGA_DRILL_BREAKER -> PrimarySkillType.EXCAVATION; case SUPER_SHOTGUN -> PrimarySkillType.CROSSBOWS; - case TRIDENT_ABILITY -> PrimarySkillType.TRIDENTS; + case TRIDENTS_SUPER_ABILITY -> PrimarySkillType.TRIDENTS; default -> throw new InvalidSkillException("No parent defined for super ability! " + superAbilityType.toString()); }; diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index f5a0b46cce..27fdde9c71 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -19,9 +19,6 @@ load: POSTWORLD api-version: 1.13 commands: -# mmodroptreasures: -# description: An admin command used to spawn treasure drops -# permission: mcmmo.commands.droptreasures mmoxpbar: aliases: xpbarsettings description: Change XP bar settings @@ -237,6 +234,7 @@ permissions: mcmmo.ability.alchemy.all: true mcmmo.ability.archery.all: true mcmmo.ability.axes.all: true + mcmmo.ability.crossbows.all: true mcmmo.ability.excavation.all: true mcmmo.ability.fishing.all: true mcmmo.ability.herbalism.all: true @@ -246,6 +244,7 @@ permissions: mcmmo.ability.smelting.all: true mcmmo.ability.swords.all: true mcmmo.ability.taming.all: true + mcmmo.ability.tridents.all: true mcmmo.ability.unarmed.all: true mcmmo.ability.woodcutting.all: true mcmmo.ability.acrobatics.*: @@ -289,7 +288,7 @@ permissions: mcmmo.ability.archery.arrowretrieval: true mcmmo.ability.archery.archerylimitbreak: true mcmmo.ability.archery.archerylimitbreak: - description: Adds damage to bows and crossbows + description: Adds damage to bows mcmmo.ability.archery.skillshot: description: Allows bonus damage from the Archery SkillShot ability mcmmo.ability.archery.daze: @@ -322,6 +321,16 @@ permissions: description: Allows access to the Impact ability mcmmo.ability.axes.skullsplitter: description: Allows access to the Skull Splitter ability + mcmmo.ability.crossbows.*: + description: Allows access to all Crossbows abilities + children: + mcmmo.ability.crossbows.all: true + mcmmo.ability.crossbows.all: + description: Allows access to all Crossbows abilities + children: + mcmmo.ability.crossbows.supershotgun: true + mcmmo.ability.crossbows.supershotgun: + description: Allows access to the Super Shotgun ability mcmmo.ability.excavation.*: default: false description: Allows access to all Excavation abilities @@ -686,6 +695,17 @@ permissions: description: Allows access to the Thick Fur ability mcmmo.ability.taming.pummel: description: Allows access to the Pummel ability + mcmmo.ability.tridents.*: + default: false + description: Allows access to all Trident abilities + children: + mcmmo.ability.tridents.all: true + mcmmo.ability.tridents.all: + description: Allows access to all Trident abilities + children: + mcmmo.ability.tridents.superability: true + mcmmo.ability.tridents.superability: + description: Allows access to tridents super ability mcmmo.ability.unarmed.*: default: false description: Allows access to all Unarmed abilities @@ -884,29 +904,16 @@ permissions: description: Allows access to the archery command mcmmo.commands.axes: description: Allows access to the axes command + mcmmo.commands.crossbows: + description: Allows access to the crossbows command mcmmo.commands.excavation: description: Allows access to the excavation command mcmmo.commands.fishing: description: Allows access to the fishing command -# mcmmo.commands.hardcore.*: -# default: false -# description: Implies access to all mcmmo.commands.hardcore permissions -# children: -# mcmmo.commands.hardcore.all: true -# mcmmo.commands.hardcore.all: -# description: Implies access to all mcmmo.commands.hardcore permissions -# children: -# mcmmo.commands.hardcore: true -# mcmmo.commands.hardcore.modify: true -# mcmmo.commands.hardcore.toggle: true -# mcmmo.commands.hardcore: -# description: Allows access to the hardcore command -# mcmmo.commands.hardcore.modify: -# description: Allows access to the hardcore command to modify the hardcore rate -# mcmmo.commands.hardcore.toggle: -# description: Allows access to the hardcore command to toggle hardcore on/off mcmmo.commands.herbalism: description: Allows access to the herbalism command + mcmmo.commands.tridents: + description: Allows access to the tridents command mcmmo.commands.inspect.*: default: false description: Implies access to all mcmmo.commands.inspect permissions @@ -1012,6 +1019,7 @@ permissions: mcmmo.commands.mctop.alchemy: true mcmmo.commands.mctop.archery: true mcmmo.commands.mctop.axes: true + mcmmo.commands.mctop.crossbows: true mcmmo.commands.mctop.excavation: true mcmmo.commands.mctop.fishing: true mcmmo.commands.mctop.herbalism: true @@ -1021,6 +1029,7 @@ permissions: mcmmo.commands.mctop.smelting: true mcmmo.commands.mctop.swords: true mcmmo.commands.mctop.taming: true + mcmmo.commands.mctop.tridents: true mcmmo.commands.mctop.unarmed: true mcmmo.commands.mctop.woodcutting: true mcmmo.commands.mctop: @@ -1033,6 +1042,8 @@ permissions: description: Allows access to the mctop command for archery mcmmo.commands.mctop.axes: description: Allows access to the mctop command for axes + mcmmo.commands.mctop.crossbows: + description: Allows access to the mctop command for crossbows mcmmo.commands.mctop.excavation: description: Allows access to the mctop command for excavation mcmmo.commands.mctop.fishing: @@ -1051,6 +1062,8 @@ permissions: description: Allows access to the mctop command for swords mcmmo.commands.mctop.taming: description: Allows access to the mctop command for taming + mcmmo.commands.mctop.tridents: + description: Allows access to the mctop command for tridents mcmmo.commands.mctop.unarmed: description: Allows access to the mctop command for unarmed mcmmo.commands.mctop.woodcutting: @@ -1465,6 +1478,9 @@ permissions: mcmmo.perks.lucky.axes: default: false description: Gives Axes abilities & skills a 33.3% better chance to activate. + mcmmo.perks.lucky.crossbows: + default: false + description: Gives Crossbows abilities & skills a 33.3% better chance to activate. mcmmo.perks.lucky.excavation: default: false description: Gives Excavation abilities & skills a 33.3% better chance to activate. @@ -1492,6 +1508,9 @@ permissions: mcmmo.perks.lucky.taming: default: false description: Gives Taming abilities & skills a 33.3% better chance to activate. + mcmmo.perks.lucky.tridents: + default: false + description: Gives Tridents abilities & skills a 33.3% better chance to activate. mcmmo.perks.lucky.unarmed: default: false description: Gives Unarmed abilities & skills a 33.3% better chance to activate. @@ -1533,6 +1552,7 @@ permissions: mcmmo.perks.xp.150percentboost.alchemy: true mcmmo.perks.xp.150percentboost.archery: true mcmmo.perks.xp.150percentboost.axes: true + mcmmo.perks.xp.150percentboost.crossbows: true mcmmo.perks.xp.150percentboost.excavation: true mcmmo.perks.xp.150percentboost.fishing: true mcmmo.perks.xp.150percentboost.herbalism: true @@ -1541,6 +1561,7 @@ permissions: mcmmo.perks.xp.150percentboost.smelting: true mcmmo.perks.xp.150percentboost.swords: true mcmmo.perks.xp.150percentboost.taming: true + mcmmo.perks.xp.150percentboost.tridents: true mcmmo.perks.xp.150percentboost.unarmed: true mcmmo.perks.xp.150percentboost.woodcutting: true mcmmo.perks.xp.150percentboost.acrobatics: @@ -1555,6 +1576,9 @@ permissions: mcmmo.perks.xp.150percentboost.axes: default: false description: Multiplies incoming Axes XP by 2.5 + mcmmo.perks.xp.150percentboost.crossbows: + default: false + description: Multiplies incoming Crossbows XP by 2.5 mcmmo.perks.xp.150percentboost.excavation: default: false description: Multiplies incoming Excavation XP by 2.5 @@ -1579,6 +1603,9 @@ permissions: mcmmo.perks.xp.150percentboost.taming: default: false description: Multiplies incoming Taming XP by 2.5 + mcmmo.perks.xp.150percentboost.tridents: + default: false + description: Multiplies incoming Tridents XP by 2.5 mcmmo.perks.xp.150percentboost.unarmed: default: false description: Multiplies incoming Unarmed XP by 2.5 @@ -1603,6 +1630,7 @@ permissions: mcmmo.perks.xp.50percentboost.alchemy: true mcmmo.perks.xp.50percentboost.archery: true mcmmo.perks.xp.50percentboost.axes: true + mcmmo.perks.xp.50percentboost.crossbows: true mcmmo.perks.xp.50percentboost.excavation: true mcmmo.perks.xp.50percentboost.fishing: true mcmmo.perks.xp.50percentboost.herbalism: true @@ -1611,6 +1639,7 @@ permissions: mcmmo.perks.xp.50percentboost.smelting: true mcmmo.perks.xp.50percentboost.swords: true mcmmo.perks.xp.50percentboost.taming: true + mcmmo.perks.xp.50percentboost.tridents: true mcmmo.perks.xp.50percentboost.unarmed: true mcmmo.perks.xp.50percentboost.woodcutting: true mcmmo.perks.xp.50percentboost.acrobatics: @@ -1625,6 +1654,9 @@ permissions: mcmmo.perks.xp.50percentboost.axes: default: false description: Multiplies incoming Axes XP by 1.5 + mcmmo.perks.xp.50percentboost.crossbows: + default: false + description: Multiplies incoming Crossbows XP by 1.5 mcmmo.perks.xp.50percentboost.excavation: default: false description: Multiplies incoming Excavation XP by 1.5 @@ -1649,6 +1681,9 @@ permissions: mcmmo.perks.xp.50percentboost.taming: default: false description: Multiplies incoming Taming XP by 1.5 + mcmmo.perks.xp.50percentboost.tridents: + default: false + description: Multiplies incoming Tridents XP by 1.5 mcmmo.perks.xp.50percentboost.unarmed: default: false description: Multiplies incoming Unarmed XP by 1.5 @@ -1669,20 +1704,22 @@ permissions: default: false description: Multiplies incoming XP by 1.25 children: - mcmmo.perks.xp.25percentboost.acrobatics: true - mcmmo.perks.xp.25percentboost.alchemy: true - mcmmo.perks.xp.25percentboost.archery: true - mcmmo.perks.xp.25percentboost.axes: true - mcmmo.perks.xp.25percentboost.excavation: true - mcmmo.perks.xp.25percentboost.fishing: true - mcmmo.perks.xp.25percentboost.herbalism: true - mcmmo.perks.xp.25percentboost.mining: true - mcmmo.perks.xp.25percentboost.repair: true - mcmmo.perks.xp.25percentboost.smelting: true - mcmmo.perks.xp.25percentboost.swords: true - mcmmo.perks.xp.25percentboost.taming: true - mcmmo.perks.xp.25percentboost.unarmed: true - mcmmo.perks.xp.25percentboost.woodcutting: true + mcmmo.perks.xp.25percentboost.acrobatics: true + mcmmo.perks.xp.25percentboost.alchemy: true + mcmmo.perks.xp.25percentboost.archery: true + mcmmo.perks.xp.25percentboost.axes: true + mcmmo.perks.xp.25percentboost.crossbows: true + mcmmo.perks.xp.25percentboost.excavation: true + mcmmo.perks.xp.25percentboost.fishing: true + mcmmo.perks.xp.25percentboost.herbalism: true + mcmmo.perks.xp.25percentboost.mining: true + mcmmo.perks.xp.25percentboost.repair: true + mcmmo.perks.xp.25percentboost.smelting: true + mcmmo.perks.xp.25percentboost.swords: true + mcmmo.perks.xp.25percentboost.taming: true + mcmmo.perks.xp.25percentboost.tridents: true + mcmmo.perks.xp.25percentboost.unarmed: true + mcmmo.perks.xp.25percentboost.woodcutting: true mcmmo.perks.xp.25percentboost.acrobatics: default: false description: Multiplies incoming Acrobatics XP by 1.25 @@ -1695,6 +1732,9 @@ permissions: mcmmo.perks.xp.25percentboost.axes: default: false description: Multiplies incoming Axes XP by 1.25 + mcmmo.perks.xp.25percentboost.crossbows: + default: false + description: Multiplies incoming Crossbows XP by 1.25 mcmmo.perks.xp.25percentboost.excavation: default: false description: Multiplies incoming Excavation XP by 1.25 @@ -1719,6 +1759,9 @@ permissions: mcmmo.perks.xp.25percentboost.taming: default: false description: Multiplies incoming Taming XP by 1.25 + mcmmo.perks.xp.25percentboost.tridents: + default: false + description: Multiplies incoming Tridents XP by 1.25 mcmmo.perks.xp.25percentboost.unarmed: default: false description: Multiplies incoming Unarmed XP by 1.5 @@ -1743,6 +1786,7 @@ permissions: mcmmo.perks.xp.10percentboost.alchemy: true mcmmo.perks.xp.10percentboost.archery: true mcmmo.perks.xp.10percentboost.axes: true + mcmmo.perks.xp.10percentboost.crossbows: true mcmmo.perks.xp.10percentboost.excavation: true mcmmo.perks.xp.10percentboost.fishing: true mcmmo.perks.xp.10percentboost.herbalism: true @@ -1751,6 +1795,7 @@ permissions: mcmmo.perks.xp.10percentboost.smelting: true mcmmo.perks.xp.10percentboost.swords: true mcmmo.perks.xp.10percentboost.taming: true + mcmmo.perks.xp.10percentboost.tridents: true mcmmo.perks.xp.10percentboost.unarmed: true mcmmo.perks.xp.10percentboost.woodcutting: true mcmmo.perks.xp.10percentboost.acrobatics: @@ -1765,6 +1810,9 @@ permissions: mcmmo.perks.xp.10percentboost.axes: default: false description: Multiplies incoming Axes XP by 1.1 + mcmmo.perks.xp.10percentboost.crossbows: + default: false + description: Multiplies incoming Crossbows XP by 1.1 mcmmo.perks.xp.10percentboost.excavation: default: false description: Multiplies incoming Excavation XP by 1.1 @@ -1789,6 +1837,9 @@ permissions: mcmmo.perks.xp.10percentboost.taming: default: false description: Multiplies incoming Taming XP by 1.1 + mcmmo.perks.xp.10percentboost.tridents: + default: false + description: Multiplies incoming Tridents XP by 1.1 mcmmo.perks.xp.10percentboost.unarmed: default: false description: Multiplies incoming Unarmed XP by 1.1 @@ -1813,6 +1864,7 @@ permissions: mcmmo.perks.xp.customboost.alchemy: true mcmmo.perks.xp.customboost.archery: true mcmmo.perks.xp.customboost.axes: true + mcmmo.perks.xp.customboost.crossbows: true mcmmo.perks.xp.customboost.excavation: true mcmmo.perks.xp.customboost.fishing: true mcmmo.perks.xp.customboost.herbalism: true @@ -1821,6 +1873,7 @@ permissions: mcmmo.perks.xp.customboost.smelting: true mcmmo.perks.xp.customboost.swords: true mcmmo.perks.xp.customboost.taming: true + mcmmo.perks.xp.customboost.tridents: true mcmmo.perks.xp.customboost.unarmed: true mcmmo.perks.xp.customboost.woodcutting: true mcmmo.perks.xp.customboost.acrobatics: @@ -1835,6 +1888,9 @@ permissions: mcmmo.perks.xp.customboost.axes: default: false description: Multiplies incoming Axes XP by the boost amount defined in the experience config + mcmmo.perks.xp.customboost.crossbows: + default: false + description: Multiplies incoming Crossbows XP by the boost amount defined in the experience config mcmmo.perks.xp.customboost.excavation: default: false description: Multiplies incoming Excavation XP by the boost amount defined in the experience config @@ -1859,6 +1915,9 @@ permissions: mcmmo.perks.xp.customboost.taming: default: false description: Multiplies incoming Taming XP by the boost amount defined in the experience config + mcmmo.perks.xp.customboost.tridents: + default: false + description: Multiplies incoming Tridents XP by the boost amount defined in the experience config mcmmo.perks.xp.customboost.unarmed: default: false description: Multiplies incoming Unarmed XP by the boost amount defined in the experience config @@ -1883,6 +1942,7 @@ permissions: mcmmo.perks.xp.double.alchemy: true mcmmo.perks.xp.double.archery: true mcmmo.perks.xp.double.axes: true + mcmmo.perks.xp.double.crossbows: true mcmmo.perks.xp.double.excavation: true mcmmo.perks.xp.double.fishing: true mcmmo.perks.xp.double.herbalism: true @@ -1891,6 +1951,7 @@ permissions: mcmmo.perks.xp.double.smelting: true mcmmo.perks.xp.double.swords: true mcmmo.perks.xp.double.taming: true + mcmmo.perks.xp.double.tridents: true mcmmo.perks.xp.double.unarmed: true mcmmo.perks.xp.double.woodcutting: true mcmmo.perks.xp.double.acrobatics: @@ -1905,6 +1966,9 @@ permissions: mcmmo.perks.xp.double.axes: default: false description: Doubles incoming Axes XP + mcmmo.perks.xp.double.crossbows: + default: false + description: Doubles incoming Crossbows XP mcmmo.perks.xp.double.excavation: default: false description: Doubles incoming Excavation XP @@ -1929,6 +1993,9 @@ permissions: mcmmo.perks.xp.double.taming: default: false description: Doubles incoming Taming XP + mcmmo.perks.xp.double.tridents: + default: false + description: Doubles incoming Tridents XP mcmmo.perks.xp.double.unarmed: default: false description: Doubles incoming Unarmed XP @@ -1953,6 +2020,7 @@ permissions: mcmmo.perks.xp.quadruple.alchemy: true mcmmo.perks.xp.quadruple.archery: true mcmmo.perks.xp.quadruple.axes: true + mcmmo.perks.xp.quadruple.crossbows: true mcmmo.perks.xp.quadruple.excavation: true mcmmo.perks.xp.quadruple.fishing: true mcmmo.perks.xp.quadruple.herbalism: true @@ -1961,6 +2029,7 @@ permissions: mcmmo.perks.xp.quadruple.smelting: true mcmmo.perks.xp.quadruple.swords: true mcmmo.perks.xp.quadruple.taming: true + mcmmo.perks.xp.quadruple.tridents: true mcmmo.perks.xp.quadruple.unarmed: true mcmmo.perks.xp.quadruple.woodcutting: true mcmmo.perks.xp.quadruple.acrobatics: @@ -1975,6 +2044,9 @@ permissions: mcmmo.perks.xp.quadruple.axes: default: false description: Quadruples incoming Axes XP + mcmmo.perks.xp.quadruple.crossbows: + default: false + description: Quadruples incoming Crossbows XP mcmmo.perks.xp.quadruple.excavation: default: false description: Quadruples incoming Excavation XP @@ -1999,6 +2071,9 @@ permissions: mcmmo.perks.xp.quadruple.taming: default: false description: Quadruples incoming Taming XP + mcmmo.perks.xp.quadruple.tridents: + default: false + description: Quadruples incoming Tridents XP mcmmo.perks.xp.quadruple.unarmed: default: false description: Quadruples incoming Unarmed XP @@ -2023,6 +2098,7 @@ permissions: mcmmo.perks.xp.triple.alchemy: true mcmmo.perks.xp.triple.archery: true mcmmo.perks.xp.triple.axes: true + mcmmo.perks.xp.triple.crossbows: true mcmmo.perks.xp.triple.excavation: true mcmmo.perks.xp.triple.fishing: true mcmmo.perks.xp.triple.herbalism: true @@ -2031,6 +2107,7 @@ permissions: mcmmo.perks.xp.triple.smelting: true mcmmo.perks.xp.triple.swords: true mcmmo.perks.xp.triple.taming: true + mcmmo.perks.xp.triple.tridents: true mcmmo.perks.xp.triple.unarmed: true mcmmo.perks.xp.triple.woodcutting: true mcmmo.perks.xp.triple.acrobatics: @@ -2045,6 +2122,9 @@ permissions: mcmmo.perks.xp.triple.axes: default: false description: Triples incoming Axes XP + mcmmo.perks.xp.triple.crossbows: + default: false + description: Triples incoming Crossbows XP mcmmo.perks.xp.triple.excavation: default: false description: Triples incoming Excavation XP @@ -2069,6 +2149,9 @@ permissions: mcmmo.perks.xp.triple.taming: default: false description: Triples incoming Taming XP + mcmmo.perks.xp.triple.tridents: + default: false + description: Triples incoming Tridents XP mcmmo.perks.xp.triple.unarmed: default: false description: Triples incoming Unarmed XP @@ -2124,6 +2207,11 @@ permissions: children: mcmmo.ability.axes.all: true mcmmo.commands.axes: true + mcmmo.skills.crossbows: + description: Allows access to the Crossbows skill + children: + mcmmo.ability.crossbows.all: true + mcmmo.commands.crossbows: true mcmmo.skills.excavation: description: Allows access to the Excavation skill children: @@ -2169,6 +2257,11 @@ permissions: children: mcmmo.ability.taming.all: true mcmmo.commands.taming: true + mcmmo.skills.tridents: + description: Allows access to the Tridents skill + children: + mcmmo.ability.tridents.all: true + mcmmo.commands.tridents: true mcmmo.skills.unarmed: description: Allows access to the Unarmed skill children: @@ -2182,16 +2275,3 @@ permissions: mcmmo.showversion: default: true description: Show mcMMO version number in /mcmmo and motd - mcmmo.tools.*: - default: false - description: Implies all mcmmo.tools permissions. - children: - mcmmo.tools.all: true - mcmmo.tools.all: - default: false - description: Implies all mcmmo.tools permissions. - children: - mcmmo.tools.updatecheck: true - mcmmo.tools.updatecheck: - default: false - description: Notifies admins if there is a new version of mcMMO available diff --git a/src/main/resources/skillranks.yml b/src/main/resources/skillranks.yml index 74f9745bcb..455403a126 100644 --- a/src/main/resources/skillranks.yml +++ b/src/main/resources/skillranks.yml @@ -207,6 +207,12 @@ Crossbows: Rank_1: 5 RetroMode: Rank_1: 50 +Tridents: + TridentsSuperAbility: + Standard: + Rank_1: 5 + RetroMode: + Rank_1: 50 Taming: BeastLore: Standard: diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index 337162a56e..8fd37ebc99 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -492,7 +492,7 @@ private long getExpectedSuperAbilityDATS(@NotNull SuperAbilityType superAbilityT return expectedSerratedStrikesCd; case BLAST_MINING: return expectedBlastMiningCd; - case TRIDENT_ABILITY: + case TRIDENTS_SUPER_ABILITY: return expectedTridentSuperCd; } From fc9287622dfde40ec87baaeed47dfbe9b4cac0a9 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 11 Apr 2023 03:28:15 -0700 Subject: [PATCH 30/75] Add missing skill command definitions to plugin.yml --- src/main/resources/plugin.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 27fdde9c71..eccc5a451f 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -120,12 +120,18 @@ commands: archery: description: Detailed mcMMO skill info permission: mcmmo.commands.archery + crossbows: + description: Detailed mcMMO skill info + permission: mcmmo.commands.crossbows swords: description: Detailed mcMMO skill info permission: mcmmo.commands.swords taming: description: Detailed mcMMO skill info permission: mcmmo.commands.taming + tridents: + description: Detailed mcMMO skill info + permission: mcmmo.commands.tridents unarmed: description: Detailed mcMMO skill info permission: mcmmo.commands.unarmed From 5b9ab65c782cb92226a2f1c9c1a9f916c4348937 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 11 Apr 2023 03:34:02 -0700 Subject: [PATCH 31/75] Add Xbows/Tridents to combat skills list --- .../gmail/nossr50/util/skills/SkillTools.java | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java index 55eed3a89c..7e743bb41c 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java @@ -157,9 +157,26 @@ public SkillTools(@NotNull mcMMO pluginRef) { * Build categorized skill lists */ - COMBAT_SKILLS = ImmutableList.of(PrimarySkillType.ARCHERY, PrimarySkillType.AXES, PrimarySkillType.SWORDS, PrimarySkillType.TAMING, PrimarySkillType.UNARMED); - GATHERING_SKILLS = ImmutableList.of(PrimarySkillType.EXCAVATION, PrimarySkillType.FISHING, PrimarySkillType.HERBALISM, PrimarySkillType.MINING, PrimarySkillType.WOODCUTTING); - MISC_SKILLS = ImmutableList.of(PrimarySkillType.ACROBATICS, PrimarySkillType.ALCHEMY, PrimarySkillType.REPAIR, PrimarySkillType.SALVAGE, PrimarySkillType.SMELTING); + COMBAT_SKILLS = ImmutableList.of( + PrimarySkillType.ARCHERY, + PrimarySkillType.AXES, + PrimarySkillType.CROSSBOWS, + PrimarySkillType.SWORDS, + PrimarySkillType.TAMING, + PrimarySkillType.TRIDENTS, + PrimarySkillType.UNARMED); + GATHERING_SKILLS = ImmutableList.of( + PrimarySkillType.EXCAVATION, + PrimarySkillType.FISHING, + PrimarySkillType.HERBALISM, + PrimarySkillType.MINING, + PrimarySkillType.WOODCUTTING); + MISC_SKILLS = ImmutableList.of( + PrimarySkillType.ACROBATICS, + PrimarySkillType.ALCHEMY, + PrimarySkillType.REPAIR, + PrimarySkillType.SALVAGE, + PrimarySkillType.SMELTING); /* * Build formatted/localized/etc string lists From 63e7c09ed44474f0a099169c2304f7fe3f484032 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 11 Apr 2023 03:43:16 -0700 Subject: [PATCH 32/75] Added missing locale strings for Xbows/Tridents --- src/main/resources/locale/locale_en_US.properties | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 08ecdc9425..d00b2cbdc3 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -21,6 +21,7 @@ JSON.Acrobatics=Acrobatics JSON.Alchemy=Alchemy JSON.Archery=Archery JSON.Axes=Axes +JSON.Crossbows=Crossbows JSON.Excavation=Excavation JSON.Fishing=Fishing JSON.Herbalism=Herbalism @@ -29,6 +30,7 @@ JSON.Repair=Repair JSON.Salvage=Salvage JSON.Swords=Swords JSON.Taming=Taming +JSON.Tridents=Tridents JSON.Unarmed=Unarmed JSON.Woodcutting=Woodcutting JSON.URL.Website=The official mcMMO Website! @@ -88,6 +90,7 @@ Overhaul.Name.Acrobatics=Acrobatics Overhaul.Name.Alchemy=Alchemy Overhaul.Name.Archery=Archery Overhaul.Name.Axes=Axes +Overhaul.Name.Crossbows=Crossbows Overhaul.Name.Excavation=Excavation Overhaul.Name.Fishing=Fishing Overhaul.Name.Herbalism=Herbalism @@ -97,6 +100,7 @@ Overhaul.Name.Salvage=Salvage Overhaul.Name.Smelting=Smelting Overhaul.Name.Swords=Swords Overhaul.Name.Taming=Taming +Overhaul.Name.Tridents=Tridents Overhaul.Name.Unarmed=Unarmed Overhaul.Name.Woodcutting=Woodcutting # /mcMMO Command Style Stuff @@ -112,6 +116,7 @@ XPBar.Acrobatics=Acrobatics Lv.&6{0} XPBar.Alchemy=Alchemy Lv.&6{0} XPBar.Archery=Archery Lv.&6{0} XPBar.Axes=Axes Lv.&6{0} +XPBar.Crossbows=Crossbows Lv.&6{0} XPBar.Excavation=Excavation Lv.&6{0} XPBar.Fishing=Fishing Lv.&6{0} XPBar.Herbalism=Herbalism Lv.&6{0} @@ -121,6 +126,7 @@ XPBar.Salvage=Salvage Lv.&6{0} XPBar.Smelting=Smelting Lv.&6{0} XPBar.Swords=Swords Lv.&6{0} XPBar.Taming=Taming Lv.&6{0} +XPBar.Tridents=Tridents Lv.&6{0} XPBar.Unarmed=Unarmed Lv.&6{0} XPBar.Woodcutting=Woodcutting Lv.&6{0} #This is just a preset template that gets used if the 'ExtraDetails' setting is turned on in experience.yml (off by default), you can ignore this template and just edit the strings above @@ -411,15 +417,21 @@ Salvage.Skills.Lottery.Untrained=&7You aren't properly trained in salvaging. You #Anvil (Shared between SALVAGE and REPAIR) Anvil.Unbreakable=This item is unbreakable! #CROSSBOWS +Crossbows.SkillName=CROSSBOWS Crossbows.Ability.Lower=&7You lower your crossbow. Crossbows.Ability.Ready=&3You &6ready&3 your Crossbow. Crossbows.Skills.SSG.Refresh=&aYour &eSuper Shotgun &aability is refreshed! Crossbows.Skills.SSG.Other.On=&a{0}&2 used &Super Shotgun! +Crossbows.SubSkill.SuperShotgun.Name=Super Shotgun +Crossbows.Listener=Crossbows: #TRIDENTS +Tridents.SkillName=TRIDENTS Tridents.Ability.Lower=&7You lower your trident. Tridents.Ability.Ready=&3You &6ready&3 your Trident. Tridents.Skills.TA.Refresh=&aYour &eSuper &aability is refreshed! Tridents.Skills.TA.Other.On=&a{0}&2 used Trident &Super! +Tridents.SubSkill.SuperAbility.Name=Tridents Super Ability +Tridents.Listener=Tridents: #SWORDS Swords.Ability.Lower=&7You lower your sword. @@ -850,6 +862,7 @@ Commands.XPGain.Alchemy=Brewing Potions Commands.XPGain.Archery=Attacking Monsters Commands.XPGain.Axes=Attacking Monsters Commands.XPGain.Child=Gains levels from Parent Skills +Commands.XPGain.Crossbows=Attacking Monsters Commands.XPGain.Excavation=Digging and finding treasures Commands.XPGain.Fishing=Fishing (Go figure!) Commands.XPGain.Herbalism=Harvesting Herbs @@ -857,6 +870,7 @@ Commands.XPGain.Mining=Mining Stone & Ore Commands.XPGain.Repair=Repairing Commands.XPGain.Swords=Attacking Monsters Commands.XPGain.Taming=Animal Taming, or combat w/ your wolves +Commands.XPGain.Tridents=Attacking Monsters Commands.XPGain.Unarmed=Attacking Monsters Commands.XPGain.Woodcutting=Chopping down trees Commands.XPGain=&8XP GAIN: &f{0} From aaa47d3b670ec0831f9a08b7d96bb686c50fadc1 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 11 Apr 2023 04:17:29 -0700 Subject: [PATCH 33/75] Add some combat processing logic for Tridents/Xbows --- Changelog.txt | 3 + .../nossr50/datatypes/player/McMMOPlayer.java | 16 ++-- .../datatypes/skills/SubSkillType.java | 2 + .../nossr50/listeners/EntityListener.java | 24 ------ .../skills/archery/ArcheryManager.java | 2 +- .../skills/tridents/TridentsManager.java | 10 +++ .../nossr50/util/skills/CombatUtils.java | 83 ++++++++++++++++++- .../resources/locale/locale_en_US.properties | 13 ++- src/main/resources/plugin.yml | 6 ++ src/main/resources/skillranks.yml | 46 ++++++++++ 10 files changed, 169 insertions(+), 36 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 8e809c0dee..9f79298c1e 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,4 +1,7 @@ Version 2.2.000 + TODO: Add unit test to determine crossbow or bow skill + TODO: Add unit test for trident xp processing + TODO: Add missing entries to changelog (API) 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 Treasure drop rate from Shake, Fishing, Hylian, and Excavation now benefit from the Luck perk Added 'Send_To_Console' settings to chat.yml to toggle sending party or admin chat messages to console diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index bba7cea296..a0c957892d 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -233,15 +233,6 @@ public double getAttackStrength() { return attackStrength; } -// public void setAttackStrength(double attackStrength) { -// this.attackStrength = attackStrength; -// } - - /*public void hideXpBar(PrimarySkillType primarySkillType) - { - experienceBarManager.hideExperienceBar(primarySkillType); - }*/ - public @NotNull PrimarySkillType getLastSkillShownScoreboard() { return lastSkillShownScoreboard; } @@ -314,6 +305,13 @@ public ArcheryManager getArcheryManager() { public AxesManager getAxesManager() { return (AxesManager) skillManagers.get(PrimarySkillType.AXES); } + public CrossbowsManager getCrossbowsManager() { + return (CrossbowsManager) skillManagers.get(PrimarySkillType.CROSSBOWS); + } + + public TridentsManager getTridentsManager() { + return (TridentsManager) skillManagers.get(PrimarySkillType.TRIDENTS); + } public ExcavationManager getExcavationManager() { return (ExcavationManager) skillManagers.get(PrimarySkillType.EXCAVATION); diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java index ead0326ca4..433d9f2b91 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java @@ -33,6 +33,7 @@ public enum SubSkillType { /* CROSSBOWS */ CROSSBOWS_SUPER_SHOTGUN(1), + CROSSBOWS_CROSSBOWS_LIMIT_BREAK(10), /* Excavation */ EXCAVATION_ARCHAEOLOGY(8), @@ -98,6 +99,7 @@ public enum SubSkillType { /* Tridents */ TRIDENTS_TRIDENTS_SUPER_ABILITY(1), + TRIDENTS_TRIDENTS_LIMIT_BREAK(10), /* Unarmed */ UNARMED_ARROW_DEFLECT(1), diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index fc9f686be5..2bcfc65a12 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -65,30 +65,6 @@ public EntityListener(final mcMMO pluginRef) { mobMetadataService = mcMMO.getMetadataService().getMobMetadataService(); } -// @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) -// public void onBlockDropItemEvent(EntityDropItemEvent event) { -// if(event.getEntity() instanceof Block) { -// Block itemDispensingBlock = (Block) event.getEntity(); -// -// //Is it a berry bush? -// if(itemDispensingBlock.getType().toString().equalsIgnoreCase("sweet_berry_bush")) { -// //Berry Bush Time! -// if (event.getEntity().getMetadata(mcMMO.BONUS_DROPS_METAKEY).size() > 0) { -// Bukkit.broadcastMessage("Pop pop!"); -// BonusDropMeta bonusDropMeta = (BonusDropMeta) event.getEntity().getMetadata(mcMMO.BONUS_DROPS_METAKEY).get(0); -// int bonusCount = bonusDropMeta.asInt(); -// -// for (int i = 0; i < bonusCount; i++) { -// Misc.spawnItemNaturally(event.getEntity().getLocation(), event.getItemDrop().getItemStack(), ItemSpawnReason.BONUS_DROPS); -// } -// } -// } -// -// if(event.getEntity().hasMetadata(mcMMO.BONUS_DROPS_METAKEY)) -// event.getEntity().removeMetadata(mcMMO.BONUS_DROPS_METAKEY, pluginRef); -// } -// } - @EventHandler(priority = EventPriority.MONITOR) public void onEntityTransform(EntityTransformEvent event) { if(event.getEntity() instanceof LivingEntity livingEntity) { diff --git a/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java b/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java index fc8a8be28a..b463170678 100644 --- a/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java +++ b/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java @@ -52,7 +52,7 @@ public boolean canRetrieveArrows() { * @param target The {@link LivingEntity} damaged by the arrow * @param arrow The {@link Entity} who shot the arrow */ - public double distanceXpBonusMultiplier(LivingEntity target, Entity arrow) { + public static double distanceXpBonusMultiplier(LivingEntity target, Entity arrow) { //Hacky Fix - some plugins spawn arrows and assign them to players after the ProjectileLaunchEvent fires if(!arrow.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE)) return 1; diff --git a/src/main/java/com/gmail/nossr50/skills/tridents/TridentsManager.java b/src/main/java/com/gmail/nossr50/skills/tridents/TridentsManager.java index 5b52d94638..22ae802cb2 100644 --- a/src/main/java/com/gmail/nossr50/skills/tridents/TridentsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/tridents/TridentsManager.java @@ -2,10 +2,20 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.datatypes.skills.ToolType; import com.gmail.nossr50.skills.SkillManager; +import com.gmail.nossr50.util.Permissions; public class TridentsManager extends SkillManager { public TridentsManager(McMMOPlayer mmoPlayer) { super(mmoPlayer, PrimarySkillType.TRIDENTS); } + + /** + * Checks if the player can activate the Super Ability for Tridents + * @return true if the player can activate the Super Ability, false otherwise + */ + public boolean canActivateAbility() { + return mmoPlayer.getToolPreparationMode(ToolType.TRIDENTS) && Permissions.tridentsSuper(getPlayer()); + } } diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index ac9cc6388b..1427be479e 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -17,8 +17,10 @@ import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager; import com.gmail.nossr50.skills.archery.ArcheryManager; import com.gmail.nossr50.skills.axes.AxesManager; +import com.gmail.nossr50.skills.crossbows.CrossbowsManager; import com.gmail.nossr50.skills.swords.SwordsManager; import com.gmail.nossr50.skills.taming.TamingManager; +import com.gmail.nossr50.skills.tridents.TridentsManager; import com.gmail.nossr50.skills.unarmed.UnarmedManager; import com.gmail.nossr50.util.*; import com.gmail.nossr50.util.player.NotificationManager; @@ -116,6 +118,75 @@ private static void printFinalDamageDebug(@NotNull Player player, @NotNull Entit } } } + private static void processTridentCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) { + if (event.getCause() == DamageCause.THORNS) { + return; + } + + double boostedDamage = event.getDamage(); + + McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + + //Make sure the profiles been loaded + if(mcMMOPlayer == null) { + return; + } + + TridentsManager tridentsManager = mcMMOPlayer.getTridentsManager(); + + if (tridentsManager.canActivateAbility()) { + mcMMOPlayer.checkAbilityActivation(PrimarySkillType.TRIDENTS); + } + + if(canUseLimitBreak(player, target, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK)) + { + boostedDamage+=(getLimitBreakDamage(player, target, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK) * mcMMOPlayer.getAttackStrength()); + } + + event.setDamage(boostedDamage); + processCombatXP(mcMMOPlayer, target, PrimarySkillType.TRIDENTS); + + printFinalDamageDebug(player, event, mcMMOPlayer); + } + + private static void processCrossbowsCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event, @NotNull Projectile arrow) { + double initialDamage = event.getDamage(); + + McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + + //Make sure the profiles been loaded + if(mcMMOPlayer == null) { + cleanupArrowMetadata(arrow); + return; + } + + // CrossbowsManager crossbowsManager = mcMMOPlayer.getCrossbowsManager(); + +// if (crossbowsManager.canActivateAbility()) { +// mcMMOPlayer.checkAbilityActivation(PrimarySkillType.CROSSBOWS); +// } + + double boostedDamage = event.getDamage(); + + if(canUseLimitBreak(player, target, SubSkillType.CROSSBOWS_CROSSBOWS_LIMIT_BREAK)) { + boostedDamage+=getLimitBreakDamage(player, target, SubSkillType.CROSSBOWS_CROSSBOWS_LIMIT_BREAK); + } + + double distanceMultiplier = ArcheryManager.distanceXpBonusMultiplier(target, arrow); + double forceMultiplier = 1.0; + + event.setDamage(boostedDamage); + processCombatXP(mcMMOPlayer, target, PrimarySkillType.CROSSBOWS, forceMultiplier * distanceMultiplier); + + printFinalDamageDebug(player, event, mcMMOPlayer, + "Distance Multiplier: "+distanceMultiplier, + "Force Multiplier: "+forceMultiplier, + "Initial Damage: "+initialDamage, + "Final Damage: "+boostedDamage); + + //Clean data + cleanupArrowMetadata(arrow); + } private static void processAxeCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) { if (event.getCause() == DamageCause.THORNS) { @@ -277,7 +348,7 @@ private static void processArcheryCombat(@NotNull LivingEntity target, @NotNull boostedDamage+=getLimitBreakDamage(player, target, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK); } - double distanceMultiplier = archeryManager.distanceXpBonusMultiplier(target, arrow); + double distanceMultiplier = ArcheryManager.distanceXpBonusMultiplier(target, arrow); double forceMultiplier = 1.0; //Hacky Fix - some plugins spawn arrows and assign them to players after the ProjectileLaunchEvent fires if(arrow.hasMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE)) @@ -387,6 +458,15 @@ else if (ItemUtils.isUnarmed(heldItem)) { processUnarmedCombat(target, player, event); } } + else if (ItemUtils.isTrident(heldItem)) { + if (!mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.TRIDENTS, target)) { + return; + } + + if (mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.TRIDENTS)) { + processTridentCombat(target, player, event); + } + } } else if (entityType == EntityType.WOLF) { @@ -405,6 +485,7 @@ else if (entityType == EntityType.ARROW || entityType == EntityType.SPECTRAL_ARR ProjectileSource projectileSource = arrow.getShooter(); if (projectileSource instanceof Player player && mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.ARCHERY, target)) { + // TODO: Add metadata to projectiles to determine source weapon to process combat skills if (!Misc.isNPCEntityExcludingVillagers(player) && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.ARCHERY)) { processArcheryCombat(target, player, event, arrow); diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index d00b2cbdc3..ac1f969c70 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -407,7 +407,7 @@ Salvage.Skills.Adept.Level=You must be level &e{0}&c to salvage &e{1} Salvage.Skills.TooDamaged=&4This item is too damaged to be salvaged. Salvage.Skills.ArcaneFailed=&cYou were unable to extract the knowledge contained within this item. Salvage.Skills.ArcanePartial=&cYou were only able to extract some of the knowledge contained within this item. -Salvage.Skills.ArcaneSuccess=&aYou able to extract all of the knowledge contained within this item! +Salvage.Skills.ArcaneSuccess=&aYou were able to extract all the knowledge contained within this item! Salvage.Listener.Anvil=&4You have placed a Salvage anvil, use this to Salvage tools and armor. Salvage.Listener=Salvage: Salvage.SkillName=SALVAGE @@ -423,7 +423,13 @@ Crossbows.Ability.Ready=&3You &6ready&3 your Crossbow. Crossbows.Skills.SSG.Refresh=&aYour &eSuper Shotgun &aability is refreshed! Crossbows.Skills.SSG.Other.On=&a{0}&2 used &Super Shotgun! Crossbows.SubSkill.SuperShotgun.Name=Super Shotgun +Crossbows.SubSkill.SuperShotgun.Description=Shoot dozens of arrows at once +Crossbows.SubSkill.SuperShotgun.Stat=Per Projectile damage {0} +Crossbows.SubSkill.CrossbowsLimitBreak.Name=Crossbows Limit Break +Crossbows.SubSkill.CrossbowsLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether it will boost damage in PVE. +Crossbows.SubSkill.CrossbowsLimitBreak.Stat=Limit Break Max DMG Crossbows.Listener=Crossbows: + #TRIDENTS Tridents.SkillName=TRIDENTS Tridents.Ability.Lower=&7You lower your trident. @@ -431,6 +437,11 @@ Tridents.Ability.Ready=&3You &6ready&3 your Trident. Tridents.Skills.TA.Refresh=&aYour &eSuper &aability is refreshed! Tridents.Skills.TA.Other.On=&a{0}&2 used Trident &Super! Tridents.SubSkill.SuperAbility.Name=Tridents Super Ability +Tridents.SubSkill.SuperAbility.Description=N/A +Tridents.SubSkill.SuperAbility.Stat=N/A +Tridents.SubSkill.TridentsLimitBreak.Name=Tridents Limit Break +Tridents.SubSkill.TridentsLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether it will boost damage in PVE. +Tridents.SubSkill.TridentsLimitBreak.Stat=Limit Break Max DMG Tridents.Listener=Tridents: #SWORDS diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index eccc5a451f..62ec6c0326 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -335,8 +335,11 @@ permissions: description: Allows access to all Crossbows abilities children: mcmmo.ability.crossbows.supershotgun: true + mcmmo.ability.crossbows.crossbowslimitbreak: true mcmmo.ability.crossbows.supershotgun: description: Allows access to the Super Shotgun ability + mcmmo.ability.crossbows.crossbowslimitbreak: + description: Adds damage to crossbows mcmmo.ability.excavation.*: default: false description: Allows access to all Excavation abilities @@ -710,8 +713,11 @@ permissions: description: Allows access to all Trident abilities children: mcmmo.ability.tridents.superability: true + mcmmo.ability.tridents.tridentslimitbreak: true mcmmo.ability.tridents.superability: description: Allows access to tridents super ability + mcmmo.ability.tridents.tridentslimitbreak: + description: Adds damage to tridents mcmmo.ability.unarmed.*: default: false description: Allows access to all Unarmed abilities diff --git a/src/main/resources/skillranks.yml b/src/main/resources/skillranks.yml index 455403a126..ae71e50748 100644 --- a/src/main/resources/skillranks.yml +++ b/src/main/resources/skillranks.yml @@ -202,12 +202,58 @@ Axes: Rank_3: 150 Rank_4: 200 Crossbows: + CrossbowsLimitBreak: + Standard: + Rank_1: 10 + Rank_2: 20 + Rank_3: 30 + Rank_4: 40 + Rank_5: 50 + Rank_6: 60 + Rank_7: 70 + Rank_8: 80 + Rank_9: 90 + Rank_10: 100 + RetroMode: + Rank_1: 100 + Rank_2: 200 + Rank_3: 300 + Rank_4: 400 + Rank_5: 500 + Rank_6: 600 + Rank_7: 700 + Rank_8: 800 + Rank_9: 900 + Rank_10: 1000 SuperShotgun: Standard: Rank_1: 5 RetroMode: Rank_1: 50 Tridents: + TridentsLimitBreak: + Standard: + Rank_1: 10 + Rank_2: 20 + Rank_3: 30 + Rank_4: 40 + Rank_5: 50 + Rank_6: 60 + Rank_7: 70 + Rank_8: 80 + Rank_9: 90 + Rank_10: 100 + RetroMode: + Rank_1: 100 + Rank_2: 200 + Rank_3: 300 + Rank_4: 400 + Rank_5: 500 + Rank_6: 600 + Rank_7: 700 + Rank_8: 800 + Rank_9: 900 + Rank_10: 1000 TridentsSuperAbility: Standard: Rank_1: 5 From dc1d2540db435955ba9ec3e0ddf35f285737d831 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 11 Apr 2023 04:24:48 -0700 Subject: [PATCH 34/75] Fixed UnarmedManager being used for Tridents --- .../java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index a0c957892d..3039fb223f 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -214,6 +214,7 @@ private void initManager(PrimarySkillType primarySkillType) throws InvalidSkillE break; case TRIDENTS: skillManagers.put(primarySkillType, new TridentsManager(this)); + break; case UNARMED: skillManagers.put(primarySkillType, new UnarmedManager(this)); break; From 7af0bc468a93d53fd291e6612146754f586ff4f1 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 11 Apr 2023 15:39:01 -0700 Subject: [PATCH 35/75] Config files will update automatically again --- Changelog.txt | 19 +- .../com/gmail/nossr50/api/ExperienceAPI.java | 4 +- .../com/gmail/nossr50/chat/ChatManager.java | 8 +- .../chat/author/AbstractPlayerAuthor.java | 2 +- .../com/gmail/nossr50/chat/author/Author.java | 4 +- .../nossr50/chat/mailer/AdminChatMailer.java | 4 +- .../nossr50/chat/mailer/PartyChatMailer.java | 4 +- .../gmail/nossr50/config/AdvancedConfig.java | 9 +- .../gmail/nossr50/config/BukkitConfig.java | 185 +++++++----------- .../com/gmail/nossr50/config/ChatConfig.java | 2 +- .../nossr50/config/CoreSkillsConfig.java | 4 +- .../config/experience/ExperienceConfig.java | 6 - .../config/skills/repair/RepairConfig.java | 2 +- .../treasure/FishingTreasureConfig.java | 2 +- .../config/treasure/TreasureConfig.java | 2 +- .../nossr50/datatypes/player/McMMOPlayer.java | 6 +- .../datatypes/skills/interfaces/Toolable.java | 2 +- .../skills/subskills/AbstractSubSkill.java | 2 +- .../skills/subskills/interfaces/SubSkill.java | 2 +- .../nossr50/metadata/MobMetadataService.java | 4 +- .../nossr50/skills/taming/TamingManager.java | 2 +- .../java/com/gmail/nossr50/util/Misc.java | 2 +- .../util/compat/CompatibilityLayer.java | 2 +- .../util/experience/ExperienceBarWrapper.java | 5 +- .../util/platform/MajorMinorPatchVersion.java | 2 +- .../util/platform/MinecraftGameVersion.java | 2 +- .../gmail/nossr50/util/skills/RankUtils.java | 8 +- src/main/resources/chat.yml | 6 +- src/main/resources/config.yml | 19 +- src/main/resources/experience.yml | 2 +- .../resources/locale/locale_cs_CZ.properties | 2 +- .../resources/locale/locale_cy.properties | 2 +- .../resources/locale/locale_da.properties | 2 +- .../resources/locale/locale_en_US.properties | 10 +- .../resources/locale/locale_es.properties | 2 +- .../resources/locale/locale_fi.properties | 2 +- .../resources/locale/locale_it.properties | 2 +- .../resources/locale/locale_ko.properties | 2 +- .../resources/locale/locale_nl.properties | 2 +- .../resources/locale/locale_sv.properties | 2 +- .../resources/locale/locale_th_TH.properties | 2 +- src/main/resources/mods/armor.default.yml | 2 +- src/main/resources/mods/tools.default.yml | 4 +- src/main/resources/plugin.yml | 4 +- 44 files changed, 160 insertions(+), 203 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 9f79298c1e..6cdf1d6a12 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,4 +1,7 @@ Version 2.2.000 + TODO: Configs are not adding new keys and this needs to be fixed, this affects config.yml, experience.yml, etc + TODO: Add Xbows/Tridents to salvage/repair + TODO: Add unit test for combat XP values TODO: Add unit test to determine crossbow or bow skill TODO: Add unit test for trident xp processing TODO: Add missing entries to changelog @@ -1297,7 +1300,7 @@ Version 2.1.128 Fixed a bug where certain types of ore did not receive bonuses from Blast Mining Fixed a few locale errors with commands (API) Added ExperienceAPI::addCombatXP for adding combat XP to players, signature may change so its deprecated for now - mcMMO now logs whether or not its using FlatFile or SQL database on load + mcMMO now logs whether its using FlatFile or SQL database on load (1.16) Strider added to combat experience with a value of 1.2 NOTES: A more thorough look at Unarmed balance will happen in the future, the intention of this nerf is to make Unarmed less rewarding until it is leveled quite a bit. @@ -1317,7 +1320,7 @@ Version 2.1.127 Version 2.1.126 mcMMO now relies on NMS for some of its features, if NMS cannot properly be wired up when initializing mcMMO behaviours relying on NMS will either be partially supported or disabled mcMMO now has a compatibility mode, any features that require specific versions of Minecraft for full functionality will be disabled if your server is not running a compatible version, mcMMO will still function in compatibility mode, but either the feature will be modified or disabled depending on the version of the server software - New command /mmocompat - Shows information about whether or not mcMMO is fully functional or if some features are disabled due to the server software not being fully supported. Can be used by players or console. + New command /mmocompat - Shows information about whether mcMMO is fully functional or if some features are disabled due to the server software not being fully supported. Can be used by players or console. New command /mmoxpbar (alias /xpbarsettings) - Players can choose to always show XP bars or to never show XP bars on a per skill basis XPBars now last for 3 seconds before hiding instead of 2 seconds Fixed an exploit involving fishing rods @@ -1953,7 +1956,7 @@ Version 2.1.68 Fixed a bug where consuming food in the off hand did not trigger the Diet abilities Version 2.1.67 - The XP bar now reflects whether or not the player is receiving the early game boost + The XP bar now reflects whether the player is receiving the early game boost Players who are receiving an early game boost will be shown "Learning a skill..." as the title of the XP bar while gaining XP New locale string 'XPBar.Template.EarlyGameBoost' @@ -2002,7 +2005,7 @@ Version 2.1.63 Version 2.1.62 Added a new admin notification system, sensitive commands will print chat messages to "admins" (players with either Operator status or admin chat permission) Added a setting to disable the new admin notifications to config.yml 'General.AdminNotifications' (this will be more configurable in 2.2) - OPs and players with the admin chat permission will now see details about XP rate event commands regardless of whether or not the XP rate event messages are enabled + OPs and players with the admin chat permission will now see details about XP rate event commands regardless of whether the XP rate event messages are enabled Updated hu_HU locale (thanks andris155) Added XP for mining Magma_Block (default 30 XP - Update your config, see notes) Diamond tools & armor in the repair config now have a minimum level of 0 (Update your config, temporary hotfix, 2.2 addresses this issue, see notes) @@ -2010,9 +2013,9 @@ Version 2.1.62 New locale string - 'Server.ConsoleName' the name of the server console, this will be used in place of player names when sending admin notifications out if the command was used from console New locale string - 'Notifications.Admin.Format.Others' style formatting + prefix for admin notifications used in the other new strings below New locale string - 'Notifications.Admin.Format.Self' style formatting + prefix for admin command confirmations sent to the user who executed the command - New locale string - 'Notifications.Admin.XPRate.Start.Self' sent to the user who modifies the XP rate regardless of whether or not messages for the event are enabled + New locale string - 'Notifications.Admin.XPRate.Start.Self' sent to the user who modifies the XP rate regardless of whether messages for the event are enabled New locale string - 'Notifications.Admin.XPRate.Start.Others' details of who started an XP rate event are sent to players who have Operator status or admin chat permission when the command to start or modify XP of an event has been issued - New locale string - 'Notifications.Admin.XPRate.End.Self' sent to the user who ended the XP rate event regardless of whether or not messages for the event are enabled + New locale string - 'Notifications.Admin.XPRate.End.Self' sent to the user who ended the XP rate event regardless of whether messages for the event are enabled New locale string - 'Notifications.Admin.XPRate.End.Others' details of who ended an XP rate event are sent to players who have Operator status or admin chat permission when the command to end the event has been issued NOTES: @@ -3984,7 +3987,7 @@ Removed performance debugging Removed some useless settings from the config file Version 1.0.34 -Fixed the PVP setting determining whether or not you would hurt yourself from AoE Abilities +Fixed the PVP setting determining whether you would hurt yourself from AoE Abilities Added Dutch (nl) language support Super Breaker now gives the correct XP as determined by config.yml Sand Stone XP is now configurable and no longer shares the 'stone' node @@ -3994,7 +3997,7 @@ Version 1.0.33 Fixed the toggle for the Excavation drop 'Cocoa Beans' Fixed bug where Unarmed users could disarm without being bare handed Cocoa Beans now have an XP modifier in config.yml -You can now toggle whether or not Mobspawners will give XP (in config.yml) +You can now toggle whether Mobspawners will give XP (in config.yml) MySQL version now makes requests to the MySQL server less frequently (should help performance) Fixed bug with Skull Splitter hitting the user diff --git a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java index 7fb2ed7ee3..f18cd18ca1 100644 --- a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java +++ b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java @@ -41,7 +41,7 @@ public static boolean isValidSkillType(@NotNull String skillType) { /** * Start the task that gives combat XP. - * Processes combat XP like mcMMO normally would, so mcMMO will check whether or not the entity should reward XP when giving out the XP + * Processes combat XP like mcMMO normally would, so mcMMO will check whether the entity should reward XP when giving out the XP * * @param mcMMOPlayer The attacking player * @param target The defending entity @@ -56,7 +56,7 @@ public static void addCombatXP(McMMOPlayer mcMMOPlayer, LivingEntity target, Pri /** * Start the task that gives combat XP. - * Processes combat XP like mcMMO normally would, so mcMMO will check whether or not the entity should reward XP when giving out the XP + * Processes combat XP like mcMMO normally would, so mcMMO will check whether the entity should reward XP when giving out the XP * * @param mcMMOPlayer The attacking player * @param target The defending entity diff --git a/src/main/java/com/gmail/nossr50/chat/ChatManager.java b/src/main/java/com/gmail/nossr50/chat/ChatManager.java index a0a1e6f308..658f4dd16d 100644 --- a/src/main/java/com/gmail/nossr50/chat/ChatManager.java +++ b/src/main/java/com/gmail/nossr50/chat/ChatManager.java @@ -43,7 +43,7 @@ public ChatManager(@NotNull mcMMO pluginRef) { * * @param mmoPlayer target player * @param rawMessage the raw message from the player as it was typed - * @param isAsync whether or not this is getting processed via async + * @param isAsync whether this is getting processed via async */ public void processPlayerMessage(@NotNull McMMOPlayer mmoPlayer, @NotNull String rawMessage, boolean isAsync) { processPlayerMessage(mmoPlayer, mmoPlayer.getChatChannel(), rawMessage, isAsync); @@ -69,7 +69,7 @@ public void processPlayerMessage(@NotNull McMMOPlayer mmoPlayer, @NotNull String * @param mmoPlayer target player * @param chatChannel target chat channel * @param rawMessage raw chat message as it was typed - * @param isAsync whether or not this is getting processed via async + * @param isAsync whether this is getting processed via async */ private void processPlayerMessage(@NotNull McMMOPlayer mmoPlayer, @NotNull ChatChannel chatChannel, @NotNull String rawMessage, boolean isAsync) { switch (chatChannel) { @@ -155,7 +155,7 @@ public void setOrToggleChatChannel(@NotNull McMMOPlayer mmoPlayer, @NotNull Chat } /** - * Whether or not the player is allowed to send a message to the chat channel they are targeting + * Whether the player is allowed to send a message to the chat channel they are targeting * @param mmoPlayer target player * @return true if the player can send messages to that chat channel */ @@ -197,7 +197,7 @@ public boolean isChatEnabled() { } /** - * Whether or not a specific chat channel is enabled + * Whether a specific chat channel is enabled * ChatChannels are enabled/disabled via user config * * If chat is disabled, this always returns false diff --git a/src/main/java/com/gmail/nossr50/chat/author/AbstractPlayerAuthor.java b/src/main/java/com/gmail/nossr50/chat/author/AbstractPlayerAuthor.java index e2bb7c7e08..eb606af6d2 100644 --- a/src/main/java/com/gmail/nossr50/chat/author/AbstractPlayerAuthor.java +++ b/src/main/java/com/gmail/nossr50/chat/author/AbstractPlayerAuthor.java @@ -73,7 +73,7 @@ private void updateLastKnownDisplayName() { * Sanitized names are associated with a {@link ChatChannel} as different chat channels have different chat name settings * * @param chatChannel target chat channel - * @param useDisplayName whether or not to use this authors display name + * @param useDisplayName whether to use this authors display name */ private void updateSanitizedNameCache(@NotNull ChatChannel chatChannel, boolean useDisplayName) { if(useDisplayName) { diff --git a/src/main/java/com/gmail/nossr50/chat/author/Author.java b/src/main/java/com/gmail/nossr50/chat/author/Author.java index 6f45a21b72..c7c35b7e22 100644 --- a/src/main/java/com/gmail/nossr50/chat/author/Author.java +++ b/src/main/java/com/gmail/nossr50/chat/author/Author.java @@ -17,14 +17,14 @@ public interface Author extends Identity { @NotNull String getAuthoredName(@NotNull ChatChannel chatChannel); /** - * Whether or not this author is a {@link org.bukkit.command.ConsoleCommandSender} + * Whether this author is a {@link org.bukkit.command.ConsoleCommandSender} * * @return true if this author is the console */ boolean isConsole(); /** - * Whether or not this author is a {@link org.bukkit.entity.Player} + * Whether this author is a {@link org.bukkit.entity.Player} * @return true if this author is a player */ boolean isPlayer(); diff --git a/src/main/java/com/gmail/nossr50/chat/mailer/AdminChatMailer.java b/src/main/java/com/gmail/nossr50/chat/mailer/AdminChatMailer.java index 8498e518f3..5ec0f5c37a 100644 --- a/src/main/java/com/gmail/nossr50/chat/mailer/AdminChatMailer.java +++ b/src/main/java/com/gmail/nossr50/chat/mailer/AdminChatMailer.java @@ -74,8 +74,8 @@ public void sendMail(@NotNull ChatMessage chatMessage) { * * @param author the author * @param rawString the raw message as the author typed it before any styling - * @param isAsync whether or not this is being processed asynchronously - * @param canColor whether or not the author can use colors in chat + * @param isAsync whether this is being processed asynchronously + * @param canColor whether the author can use colors in chat */ public void processChatMessage(@NotNull Author author, @NotNull String rawString, boolean isAsync, boolean canColor) { AdminChatMessage chatMessage = new AdminChatMessage(pluginRef, author, constructAudience(), rawString, addStyle(author, rawString, canColor)); diff --git a/src/main/java/com/gmail/nossr50/chat/mailer/PartyChatMailer.java b/src/main/java/com/gmail/nossr50/chat/mailer/PartyChatMailer.java index 6158ad826e..ad8d8992d7 100644 --- a/src/main/java/com/gmail/nossr50/chat/mailer/PartyChatMailer.java +++ b/src/main/java/com/gmail/nossr50/chat/mailer/PartyChatMailer.java @@ -27,8 +27,8 @@ public PartyChatMailer(@NotNull Plugin pluginRef) { * * @param author the author * @param rawString the raw message as the author typed it before any styling - * @param isAsync whether or not this is being processed asynchronously - * @param canColor whether or not the author can use colors in chat + * @param isAsync whether this is being processed asynchronously + * @param canColor whether the author can use colors in chat */ public void processChatMessage(@NotNull Author author, @NotNull String rawString, @NotNull Party party, boolean isAsync, boolean canColor, boolean isLeader) { PartyChatMessage chatMessage = new PartyChatMessage(pluginRef, author, constructPartyAudience(party), rawString, addStyle(author, rawString, canColor, isLeader), party); diff --git a/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java b/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java index 25425a0a30..04cca138a7 100644 --- a/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java +++ b/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java @@ -17,11 +17,6 @@ public AdvancedConfig(File dataFolder) { validate(); } - @Override - public void initDefaults() { - config.addDefault("Skills.General.StartingLevel", 0); - } - @Override protected boolean validateKeys() { // Validate all the settings! @@ -427,7 +422,7 @@ public boolean allowPlayerTips() { /** * This returns the maximum level at which superabilities will stop lengthening from scaling alongside skill level. - * It returns a different value depending on whether or not the server is in retro mode + * It returns a different value depending on whether the server is in retro mode * * @return the level at which abilities stop increasing in length */ @@ -440,7 +435,7 @@ public int getAbilityLengthCap() { /** * This returns the frequency at which abilities will increase in length - * It returns a different value depending on whether or not the server is in retro mode + * It returns a different value depending on whether the server is in retro mode * * @return the number of levels required per ability length increase */ diff --git a/src/main/java/com/gmail/nossr50/config/BukkitConfig.java b/src/main/java/com/gmail/nossr50/config/BukkitConfig.java index 5e7b82c901..4a0f02e69f 100644 --- a/src/main/java/com/gmail/nossr50/config/BukkitConfig.java +++ b/src/main/java/com/gmail/nossr50/config/BukkitConfig.java @@ -7,52 +7,111 @@ import java.io.File; import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.List; public abstract class BukkitConfig { - public static final String CONFIG_PATCH_PREFIX = "ConfigPatchVersion:"; - public static final String CURRENT_CONFIG_PATCH_VER = "ConfigPatchVersion: 2"; - public static final char COMMENT_PREFIX = '#'; + boolean copyDefaults = true; protected final String fileName; protected final File configFile; + protected YamlConfiguration defaultYamlConfig; protected YamlConfiguration config; - protected @NotNull - final File dataFolder; + protected @NotNull final File dataFolder; public BukkitConfig(@NotNull String fileName, @NotNull File dataFolder) { mcMMO.p.getLogger().info("[config] Initializing config: " + fileName); this.fileName = fileName; this.dataFolder = dataFolder; configFile = new File(dataFolder, fileName); - // purgeComments(true); + this.defaultYamlConfig = copyDefaultConfig(); + this.config = initConfig(); + updateFile(); + mcMMO.p.getLogger().info("[config] Config initialized: " + fileName); + } + + public BukkitConfig(@NotNull String fileName, @NotNull File dataFolder, boolean copyDefaults) { + mcMMO.p.getLogger().info("[config] Initializing config: " + fileName); + this.copyDefaults = copyDefaults; + this.fileName = fileName; + this.dataFolder = dataFolder; + configFile = new File(dataFolder, fileName); + this.defaultYamlConfig = copyDefaultConfig(); this.config = initConfig(); - initDefaults(); updateFile(); mcMMO.p.getLogger().info("[config] Config initialized: " + fileName); } - @Deprecated public BukkitConfig(@NotNull String fileName) { this(fileName, mcMMO.p.getDataFolder()); } - - /** - * Initialize default values for the config - */ - public void initDefaults() {} + public BukkitConfig(@NotNull String fileName, boolean copyDefaults) { + this(fileName, mcMMO.p.getDataFolder(), copyDefaults); + } /** * Update the file on the disk by copying out any new and missing defaults */ public void updateFile() { try { + if(copyDefaults) { + copyMissingDefaultsFromResource(); + } config.save(configFile); } catch (IOException e) { e.printStackTrace(); } } - private YamlConfiguration initConfig() { + /** + * Copies missing keys and values from the internal resource config within the JAR + */ + private void copyMissingDefaultsFromResource() { + boolean updated = false; + for (String key : defaultYamlConfig.getKeys(true)) { + if (!config.contains(key)) { + config.set(key, defaultYamlConfig.get(key)); + updated = true; + } + } + + if (updated) { + updateFile(); + } + } + + /** + * Copies the config from the JAR to defaults/ + */ + YamlConfiguration copyDefaultConfig() { + mcMMO.p.getLogger().info("[config] Copying default config to disk: " + fileName + " to defaults/" + fileName); + try(InputStream inputStream = mcMMO.p.getResource(fileName)) { + if(inputStream == null) { + mcMMO.p.getLogger().severe("[config] Unable to copy default config: " + fileName); + return null; + } + + //Save default file into defaults/ + File defaultsFolder = new File(dataFolder, "defaults"); + if (!defaultsFolder.exists()) { + defaultsFolder.mkdir(); + } + File defaultFile = new File(defaultsFolder, fileName); + Path path = defaultFile.toPath(); + Files.copy(inputStream, path, java.nio.file.StandardCopyOption.REPLACE_EXISTING); + + // Load file into YAML config + YamlConfiguration defaultYamlConfig = new YamlConfiguration(); + defaultYamlConfig.load(defaultFile); + return defaultYamlConfig; + } catch (IOException | InvalidConfigurationException e) { + e.printStackTrace(); + } + return null; + } + + YamlConfiguration initConfig() { if (!configFile.exists()) { mcMMO.p.getLogger().info("[config] User config file not found, copying a default config to disk: " + fileName); mcMMO.p.saveResource(fileName, false); @@ -105,8 +164,8 @@ protected void validate() { } public void backup() { - mcMMO.p.getLogger().severe("You are using an old version of the " + fileName + " file."); - mcMMO.p.getLogger().severe("Your old file has been renamed to " + fileName + ".old and has been replaced by an updated version."); + mcMMO.p.getLogger().info("You are using an old version of the " + fileName + " file."); + mcMMO.p.getLogger().info("Your old file has been renamed to " + fileName + ".old and has been replaced by an updated version."); configFile.renameTo(new File(configFile.getPath() + ".old")); @@ -122,98 +181,4 @@ public void backup() { public File getFile() { return configFile; } - -// /** -// * Somewhere between December 2021-January 2022 Spigot updated their -// * SnakeYAML dependency/API and due to our own crappy legacy code -// * this introduced a very problematic bug where comments got duplicated -// *

-// * This method hotfixes the problem by just deleting any existing comments -// * it's ugly, but it gets the job done -// * -// * @param silentFail when true mcMMO will report errors during the patch process or debug information -// * the option to have it fail silently is because mcMMO wants to check files before they are parsed as a file with a zillion comments will fail to even load -// */ -// private void purgeComments(boolean silentFail) { -// if(!configFile.exists()) -// return; -// -// int dupedLines = 0, lineCount = 0, lineCountAfter = 0; -// try (FileReader fileReader = new FileReader(configFile); -// BufferedReader bufferedReader = new BufferedReader(fileReader)) { -// StringBuilder stringBuilder = new StringBuilder(); -// String line; -// Set seenBefore = new HashSet<>(); -// -// stringBuilder.append(CURRENT_CONFIG_PATCH_VER).append(System.lineSeparator()); -// boolean noPatchNeeded = false; -// -// // While not at the end of the file -// while ((line = bufferedReader.readLine()) != null) { -// lineCount++; -// -// if(line.startsWith(CURRENT_CONFIG_PATCH_VER)) { -// noPatchNeeded = true; -// break; -// } -// -// //Older version, don't append this line -// if(line.startsWith(CONFIG_PATCH_PREFIX)) -// continue; -// -// if (isFirstCharAsciiCharacter(line, COMMENT_PREFIX)) { -// if(seenBefore.contains(line)) -// dupedLines++; -// else -// seenBefore.add(line); -// -// continue; //Delete the line by not appending it -// } -// -// stringBuilder -// .append(line) //Convert existing files into two-spaced format -// .append(System.lineSeparator()); -// lineCountAfter++; -// } -// -// if(noPatchNeeded) -// return; -// -// if(lineCount == 0 && !silentFail) { -// mcMMO.p.getLogger().info("[config patcher] Config line count: " + lineCount); -// throw new InvalidConfigurationException("[config patcher] Patching of config file resulted in an empty file, this will not be saved. Contact the mcMMO devs!"); -// } -// -// if(dupedLines > 0 && !silentFail) { -// mcMMO.p.getLogger().info("[config patcher] Found "+dupedLines+" duplicate comments in config file: " + configFile.getName()); -// mcMMO.p.getLogger().info("[config patcher] Purging the duplicate comments... (Nothing is broken, this is just info used for debugging)"); -// mcMMO.p.getLogger().info("[config patcher] Line count before: "+lineCount); -// mcMMO.p.getLogger().info("[config patcher] Line count after: "+lineCountAfter); -// } -// -// // Write out the *patched* file -// // AKA the file without any comments -// try (FileWriter fileWriter = new FileWriter(configFile)) { -// fileWriter.write(stringBuilder.toString()); -// } -// } catch (IOException | InvalidConfigurationException ex) { -// mcMMO.p.getLogger().severe("Failed to patch config file: " + configFile.getName()); -// ex.printStackTrace(); -// } -// } - - private boolean isFirstCharAsciiCharacter(String line, char character) { - if(line == null || line.isEmpty()) { - return true; - } - - for(Character c : line.toCharArray()) { - if(c.equals(' ')) - continue; - - return c.equals(character); - } - - return false; - } } \ No newline at end of file diff --git a/src/main/java/com/gmail/nossr50/config/ChatConfig.java b/src/main/java/com/gmail/nossr50/config/ChatConfig.java index d89c1611e5..627686efb7 100644 --- a/src/main/java/com/gmail/nossr50/config/ChatConfig.java +++ b/src/main/java/com/gmail/nossr50/config/ChatConfig.java @@ -40,7 +40,7 @@ public boolean isChatChannelEnabled(@NotNull ChatChannel chatChannel) { } /** - * Whether or not to use display names for players in target {@link ChatChannel} + * Whether to use display names for players in target {@link ChatChannel} * * @param chatChannel target chat channel * diff --git a/src/main/java/com/gmail/nossr50/config/CoreSkillsConfig.java b/src/main/java/com/gmail/nossr50/config/CoreSkillsConfig.java index f92990ad6e..d172e45512 100644 --- a/src/main/java/com/gmail/nossr50/config/CoreSkillsConfig.java +++ b/src/main/java/com/gmail/nossr50/config/CoreSkillsConfig.java @@ -35,7 +35,7 @@ protected boolean validateKeys() { */ /** - * Whether or not a skill is enabled + * Whether a skill is enabled * Defaults true * * @param abstractSubSkill SubSkill definition to check @@ -47,7 +47,7 @@ public boolean isSkillEnabled(AbstractSubSkill abstractSubSkill) { } /** - * Whether or not this primary skill is enabled + * Whether this primary skill is enabled * * @param primarySkillType target primary skill * diff --git a/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java b/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java index 75686cfcd2..929fdcefe3 100644 --- a/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java +++ b/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java @@ -25,12 +25,6 @@ private ExperienceConfig() { validate(); } - @Override - public void initDefaults() { - config.addDefault("ExploitFix.Combat.XPCeiling.Enabled", true); - config.addDefault("ExploitFix.Combat.XPCeiling.Damage_Limit", 100); - } - public static ExperienceConfig getInstance() { if (instance == null) { instance = new ExperienceConfig(); diff --git a/src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfig.java b/src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfig.java index 604a18e9c1..14dafd766b 100644 --- a/src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfig.java +++ b/src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfig.java @@ -18,7 +18,7 @@ public class RepairConfig extends BukkitConfig { private List repairables; public RepairConfig(String fileName) { - super(fileName); + super(fileName, false); notSupported = new HashSet<>(); loadKeys(); } diff --git a/src/main/java/com/gmail/nossr50/config/treasure/FishingTreasureConfig.java b/src/main/java/com/gmail/nossr50/config/treasure/FishingTreasureConfig.java index 1a9dd41c5e..4239d88032 100755 --- a/src/main/java/com/gmail/nossr50/config/treasure/FishingTreasureConfig.java +++ b/src/main/java/com/gmail/nossr50/config/treasure/FishingTreasureConfig.java @@ -28,7 +28,7 @@ public class FishingTreasureConfig extends BukkitConfig { public @NotNull HashMap> shakeMap = new HashMap<>(); private FishingTreasureConfig() { - super(FILENAME); + super(FILENAME, false); loadKeys(); validate(); } diff --git a/src/main/java/com/gmail/nossr50/config/treasure/TreasureConfig.java b/src/main/java/com/gmail/nossr50/config/treasure/TreasureConfig.java index 1827188dd1..7ebf53ae77 100755 --- a/src/main/java/com/gmail/nossr50/config/treasure/TreasureConfig.java +++ b/src/main/java/com/gmail/nossr50/config/treasure/TreasureConfig.java @@ -35,7 +35,7 @@ public class TreasureConfig extends BukkitConfig { public HashMap> hylianMap = new HashMap<>(); private TreasureConfig() { - super(FILENAME); + super(FILENAME, false); loadKeys(); validate(); } diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index 3039fb223f..1e62dee8d6 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -583,7 +583,7 @@ public int getPowerLevel() { } /** - * Whether or not a player is level capped + * Whether a player is level capped * If they are at the power level cap, this will return true, otherwise it checks their skill level * @param primarySkillType * @return @@ -596,7 +596,7 @@ public boolean hasReachedLevelCap(PrimarySkillType primarySkillType) { } /** - * Whether or not a player is power level capped + * Whether a player is power level capped * Compares their power level total to the current set limit * @return true if they have reached the power level cap */ @@ -918,7 +918,7 @@ public void checkAbilityActivation(PrimarySkillType primarySkillType) { return; } - //These values change depending on whether or not the server is in retro mode + //These values change depending on whether the server is in retro mode int abilityLengthVar = mcMMO.p.getAdvancedConfig().getAbilityLength(); int abilityLengthCap = mcMMO.p.getAdvancedConfig().getAbilityLengthCap(); diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Toolable.java b/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Toolable.java index 7b817bea13..e3a448eb0c 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Toolable.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Toolable.java @@ -6,7 +6,7 @@ public interface Toolable { /** - * Whether or not this Skill requires a tool + * Whether this Skill requires a tool * Not all skills will require a tool * @return true if tool is required */ diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/AbstractSubSkill.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/AbstractSubSkill.java index 2e7c9a1f53..109ece7838 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/AbstractSubSkill.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/AbstractSubSkill.java @@ -35,7 +35,7 @@ public String getDescription() { } /** - * Whether or not this subskill is enabled + * Whether this subskill is enabled * * @return true if enabled */ diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/interfaces/SubSkill.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/interfaces/SubSkill.java index 1ca73bbdfc..33d0e9874d 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/interfaces/SubSkill.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/interfaces/SubSkill.java @@ -64,7 +64,7 @@ public interface SubSkill extends Skill { void addStats(TextComponent.Builder componentBuilder, Player player); /** - * Whether or not this subskill is enabled + * Whether this subskill is enabled * @return true if enabled */ boolean isEnabled(); diff --git a/src/main/java/com/gmail/nossr50/metadata/MobMetadataService.java b/src/main/java/com/gmail/nossr50/metadata/MobMetadataService.java index c0ff78c0c5..e78b056c9b 100644 --- a/src/main/java/com/gmail/nossr50/metadata/MobMetadataService.java +++ b/src/main/java/com/gmail/nossr50/metadata/MobMetadataService.java @@ -56,7 +56,7 @@ private void initMobFlagKeyMap() throws IncompleteNamespacedKeyRegister { } /** - * Whether or not a target {@link LivingEntity} has a specific mcMMO mob flags + * Whether a target {@link LivingEntity} has a specific mcMMO mob flags * * @param flag the type of mob flag to check for * @param livingEntity the living entity to check for metadata @@ -76,7 +76,7 @@ public boolean hasMobFlag(@NotNull MobMetaFlagType flag, @NotNull LivingEntity l } /** - * Whether or not a target {@link LivingEntity} has any mcMMO mob flags + * Whether a target {@link LivingEntity} has any mcMMO mob flags * * @param livingEntity the living entity to check for metadata * diff --git a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java index 22c56f76c8..8a2673fe76 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java @@ -463,7 +463,7 @@ private void applyMetaDataToCOTWEntity(LivingEntity summonedEntity) { } /** - * Whether or not the itemstack is used for COTW + * Whether the itemstack is used for COTW * @param itemStack target ItemStack * @return true if it is used for any COTW */ diff --git a/src/main/java/com/gmail/nossr50/util/Misc.java b/src/main/java/com/gmail/nossr50/util/Misc.java index 4342359696..19d1a5dbb3 100644 --- a/src/main/java/com/gmail/nossr50/util/Misc.java +++ b/src/main/java/com/gmail/nossr50/util/Misc.java @@ -303,7 +303,7 @@ public static Location getLocationOffset(@NotNull Location location, double stre } /** - * Whether or not a player is the party leader of a party + * Whether a player is the party leader of a party * * @param mmoPlayer target player * @return true if the player is the party leader diff --git a/src/main/java/com/gmail/nossr50/util/compat/CompatibilityLayer.java b/src/main/java/com/gmail/nossr50/util/compat/CompatibilityLayer.java index 51b240338d..5abbaa818a 100644 --- a/src/main/java/com/gmail/nossr50/util/compat/CompatibilityLayer.java +++ b/src/main/java/com/gmail/nossr50/util/compat/CompatibilityLayer.java @@ -5,7 +5,7 @@ */ public interface CompatibilityLayer { /** - * Whether or not this CompatibilityLayer successfully initialized and in theory should be functional + * Whether this CompatibilityLayer successfully initialized and in theory should be functional * @return true if this CompatibilityLayer is functional */ default boolean noErrorsOnInitialize() { return true; }; diff --git a/src/main/java/com/gmail/nossr50/util/experience/ExperienceBarWrapper.java b/src/main/java/com/gmail/nossr50/util/experience/ExperienceBarWrapper.java index 5ae2032c6e..185026ed93 100644 --- a/src/main/java/com/gmail/nossr50/util/experience/ExperienceBarWrapper.java +++ b/src/main/java/com/gmail/nossr50/util/experience/ExperienceBarWrapper.java @@ -151,7 +151,10 @@ public void showExperienceBar() private void createBossBar() { - bossBar = mcMMOPlayer.getPlayer().getServer().createBossBar(title, ExperienceConfig.getInstance().getExperienceBarColor(primarySkillType), ExperienceConfig.getInstance().getExperienceBarStyle(primarySkillType)); + bossBar = mcMMOPlayer.getPlayer().getServer().createBossBar( + title, + ExperienceConfig.getInstance().getExperienceBarColor(primarySkillType), + ExperienceConfig.getInstance().getExperienceBarStyle(primarySkillType)); bossBar.addPlayer(mcMMOPlayer.getPlayer()); } } diff --git a/src/main/java/com/gmail/nossr50/util/platform/MajorMinorPatchVersion.java b/src/main/java/com/gmail/nossr50/util/platform/MajorMinorPatchVersion.java index b933786f66..47f41a82ec 100644 --- a/src/main/java/com/gmail/nossr50/util/platform/MajorMinorPatchVersion.java +++ b/src/main/java/com/gmail/nossr50/util/platform/MajorMinorPatchVersion.java @@ -84,7 +84,7 @@ public String getVersionStr() { } /** - * Whether or not this version of Minecraft is a patch + * Whether this version of Minecraft is a patch * a patch version value above 0 will indicate that this is a patch * @return true if this version is a patch */ diff --git a/src/main/java/com/gmail/nossr50/util/platform/MinecraftGameVersion.java b/src/main/java/com/gmail/nossr50/util/platform/MinecraftGameVersion.java index ead9748252..387d831d15 100644 --- a/src/main/java/com/gmail/nossr50/util/platform/MinecraftGameVersion.java +++ b/src/main/java/com/gmail/nossr50/util/platform/MinecraftGameVersion.java @@ -28,7 +28,7 @@ public MinecraftGameVersion(int majorVerNumber, int minorVerNumber) { } /** - * Returns whether or not the Minecraft version is at least equal to or higher than a target version + * Returns whether the Minecraft version is at least equal to or higher than a target version * @param majorVerNumber target major version number - for example 1.16.5 , the 1 is the major version * @param minorVerNumber target minor version number - for example 1.16.5, the 16 is the minor version * @param patchVerNumber target patch version number - for example 1.16.5, the 5 is the patch version number diff --git a/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java b/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java index 6d8b310669..8222284353 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java @@ -107,7 +107,7 @@ public static void populateRanks() } /** - * Returns whether or not the player has unlocked the first rank in target subskill + * Returns whether the player has unlocked the first rank in target subskill * @param player the player * @param subSkillType the target subskill * @return true if the player has at least one rank in the skill @@ -121,7 +121,7 @@ public static boolean hasUnlockedSubskill(Player player, SubSkillType subSkillTy } /** - * Returns whether or not the player has unlocked the first rank in target subskill + * Returns whether the player has unlocked the first rank in target subskill * @param player the player * @param abstractSubSkill the target subskill * @return true if the player has at least one rank in the skill @@ -135,7 +135,7 @@ public static boolean hasUnlockedSubskill(Player player, AbstractSubSkill abstra } /** - * Returns whether or not the player has reached the specified rank in target subskill + * Returns whether the player has reached the specified rank in target subskill * @param rank the target rank * @param player the player * @param subSkillType the target subskill @@ -147,7 +147,7 @@ public static boolean hasReachedRank(int rank, Player player, SubSkillType subSk } /** - * Returns whether or not the player has reached the specified rank in target subskill + * Returns whether the player has reached the specified rank in target subskill * @param rank the target rank * @param player the player * @param abstractSubSkill the target subskill diff --git a/src/main/resources/chat.yml b/src/main/resources/chat.yml index ab93387b79..febf9c9f68 100644 --- a/src/main/resources/chat.yml +++ b/src/main/resources/chat.yml @@ -6,17 +6,17 @@ Chat: Party: # Enable or disable party chat Enable: true - # Whether or not to use the current display name of a player + # Whether to use the current display name of a player Use_Display_Names: true Send_To_Console: true Spies: - # Whether or not players with the chat spy permission join the server with chat spying toggled on + # Whether players with the chat spy permission join the server with chat spying toggled on Automatically_Enable_Spying: false Admin: Send_To_Console: true # Enable or disable admin chat Enable: true - # Whether or not to use the current display name of a player + # Whether to use the current display name of a player Use_Display_Names: true # CUSTOMIZATION INFORMATION # If you want to customize the look and feel of chat channels, that is handled through localization which is configurable diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 0827b53b74..4df9d2eb0b 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -10,9 +10,9 @@ General: # When players reach certain level milestones messages will be broadcast Level_Up_Chat_Broadcasts: - # Whether or not level up broadcasts are enabled + # Whether level up broadcasts are enabled Enabled: true - # Whether or not you want power level milestones to be broadcast + # Whether you want power level milestones to be broadcast Broadcast_Powerlevels: Enabled: true # How often to broadcast, you can change this to 1 to always broadcast a level up event, a setting of 100 will limit it to every 100 levels (for example level 100, level 200, etc) @@ -20,9 +20,9 @@ General: Broadcast_Targets: # Send the message to the console as well Send_To_Console: true - # Whether or not to only send chat messages to party members + # Whether to only send chat messages to party members Only_Party_Members: false - # Whether or not players who recieve a level up broadcast have to be on the same world as the one who leveled up + # Whether players who receive a level up broadcast have to be on the same world as the one who leveled up Only_Same_World: false # Distance restrictions Distance_Restrictions: @@ -34,9 +34,9 @@ General: Broadcast_Targets: # Send the message to the console as well Send_To_Console: true - # Whether or not to only send chat messages to party members + # Whether to only send chat messages to party members Only_Party_Members: false - # Whether or not players who recieve a level up broadcast have to be on the same world as the one who leveled up + # Whether players who recieve a level up broadcast have to be on the same world as the one who leveled up Only_Same_World: false # Distance restrictions Distance_Restrictions: @@ -44,7 +44,7 @@ General: # When using Restrict_Distance the blow setting configures the range of the broadcast Restricted_Radius: 100 # Turning this on will scale mcMMO around 1-1000 with default scaling factor - # Everything in your config related to skill level requirements, skill level bonuses, etc will be multiplied by 10 when this mode is on + # Everything in your config related to skill level requirements, skill level bonuses, etc. will be multiplied by 10 when this mode is on # This change is purely cosmetic, it retains the old feel of mcMMO where you could level up thousands of times RetroMode: Enabled: true @@ -63,9 +63,6 @@ General: Save_Interval: 10 # Allow mcMMO to report on basic anonymous usage Stats_Tracking: true - # Allow mcMMO to check if a new version is available - Update_Check: true - Prefer_Beta: false Power_Level_Cap: 0 # Should mcMMO truncate levels if you lower your max level cap for a skillname TruncateSkills: true @@ -151,7 +148,7 @@ Scoreboard: LevelUp_Time: 5 Mob_Healthbar: - # Enabled: Whether or not the feature is enabled at all + # Enabled: Whether the feature is enabled at all # Display_Type: Per player Default display for mob health bars - HEARTS, BAR, or DISABLED Enabled: true Display_Type: HEARTS diff --git a/src/main/resources/experience.yml b/src/main/resources/experience.yml index c59d1508e7..25e5383de9 100644 --- a/src/main/resources/experience.yml +++ b/src/main/resources/experience.yml @@ -41,7 +41,7 @@ ExploitFix: SnowGolemExcavation: true # This include NPCs from stuff like Citizens, this is not a setting for Vanilla Minecraft Villagers (Which can be considered NPCs) # mcMMO normally doesn't process attacks against an Entity if it is an NPC from another plugin - # Of course, mcMMO doesn't know for sure whether or not something is an NPC, it checks a few known things, see our source code to see how + # Of course, mcMMO doesn't know for sure whether something is an NPC, it checks a few known things, see our source code to see how PreventPluginNPCInteraction: true Fishing_ExploitFix_Options: MoveRange: 3 diff --git a/src/main/resources/locale/locale_cs_CZ.properties b/src/main/resources/locale/locale_cs_CZ.properties index 4080f60bc5..c74ce2d7e9 100644 --- a/src/main/resources/locale/locale_cs_CZ.properties +++ b/src/main/resources/locale/locale_cs_CZ.properties @@ -646,4 +646,4 @@ Scoreboard.Misc.RemainingXP=Zbývající XP Scoreboard.Misc.Overall=Celkově Commands.XPBar.Usage=Proper usage is /mmoxpbar Commands.Description.mmoxpbar=Player settings for mcMMO XP bars -Commands.Description.mmocompat=Information about mcMMO and whether or not its in compatibility mode or fully functional. +Commands.Description.mmocompat=Information about mcMMO and whether its in compatibility mode or fully functional. diff --git a/src/main/resources/locale/locale_cy.properties b/src/main/resources/locale/locale_cy.properties index 254a078d38..4689705a96 100644 --- a/src/main/resources/locale/locale_cy.properties +++ b/src/main/resources/locale/locale_cy.properties @@ -467,4 +467,4 @@ Skills.AbilityGateRequirementFail= Smelting.SubSkill.UnderstandingTheArt.Name= Commands.XPBar.Usage=Proper usage is /mmoxpbar Commands.Description.mmoxpbar=Player settings for mcMMO XP bars -Commands.Description.mmocompat=Information about mcMMO and whether or not its in compatibility mode or fully functional. +Commands.Description.mmocompat=Information about mcMMO and whether its in compatibility mode or fully functional. diff --git a/src/main/resources/locale/locale_da.properties b/src/main/resources/locale/locale_da.properties index 6207fe4333..d14a1cf0ce 100644 --- a/src/main/resources/locale/locale_da.properties +++ b/src/main/resources/locale/locale_da.properties @@ -466,4 +466,4 @@ MOTD.Version=&6[mcMMO] Kører version &3{0} MOTD.Website=&6[mcMMO] &a{0}&e - mcMMO Hjemmeside Commands.XPBar.Usage=Proper usage is /mmoxpbar Commands.Description.mmoxpbar=Player settings for mcMMO XP bars -Commands.Description.mmocompat=Information about mcMMO and whether or not its in compatibility mode or fully functional. +Commands.Description.mmocompat=Information about mcMMO and whether its in compatibility mode or fully functional. diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index ac1f969c70..596aa8629e 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -178,7 +178,7 @@ Archery.SubSkill.ArrowRetrieval.Name=Arrow Retrieval Archery.SubSkill.ArrowRetrieval.Description=Chance to retrieve arrows from corpses Archery.SubSkill.ArrowRetrieval.Stat=Arrow Recovery Chance Archery.SubSkill.ArcheryLimitBreak.Name=Archery Limit Break -Archery.SubSkill.ArcheryLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether or not it will boost damage in PVE. +Archery.SubSkill.ArcheryLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether it will boost damage in PVE. Archery.SubSkill.ArcheryLimitBreak.Stat=Limit Break Max DMG Archery.Listener=Archery: Archery.SkillName=ARCHERY @@ -206,7 +206,7 @@ Axes.SubSkill.CriticalStrikes.Stat=Critical Strike Chance Axes.SubSkill.AxeMastery.Name=Axe Mastery Axes.SubSkill.AxeMastery.Description=Adds bonus DMG Axes.SubSkill.AxesLimitBreak.Name=Axes Limit Break -Axes.SubSkill.AxesLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether or not it will boost damage in PVE. +Axes.SubSkill.AxesLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether it will boost damage in PVE. Axes.SubSkill.AxesLimitBreak.Stat=Limit Break Max DMG Axes.SubSkill.ArmorImpact.Name=Armor Impact Axes.SubSkill.ArmorImpact.Description=Strike with enough force to shatter armor @@ -466,7 +466,7 @@ Swords.SubSkill.Stab.Name=Stab Swords.SubSkill.Stab.Description=Adds bonus damage to your attacks. Swords.SubSkill.Stab.Stat=Stab Damage Swords.SubSkill.SwordsLimitBreak.Name=Swords Limit Break -Swords.SubSkill.SwordsLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether or not it will boost damage in PVE. +Swords.SubSkill.SwordsLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether it will boost damage in PVE. Swords.SubSkill.SwordsLimitBreak.Stat=Limit Break Max DMG Swords.SubSkill.Rupture.Stat=Rupture Chance Swords.SubSkill.Rupture.Stat.Extra=[[DARK_AQUA]]Rupture Duration: &e{0}s&a vs Players, &e{1}s&a vs Mobs. @@ -548,7 +548,7 @@ Unarmed.SubSkill.Disarm.Name=Disarm Unarmed.SubSkill.Disarm.Description=Drops the foes item held in hand Unarmed.SubSkill.Disarm.Stat=Disarm Chance Unarmed.SubSkill.UnarmedLimitBreak.Name=Unarmed Limit Break -Unarmed.SubSkill.UnarmedLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether or not it will boost damage in PVE. +Unarmed.SubSkill.UnarmedLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether it will boost damage in PVE. Unarmed.SubSkill.UnarmedLimitBreak.Stat=Limit Break Max DMG Unarmed.SubSkill.SteelArmStyle.Name=Steel Arm Style Unarmed.SubSkill.SteelArmStyle.Description=Hardens your arm over time @@ -1173,7 +1173,7 @@ LevelCap.PowerLevel=&6(&amcMMO&6) &eYou have reached the power level cap of &c{0 LevelCap.Skill=&6(&amcMMO&6) &eYou have reached the level cap of &c{0}&e for &6{1}&e. You will cease to level in this skill from this point on. Commands.XPBar.Usage=Proper usage is /mmoxpbar Commands.Description.mmoxpbar=Player settings for mcMMO XP bars -Commands.Description.mmocompat=Information about mcMMO and whether or not its in compatibility mode or fully functional. +Commands.Description.mmocompat=Information about mcMMO and whether its in compatibility mode or fully functional. Compatibility.Layer.Unsupported=&6Compatibility for &a{0}&6 is not supported by this version of Minecraft. Compatibility.Layer.PartialSupport=&6Compatibility for &a{0}&6 is not fully supported by this version of Minecraft, but mcMMO is running a secondary system to emulate some of the missing features. Commands.XPBar.DisableAll=&6 All mcMMO XP bars are now disabled, use /mmoxpbar reset to restore default settings. diff --git a/src/main/resources/locale/locale_es.properties b/src/main/resources/locale/locale_es.properties index 331f4c2713..1a97cd0fa8 100644 --- a/src/main/resources/locale/locale_es.properties +++ b/src/main/resources/locale/locale_es.properties @@ -674,4 +674,4 @@ Scoreboard.Misc.RemainingXP=XP restante Scoreboard.Misc.Overall=Total Commands.XPBar.Usage=Proper usage is /mmoxpbar Commands.Description.mmoxpbar=Player settings for mcMMO XP bars -Commands.Description.mmocompat=Information about mcMMO and whether or not its in compatibility mode or fully functional. +Commands.Description.mmocompat=Information about mcMMO and whether its in compatibility mode or fully functional. diff --git a/src/main/resources/locale/locale_fi.properties b/src/main/resources/locale/locale_fi.properties index fc5039a010..75570f4aa5 100644 --- a/src/main/resources/locale/locale_fi.properties +++ b/src/main/resources/locale/locale_fi.properties @@ -199,4 +199,4 @@ Stats.Header.Misc=&6-=SEKALAISET TAIDOT=- Stats.Own.Stats=&a[mcMMO] Tilastot Commands.XPBar.Usage=Proper usage is /mmoxpbar Commands.Description.mmoxpbar=Player settings for mcMMO XP bars -Commands.Description.mmocompat=Information about mcMMO and whether or not its in compatibility mode or fully functional. +Commands.Description.mmocompat=Information about mcMMO and whether its in compatibility mode or fully functional. diff --git a/src/main/resources/locale/locale_it.properties b/src/main/resources/locale/locale_it.properties index c1d7408afa..250245ed35 100644 --- a/src/main/resources/locale/locale_it.properties +++ b/src/main/resources/locale/locale_it.properties @@ -1139,4 +1139,4 @@ LevelCap.PowerLevel=&6(&amcMMO&6) &eHai raggiunto il livello massimo di potenza LevelCap.Skill=&6(&amcMMO&6) &eHai raggiunto il livello massimo di &c{0}&e per &6{1}&e. Da questo punto in poi cesserai di salire di livello in questa abilità. Commands.XPBar.Usage=Proper usage is /mmoxpbar Commands.Description.mmoxpbar=Player settings for mcMMO XP bars -Commands.Description.mmocompat=Information about mcMMO and whether or not its in compatibility mode or fully functional. +Commands.Description.mmocompat=Information about mcMMO and whether its in compatibility mode or fully functional. diff --git a/src/main/resources/locale/locale_ko.properties b/src/main/resources/locale/locale_ko.properties index aa37dac393..488fb8e82c 100644 --- a/src/main/resources/locale/locale_ko.properties +++ b/src/main/resources/locale/locale_ko.properties @@ -990,7 +990,7 @@ Profile.Loading.Failure=mcMMO는 여전히 당신의 데이터를 읽을 수 없 Profile.Loading.AdminFailureNotice=&4[A]&c mcMMO는 &e{0}&c 플레이어 데이터 읽기가 불가능합니다. &d당신의 데이터베이스 설치를 검사해주세요. Commands.XPBar.Usage=Proper usage is /mmoxpbar Commands.Description.mmoxpbar=Player settings for mcMMO XP bars -Commands.Description.mmocompat=Information about mcMMO and whether or not its in compatibility mode or fully functional. +Commands.Description.mmocompat=Information about mcMMO and whether its in compatibility mode or fully functional. #OVERHAULs Overhaul.Levelup=&l{0} &r(이)가 레벨 &r&a&l{2}&r&f 로 성장 했습니다. diff --git a/src/main/resources/locale/locale_nl.properties b/src/main/resources/locale/locale_nl.properties index 165fdc7f62..5fbae168eb 100644 --- a/src/main/resources/locale/locale_nl.properties +++ b/src/main/resources/locale/locale_nl.properties @@ -430,4 +430,4 @@ Scoreboard.Misc.RemainingXP=Resterende XP Scoreboard.Misc.Overall=Globaal Commands.XPBar.Usage=Proper usage is /mmoxpbar Commands.Description.mmoxpbar=Player settings for mcMMO XP bars -Commands.Description.mmocompat=Information about mcMMO and whether or not its in compatibility mode or fully functional. +Commands.Description.mmocompat=Information about mcMMO and whether its in compatibility mode or fully functional. diff --git a/src/main/resources/locale/locale_sv.properties b/src/main/resources/locale/locale_sv.properties index 6c4ae37175..edebda8145 100644 --- a/src/main/resources/locale/locale_sv.properties +++ b/src/main/resources/locale/locale_sv.properties @@ -151,4 +151,4 @@ Stats.Header.Misc=&6-=Varierande Färdogheter=- Stats.Own.Stats=&a[mcMMO] Stats Commands.XPBar.Usage=Proper usage is /mmoxpbar Commands.Description.mmoxpbar=Player settings for mcMMO XP bars -Commands.Description.mmocompat=Information about mcMMO and whether or not its in compatibility mode or fully functional. +Commands.Description.mmocompat=Information about mcMMO and whether its in compatibility mode or fully functional. diff --git a/src/main/resources/locale/locale_th_TH.properties b/src/main/resources/locale/locale_th_TH.properties index 4faa11011b..74debe67d7 100644 --- a/src/main/resources/locale/locale_th_TH.properties +++ b/src/main/resources/locale/locale_th_TH.properties @@ -634,4 +634,4 @@ UpdateChecker.Outdated=You are using an outdated version of mcMMO! UpdateChecker.NewAvailable=There is a new version available on BukkitDev. Commands.XPBar.Usage=Proper usage is /mmoxpbar Commands.Description.mmoxpbar=Player settings for mcMMO XP bars -Commands.Description.mmocompat=Information about mcMMO and whether or not its in compatibility mode or fully functional. +Commands.Description.mmocompat=Information about mcMMO and whether its in compatibility mode or fully functional. diff --git a/src/main/resources/mods/armor.default.yml b/src/main/resources/mods/armor.default.yml index 14604141d9..e02ee9ba4d 100644 --- a/src/main/resources/mods/armor.default.yml +++ b/src/main/resources/mods/armor.default.yml @@ -8,7 +8,7 @@ # The bare minimum of an Armor piece is that it has a Repair_Material # # -# Repairable: Whether or not the item is repairable +# Repairable: Whether the item is repairable ## This defaults to true # # Repair_Material: This is the material name of the item used to repair this armor. diff --git a/src/main/resources/mods/tools.default.yml b/src/main/resources/mods/tools.default.yml index fe1d155079..361ff46306 100644 --- a/src/main/resources/mods/tools.default.yml +++ b/src/main/resources/mods/tools.default.yml @@ -18,10 +18,10 @@ ## Valid values range from 1 to 4 ## This defaults to 1 # -# Ability_Enabled: Whether or not abilities are enabled with this tool +# Ability_Enabled: Whether abilities are enabled with this tool ## This defaults to true # -# Repairable: Whether or not the item is repairable +# Repairable: Whether the item is repairable ## This defaults to true # # Repair_Material: This is the material name of the item used to repair this tool. diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 62ec6c0326..f8893ea1ac 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -23,7 +23,7 @@ commands: aliases: xpbarsettings description: Change XP bar settings mmocompat: - description: Information about the server and whether or not its considered fully compatible or running in compatibility mode + description: Information about the server and whether its considered fully compatible or running in compatibility mode mmodebug: aliases: [mcmmodebugmode] description: Toggles a debug mode which will print useful information to chat @@ -51,7 +51,7 @@ commands: description: Add mcMMO levels to a user permission: mcmmo.commands.addlevels mcability: - description: Toggle whether or not abilities get readied on right click + description: Toggle whether abilities get readied on right click permission: mcmmo.commands.mcability mcrefresh: description: Refresh all cooldowns for mcMMO From 72957c3d31a3ca0ef5a57dc6e331f953339cfabe Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 19 Apr 2023 14:13:17 -0700 Subject: [PATCH 36/75] Add XP test for Woodcutting --- .../config/experience/ExperienceConfig.java | 123 +++++------ .../nossr50/util/skills/CombatUtils.java | 1 - .../gmail/nossr50/util/skills/RankUtils.java | 1 - ...nagerTest.java => MMOTestEnvironment.java} | 193 ++++++++---------- .../nossr50/skills/tridents/TridentsTest.java | 38 ++++ .../skills/woodcutting/WoodcuttingTest.java | 107 ++++++++++ 6 files changed, 284 insertions(+), 179 deletions(-) rename src/test/java/com/gmail/nossr50/{skills/woodcutting/WoodcuttingManagerTest.java => MMOTestEnvironment.java} (53%) create mode 100644 src/test/java/com/gmail/nossr50/skills/tridents/TridentsTest.java create mode 100644 src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingTest.java diff --git a/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java b/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java index 929fdcefe3..6863c0e558 100644 --- a/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java +++ b/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java @@ -296,6 +296,10 @@ public boolean getExperienceGainsPlayerVersusPlayerEnabled() { } /* Combat XP Multipliers */ + public double getCombatXP(String entity) { + return config.getDouble("Experience_Values.Combat.Multiplier." + entity); + } + public double getCombatXP(EntityType entity) { return config.getDouble("Experience_Values.Combat.Multiplier." + StringUtils.getPrettyEntityTypeString(entity).replace(" ", "_")); } @@ -314,96 +318,73 @@ public boolean hasCombatXP(EntityType entity) { /* Materials */ public int getXp(PrimarySkillType skill, Material material) { - //TODO: Temporary measure to fix an exploit caused by a yet to be fixed Spigot bug (as of 7/3/2020) - if (material.toString().equalsIgnoreCase("LILY_PAD")) - return 0; - - String baseString = "Experience_Values." + StringUtils.getCapitalized(skill.toString()) + "."; - String explicitString = baseString + StringUtils.getExplicitConfigMaterialString(material); - if (config.contains(explicitString)) - return config.getInt(explicitString); - String friendlyString = baseString + StringUtils.getFriendlyConfigMaterialString(material); - if (config.contains(friendlyString)) - return config.getInt(friendlyString); - String wildcardString = baseString + StringUtils.getWildcardConfigMaterialString(material); - if (config.contains(wildcardString)) - return config.getInt(wildcardString); - return 0; + return getXpHelper(skill, StringUtils.getExplicitConfigMaterialString(material), + StringUtils.getFriendlyConfigMaterialString(material), + StringUtils.getWildcardConfigMaterialString(material)); } - /* Materials */ public int getXp(PrimarySkillType skill, BlockState blockState) { - Material data = blockState.getType(); - - String baseString = "Experience_Values." + StringUtils.getCapitalized(skill.toString()) + "."; - String explicitString = baseString + StringUtils.getExplicitConfigMaterialString(data); - if (config.contains(explicitString)) - return config.getInt(explicitString); - String friendlyString = baseString + StringUtils.getFriendlyConfigMaterialString(data); - if (config.contains(friendlyString)) - return config.getInt(friendlyString); - String wildcardString = baseString + StringUtils.getWildcardConfigMaterialString(data); - if (config.contains(wildcardString)) - return config.getInt(wildcardString); - return 0; + Material material = blockState.getType(); + return getXp(skill, material); } - /* Materials */ public int getXp(PrimarySkillType skill, Block block) { - Material data = block.getType(); - - String baseString = "Experience_Values." + StringUtils.getCapitalized(skill.toString()) + "."; - String explicitString = baseString + StringUtils.getExplicitConfigMaterialString(data); - if (config.contains(explicitString)) - return config.getInt(explicitString); - String friendlyString = baseString + StringUtils.getFriendlyConfigMaterialString(data); - if (config.contains(friendlyString)) - return config.getInt(friendlyString); - String wildcardString = baseString + StringUtils.getWildcardConfigMaterialString(data); - if (config.contains(wildcardString)) - return config.getInt(wildcardString); - return 0; + Material material = block.getType(); + return getXp(skill, material); } - /* Materials */ public int getXp(PrimarySkillType skill, BlockData data) { + return getXpHelper(skill, StringUtils.getExplicitConfigBlockDataString(data), + StringUtils.getFriendlyConfigBlockDataString(data), + StringUtils.getWildcardConfigBlockDataString(data)); + } + + private int getXpHelper(PrimarySkillType skill, String explicitString, String friendlyString, String wildcardString) { + if (explicitString.equalsIgnoreCase("LILY_PAD")) { + return 0; + } + String baseString = "Experience_Values." + StringUtils.getCapitalized(skill.toString()) + "."; - String explicitString = baseString + StringUtils.getExplicitConfigBlockDataString(data); - if (config.contains(explicitString)) - return config.getInt(explicitString); - String friendlyString = baseString + StringUtils.getFriendlyConfigBlockDataString(data); - if (config.contains(friendlyString)) - return config.getInt(friendlyString); - String wildcardString = baseString + StringUtils.getWildcardConfigBlockDataString(data); - if (config.contains(wildcardString)) - return config.getInt(wildcardString); + String[] configStrings = {explicitString, friendlyString, wildcardString}; + + for (String configString : configStrings) { + String fullPath = baseString + configString; + if (config.contains(fullPath)) { + return config.getInt(fullPath); + } + } + return 0; } - public boolean doesBlockGiveSkillXP(PrimarySkillType skill, Material data) { - String baseString = "Experience_Values." + StringUtils.getCapitalized(skill.toString()) + "."; - String explicitString = baseString + StringUtils.getExplicitConfigMaterialString(data); - if (config.contains(explicitString)) - return true; - String friendlyString = baseString + StringUtils.getFriendlyConfigMaterialString(data); - if (config.contains(friendlyString)) - return true; - String wildcardString = baseString + StringUtils.getWildcardConfigMaterialString(data); - return config.contains(wildcardString); + + public boolean doesBlockGiveSkillXP(PrimarySkillType skill, Material material) { + return doesBlockGiveSkillXPHelper(skill, StringUtils.getExplicitConfigMaterialString(material), + StringUtils.getFriendlyConfigMaterialString(material), + StringUtils.getWildcardConfigMaterialString(material)); } public boolean doesBlockGiveSkillXP(PrimarySkillType skill, BlockData data) { + return doesBlockGiveSkillXPHelper(skill, StringUtils.getExplicitConfigBlockDataString(data), + StringUtils.getFriendlyConfigBlockDataString(data), + StringUtils.getWildcardConfigBlockDataString(data)); + } + + private boolean doesBlockGiveSkillXPHelper(PrimarySkillType skill, String explicitString, String friendlyString, String wildcardString) { String baseString = "Experience_Values." + StringUtils.getCapitalized(skill.toString()) + "."; - String explicitString = baseString + StringUtils.getExplicitConfigBlockDataString(data); - if (config.contains(explicitString)) - return true; - String friendlyString = baseString + StringUtils.getFriendlyConfigBlockDataString(data); - if (config.contains(friendlyString)) - return true; - String wildcardString = baseString + StringUtils.getWildcardConfigBlockDataString(data); - return config.contains(wildcardString); + String[] configStrings = {explicitString, friendlyString, wildcardString}; + + for (String configString : configStrings) { + String fullPath = baseString + configString; + if (config.contains(fullPath)) { + return true; + } + } + + return false; } + /* * Experience Bar Stuff */ diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index 1427be479e..6923c32beb 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -17,7 +17,6 @@ import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager; import com.gmail.nossr50.skills.archery.ArcheryManager; import com.gmail.nossr50.skills.axes.AxesManager; -import com.gmail.nossr50.skills.crossbows.CrossbowsManager; import com.gmail.nossr50.skills.swords.SwordsManager; import com.gmail.nossr50.skills.taming.TamingManager; import com.gmail.nossr50.skills.tridents.TridentsManager; diff --git a/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java b/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java index 8222284353..4af318e9d5 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java @@ -317,7 +317,6 @@ private static void initMaps(String s) { * @param rank The target rank * @return The level at which this rank unlocks */ - @Deprecated public static int getRankUnlockLevel(SubSkillType subSkillType, int rank) { return RankConfig.getInstance().getSubSkillUnlockLevel(subSkillType, rank); diff --git a/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManagerTest.java b/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java similarity index 53% rename from src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManagerTest.java rename to src/test/java/com/gmail/nossr50/MMOTestEnvironment.java index d27f54e5d3..81e0f60942 100644 --- a/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManagerTest.java +++ b/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java @@ -1,18 +1,16 @@ -package com.gmail.nossr50.skills.woodcutting; +package com.gmail.nossr50; 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.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.mcMMO; -import com.gmail.nossr50.util.EventUtils; -import com.gmail.nossr50.util.Misc; -import com.gmail.nossr50.util.Permissions; -import com.gmail.nossr50.util.TransientEntityTracker; +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; @@ -20,83 +18,78 @@ import org.bukkit.Material; import org.bukkit.Server; import org.bukkit.World; -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.bukkit.plugin.PluginManager; -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.UUID; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; - -class WoodcuttingManagerTest { - private static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(WoodcuttingManagerTest.class.getName()); - private MockedStatic mockedMcMMO; - private MockedStatic mockedChatConfig; - private MockedStatic mockedPermissions; - private MockedStatic mockedRankUtils; - private MockedStatic mockedUserManager; - private MockedStatic mockedMisc; - private MockedStatic mockedSkillTools; - private MockedStatic mockedEventUtils; - private TransientEntityTracker transientEntityTracker; - private AdvancedConfig advancedConfig; - private GeneralConfig generalConfig; - private RankConfig rankConfig; - private SkillTools skillTools; - private Server server; - private PluginManager pluginManager; - private World world; - - private WoodcuttingManager woodcuttingManager; + +public abstract class MMOTestEnvironment { + private final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(MMOTestEnvironment.class.getName()); + protected MockedStatic mockedMcMMO; + protected MockedStatic mockedChatConfig; + protected MockedStatic experienceConfig; + protected MockedStatic mockedPermissions; + protected MockedStatic mockedRankUtils; + protected MockedStatic mockedUserManager; + protected MockedStatic mockedMisc; + protected MockedStatic mockedSkillTools; + protected MockedStatic mockedEventUtils; + protected TransientEntityTracker transientEntityTracker; + protected AdvancedConfig advancedConfig; + protected GeneralConfig generalConfig; + protected RankConfig rankConfig; + protected SkillTools skillTools; + protected Server server; + protected PluginManager pluginManager; + protected World world; /* Mocks */ - Player player; + protected Player player; + + protected UUID playerUUID = UUID.randomUUID(); + protected ItemStack itemInMainHand; - UUID playerUUID = UUID.randomUUID(); - ItemStack itemInMainHand; + protected PlayerInventory playerInventory; + protected PlayerProfile playerProfile; + protected McMMOPlayer mmoPlayer; + protected String playerName = "testPlayer"; - PlayerInventory playerInventory; - PlayerProfile playerProfile; - McMMOPlayer mmoPlayer; - String playerName = "testPlayer"; + protected ChunkManager chunkManager; - @BeforeEach - void setUp() { + protected void mockBaseEnvironment() { mockedMcMMO = Mockito.mockStatic(mcMMO.class); mcMMO.p = Mockito.mock(mcMMO.class); Mockito.when(mcMMO.p.getLogger()).thenReturn(logger); + // place store + chunkManager = Mockito.mock(ChunkManager.class); + Mockito.when(mcMMO.getPlaceStore()).thenReturn(chunkManager); + + // shut off mod manager for woodcutting + Mockito.when(mcMMO.getModManager()).thenReturn(Mockito.mock(ModManager.class)); + Mockito.when(mcMMO.getModManager().isCustomLog(any())).thenReturn(false); + // chat config mockedChatConfig = Mockito.mockStatic(ChatConfig.class); Mockito.when(ChatConfig.getInstance()).thenReturn(Mockito.mock(ChatConfig.class)); // general config - generalConfig = Mockito.mock(GeneralConfig.class); - Mockito.when(generalConfig.getTreeFellerThreshold()).thenReturn(100); - Mockito.when(generalConfig.getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, Material.OAK_LOG)).thenReturn(true); - Mockito.when(generalConfig.getLocale()).thenReturn("en_US"); - Mockito.when(mcMMO.p.getGeneralConfig()).thenReturn(generalConfig); + mockGeneralConfig(); // rank config - rankConfig = Mockito.mock(RankConfig.class); - Mockito.when(rankConfig.getSubSkillUnlockLevel(SubSkillType.WOODCUTTING_HARVEST_LUMBER, 1)).thenReturn(1); + mockRankConfig(); // wire advanced config - this.advancedConfig = Mockito.mock(AdvancedConfig.class); - 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(mcMMO.p.getAdvancedConfig()).thenReturn(advancedConfig); + mockAdvancedConfig(); + + // wire experience config + mockExperienceConfig(); // wire skill tools this.skillTools = new SkillTools(mcMMO.p); @@ -105,18 +98,9 @@ void setUp() { this.transientEntityTracker = new TransientEntityTracker(); Mockito.when(mcMMO.getTransientEntityTracker()).thenReturn(transientEntityTracker); - mockedPermissions = Mockito.mockStatic(Permissions.class); - Mockito.when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); - Mockito.when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn(true); - Mockito.when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); - Mockito.when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn(true); - Mockito.when(Permissions.lucky(player, PrimarySkillType.WOODCUTTING)).thenReturn(false); // player is not lucky + mockPermissions(); mockedRankUtils = Mockito.mockStatic(RankUtils.class); - 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); // wire server this.server = Mockito.mock(Server.class); @@ -139,9 +123,7 @@ void setUp() { // 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); // PlayerProfile and McMMOPlayer are partially mocked playerProfile = new PlayerProfile("testPlayer", player.getUniqueId(), 0); @@ -150,17 +132,51 @@ void setUp() { // wire user manager this.mockedUserManager = Mockito.mockStatic(UserManager.class); Mockito.when(UserManager.getPlayer(player)).thenReturn(mmoPlayer); + } + + private void mockPermissions() { + mockedPermissions = Mockito.mockStatic(Permissions.class); + Mockito.when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); + Mockito.when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn(true); + Mockito.when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); + Mockito.when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn(true); + Mockito.when(Permissions.lucky(player, PrimarySkillType.WOODCUTTING)).thenReturn(false); // player is not lucky + } - // Set up spy for WoodcuttingManager - woodcuttingManager = Mockito.spy(new WoodcuttingManager(mmoPlayer)); + private void mockRankConfig() { + rankConfig = Mockito.mock(RankConfig.class); + } + + private void mockAdvancedConfig() { + this.advancedConfig = Mockito.mock(AdvancedConfig.class); + Mockito.when(mcMMO.p.getAdvancedConfig()).thenReturn(advancedConfig); + } + + private void mockGeneralConfig() { + generalConfig = Mockito.mock(GeneralConfig.class); + Mockito.when(generalConfig.getTreeFellerThreshold()).thenReturn(100); + Mockito.when(generalConfig.getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, Material.OAK_LOG)).thenReturn(true); + Mockito.when(generalConfig.getLocale()).thenReturn("en_US"); + Mockito.when(mcMMO.p.getGeneralConfig()).thenReturn(generalConfig); + } + + private void mockExperienceConfig() { + experienceConfig = Mockito.mockStatic(ExperienceConfig.class); + + Mockito.when(ExperienceConfig.getInstance()).thenReturn(Mockito.mock(ExperienceConfig.class)); + + // Combat + Mockito.when(ExperienceConfig.getInstance().getCombatXP("Cow")).thenReturn(1D); } - @AfterEach - void tearDown() { + protected void cleanupBaseEnvironment() { // Clean up resources here if needed. if (mockedMcMMO != null) { mockedMcMMO.close(); } + if (experienceConfig != null) { + experienceConfig.close(); + } if (mockedChatConfig != null) { mockedChatConfig.close(); } @@ -180,39 +196,4 @@ void tearDown() { mockedEventUtils.close(); } } - - @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 - 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); - } } diff --git a/src/test/java/com/gmail/nossr50/skills/tridents/TridentsTest.java b/src/test/java/com/gmail/nossr50/skills/tridents/TridentsTest.java new file mode 100644 index 0000000000..194770f775 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/skills/tridents/TridentsTest.java @@ -0,0 +1,38 @@ +package com.gmail.nossr50.skills.tridents; + +import com.gmail.nossr50.MMOTestEnvironment; +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() { + mockBaseEnvironment(); + + // 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(); + } +} diff --git a/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingTest.java b/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingTest.java new file mode 100644 index 0000000000..1de25cc710 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingTest.java @@ -0,0 +1,107 @@ +package com.gmail.nossr50.skills.woodcutting; + +import com.gmail.nossr50.MMOTestEnvironment; +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() { + mockBaseEnvironment(); + 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 + 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()); + } +} From d30b2f7bf67ae91697cb9afcd8e2e74f05a0f0bc Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 23 Apr 2023 13:23:18 -0700 Subject: [PATCH 37/75] Fixed divide by zero bug impacting tridents XP when missing from config --- Changelog.txt | 1 + .../config/experience/ExperienceConfig.java | 2 +- .../nossr50/datatypes/player/McMMOPlayer.java | 2 +- .../com/gmail/nossr50/util/skills/CombatUtils.java | 14 +++++++------- src/main/resources/experience.yml | 6 ++++-- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 0eec68e122..e61407c9a0 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -5,6 +5,7 @@ Version 2.2.000 TODO: Add unit test to determine crossbow or bow skill TODO: Add unit test for trident xp processing TODO: Add missing entries to changelog + 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 (API) 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 Treasure drop rate from Shake, Fishing, Hylian, and Excavation now benefit from the Luck perk Added 'Send_To_Console' settings to chat.yml to toggle sending party or admin chat messages to console diff --git a/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java b/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java index 6863c0e558..bb75418280 100644 --- a/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java +++ b/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java @@ -256,7 +256,7 @@ public double getBredMobXpMultiplier() { /* Skill modifiers */ public double getFormulaSkillModifier(PrimarySkillType skill) { - return config.getDouble("Experience_Formula.Modifier." + StringUtils.getCapitalized(skill.toString())); + return config.getDouble("Experience_Formula.Modifier." + StringUtils.getCapitalized(skill.toString()), 1); } /* Custom XP perk */ diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index 1e62dee8d6..71bdbccb54 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -846,7 +846,7 @@ private float modifyXpGain(PrimarySkillType primarySkillType, float xp) { return 0; } - xp = (float) (xp / ExperienceConfig.getInstance().getFormulaSkillModifier(primarySkillType) * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()); + xp = (float) (xp * ExperienceConfig.getInstance().getFormulaSkillModifier(primarySkillType) * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()); if (mcMMO.p.getGeneralConfig().getToolModsEnabled()) { CustomTool tool = mcMMO.getModManager().getTool(player.getInventory().getItemInMainHand()); diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index 6923c32beb..45f30203be 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -137,8 +137,7 @@ private static void processTridentCombat(@NotNull LivingEntity target, @NotNull mcMMOPlayer.checkAbilityActivation(PrimarySkillType.TRIDENTS); } - if(canUseLimitBreak(player, target, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK)) - { + if(canUseLimitBreak(player, target, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK)) { boostedDamage+=(getLimitBreakDamage(player, target, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK) * mcMMOPlayer.getAttackStrength()); } @@ -821,13 +820,15 @@ public static void processCombatXP(@NotNull McMMOPlayer mcMMOPlayer, XPGainReason xpGainReason; if (target instanceof Player defender) { - if (!ExperienceConfig.getInstance().getExperienceGainsPlayerVersusPlayerEnabled() || PartyManager.inSameParty(mcMMOPlayer.getPlayer(), (Player) target)) { + if (!ExperienceConfig.getInstance().getExperienceGainsPlayerVersusPlayerEnabled() + || PartyManager.inSameParty(mcMMOPlayer.getPlayer(), (Player) target)) { return; } xpGainReason = XPGainReason.PVP; - if (defender.isOnline() && SkillUtils.cooldownExpired(mcMMOPlayer.getRespawnATS(), Misc.PLAYER_RESPAWN_COOLDOWN_SECONDS)) { + if (defender.isOnline() + && SkillUtils.cooldownExpired(mcMMOPlayer.getRespawnATS(), Misc.PLAYER_RESPAWN_COOLDOWN_SECONDS)) { baseXP = 20 * ExperienceConfig.getInstance().getPlayerVersusPlayerXP(); } } @@ -839,8 +840,7 @@ else if (target instanceof Animals) { EntityType type = target.getType(); baseXP = ExperienceConfig.getInstance().getAnimalsXP(type); } - else if (target instanceof Monster) - { + else if (target instanceof Monster) { EntityType type = target.getType(); baseXP = ExperienceConfig.getInstance().getCombatXP(type); } @@ -886,7 +886,7 @@ else if (target instanceof Monster) baseXP *= multiplier; - if (baseXP != 0) { + if (baseXP > 0) { new AwardCombatXpTask(mcMMOPlayer, primarySkillType, baseXP, target, xpGainReason).runTaskLater(mcMMO.p, 0); } } diff --git a/src/main/resources/experience.yml b/src/main/resources/experience.yml index 25e5383de9..fffceb4a39 100644 --- a/src/main/resources/experience.yml +++ b/src/main/resources/experience.yml @@ -167,8 +167,10 @@ Experience_Formula: Breeding: Multiplier: 1.0 - # Experience gained will get divided by these values. 1.0 by default, 2.0 means two times less XP gained. - Modifier: + # Experience gained will get multiplied by these values. 1.0 by default, 0.5 means half XP gained. This happens right before multiplying the XP by the global multiplier. + Skill_Multiplier: + Crossbows: 1.0 + Tridents: 1.0 Swords: 1.0 Taming: 1.0 Acrobatics: 1.0 From 25952154e3b3fd5c059961f8f097197fde6ec286 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 19 Dec 2023 11:17:22 -0800 Subject: [PATCH 38/75] Add in trident command --- Changelog.txt | 1 - .../commands/skills/TridentsCommand.java | 22 ++++++++++--------- .../com/gmail/nossr50/util/Permissions.java | 1 + .../commands/CommandRegistrationManager.java | 2 +- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 4726153ff3..e4a34a0957 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,4 @@ Version 2.2.000 - TODO: Configs are not adding new keys and this needs to be fixed, this affects config.yml, experience.yml, etc TODO: Add Xbows/Tridents to salvage/repair TODO: Add unit test for combat XP values TODO: Add unit test to determine crossbow or bow skill diff --git a/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java index 7431b2bca9..ef07c61f00 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java @@ -2,7 +2,10 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.random.ProbabilityUtil; +import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; @@ -13,30 +16,29 @@ public class TridentsCommand extends SkillCommand { - private boolean canTridentsSuper; public TridentsCommand() { super(PrimarySkillType.TRIDENTS); } @Override - protected void dataCalculations(Player player, float skillValue) { - // TODO: Implement data calculations - } + protected void dataCalculations(Player player, float skillValue) {} @Override - protected void permissionsCheck(Player player) { - canTridentsSuper = RankUtils.hasUnlockedSubskill(player, SubSkillType.TRIDENTS_TRIDENTS_SUPER_ABILITY) - && Permissions.superShotgun(player); - } + protected void permissionsCheck(Player player) {} @Override protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { List messages = new ArrayList<>(); - if (canTridentsSuper) { + if (canUseSubskill(player, SubSkillType.TRIDENTS_TRIDENTS_SUPER_ABILITY)) { messages.add("Tridents Super Ability"); - //TODO: Implement SSG + //TODO: Implement Tridents Super + } + + if(canUseSubskill(player, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK)) { + messages.add(getStatMessage(SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK, + String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK, 1000)))); } return messages; diff --git a/src/main/java/com/gmail/nossr50/util/Permissions.java b/src/main/java/com/gmail/nossr50/util/Permissions.java index 22ea4091a9..616a6f68e2 100644 --- a/src/main/java/com/gmail/nossr50/util/Permissions.java +++ b/src/main/java/com/gmail/nossr50/util/Permissions.java @@ -228,6 +228,7 @@ public static boolean customXpBoost(Permissible permissible, PrimarySkillType sk /* CROSSBOWS */ public static boolean superShotgun(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.crossbows.supershotgun"); } public static boolean tridentsSuper(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.tridents.superability"); } + public static boolean tridentsLimitBreak(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.tridents.superability"); } /* * PARTY diff --git a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java index 146858c319..23c7d74012 100644 --- a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java +++ b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java @@ -101,7 +101,7 @@ private static void registerSkillCommands() { command.setExecutor(new TamingCommand()); break; case TRIDENTS: - // TODO: Implement + command.setExecutor(new TridentsCommand()); break; case UNARMED: From 23b8e0a28cb9bcf8dd2e5ce06f5757b0ed4cce1a Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 20 Dec 2023 16:53:20 -0800 Subject: [PATCH 39/75] Add BowType metadata --- Changelog.txt | 1 + .../nossr50/listeners/EntityListener.java | 12 ++++++-- .../java/com/gmail/nossr50/util/BowType.java | 6 ++++ .../gmail/nossr50/util/MetadataConstants.java | 1 + .../nossr50/util/skills/CombatUtils.java | 29 +++++++++++++++---- .../skills/woodcutting/WoodcuttingTest.java | 2 +- 6 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/util/BowType.java diff --git a/Changelog.txt b/Changelog.txt index e4a34a0957..2d98e7f99b 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,4 +1,5 @@ Version 2.2.000 + TODO: com/gmail/nossr50/database/FlatFileDatabaseManager.java:109 reporting data entries that need correction on each launch TODO: Add Xbows/Tridents to salvage/repair TODO: Add unit test for combat XP values TODO: Add unit test to determine crossbow or bow skill diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index 7da5264146..7f71c13f70 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -128,13 +128,21 @@ public void onEntityShootBow(EntityShootBowEvent event) { ItemStack bow = event.getBow(); - if (bow != null - && bow.containsEnchantment(Enchantment.ARROW_INFINITE)) { + if (bow == null) + return; + + // determine if bow or crossbow + BowType bowType = ItemUtils.isCrossbow(bow) ? BowType.CROSSBOW : BowType.BOW; + + if (bow.containsEnchantment(Enchantment.ARROW_INFINITE)) { projectile.setMetadata(MetadataConstants.METADATA_KEY_INF_ARROW, MetadataConstants.MCMMO_METADATA_VALUE); } + // Set BowType, Force, and Distance metadata + projectile.setMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE, new FixedMetadataValue(pluginRef, bowType)); projectile.setMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, new FixedMetadataValue(pluginRef, Math.min(event.getForce() * mcMMO.p.getAdvancedConfig().getForceMultiplier(), 1.0))); projectile.setMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, new FixedMetadataValue(pluginRef, projectile.getLocation())); + //Cleanup metadata in 1 minute in case normal collection falls through CombatUtils.delayArrowMetaCleanup((Projectile) projectile); } diff --git a/src/main/java/com/gmail/nossr50/util/BowType.java b/src/main/java/com/gmail/nossr50/util/BowType.java new file mode 100644 index 0000000000..5e4d782741 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/BowType.java @@ -0,0 +1,6 @@ +package com.gmail.nossr50.util; + +public enum BowType { + BOW, + CROSSBOW +} diff --git a/src/main/java/com/gmail/nossr50/util/MetadataConstants.java b/src/main/java/com/gmail/nossr50/util/MetadataConstants.java index 090e04d17c..8bec613653 100644 --- a/src/main/java/com/gmail/nossr50/util/MetadataConstants.java +++ b/src/main/java/com/gmail/nossr50/util/MetadataConstants.java @@ -14,6 +14,7 @@ public class MetadataConstants { * Take great care if you ever modify the value of these keys */ public static final @NotNull String METADATA_KEY_REPLANT = "mcMMO: Recently Replanted"; + public static final @NotNull String METADATA_KEY_BOW_TYPE = "mcMMO: Bow Type"; public static final @NotNull String METADATA_KEY_EXPLOSION_FROM_RUPTURE = "mcMMO: Rupture Explosion"; public static final @NotNull String METADATA_KEY_FISH_HOOK_REF = "mcMMO: Fish Hook Tracker"; public static final @NotNull String METADATA_KEY_DODGE_TRACKER = "mcMMO: Dodge Tracker"; diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index 7654d4ac9d..e6397d9541 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -481,17 +481,23 @@ else if (entityType == EntityType.ARROW || entityType == EntityType.SPECTRAL_ARR Projectile arrow = (Projectile) painSource; ProjectileSource projectileSource = arrow.getShooter(); - if (projectileSource instanceof Player player && mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.ARCHERY, target)) { - // TODO: Add metadata to projectiles to determine source weapon to process combat skills - - if (!Misc.isNPCEntityExcludingVillagers(player) && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.ARCHERY)) { - processArcheryCombat(target, player, event, arrow); + if (projectileSource instanceof Player player) { + BowType bowType = getBowTypeFromMetadata(arrow); + + if (!Misc.isNPCEntityExcludingVillagers(player)) { + if(bowType == BowType.BOW && mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.ARCHERY, target)) { + processArcheryCombat(target, player, event, arrow); + } else if(bowType == BowType.CROSSBOW && mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.CROSSBOWS, target)) { + processCrossbowsCombat(target, player, event, arrow); + } } else { //Cleanup Arrow cleanupArrowMetadata(arrow); } - if (target.getType() != EntityType.CREEPER && !Misc.isNPCEntityExcludingVillagers(player) && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.TAMING)) { + if (target.getType() != EntityType.CREEPER + && !Misc.isNPCEntityExcludingVillagers(player) + && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.TAMING)) { McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); if(mcMMOPlayer == null) @@ -502,7 +508,18 @@ else if (entityType == EntityType.ARROW || entityType == EntityType.SPECTRAL_ARR } } } + } + private static BowType getBowTypeFromMetadata(Projectile projectile) { + // Return the BowType from the metadata, or default to BOW + if (projectile.hasMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE)) { + List metadataValue = projectile.getMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE); + + if (!metadataValue.isEmpty()) { + return (BowType) metadataValue.get(0).value(); + } + } + throw new IllegalStateException("BowType metadata is empty"); } /** diff --git a/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingTest.java b/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingTest.java index 1de25cc710..8960ed8218 100644 --- a/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingTest.java +++ b/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingTest.java @@ -72,10 +72,10 @@ void harvestLumberShouldDoubleDrop() { 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); From 3e11b7da2c7dd06ae7dbc8b1937207daaa288d27 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 20 Dec 2023 19:11:08 -0800 Subject: [PATCH 40/75] Add Explosive Shot definition --- .../datatypes/skills/SubSkillType.java | 1 + .../datatypes/skills/SuperAbilityType.java | 35 +++++++++---------- .../nossr50/datatypes/skills/ToolType.java | 5 +-- .../com/gmail/nossr50/util/Permissions.java | 1 + .../resources/locale/locale_en_US.properties | 5 +++ src/main/resources/plugin.yml | 3 ++ src/main/resources/skillranks.yml | 5 +++ 7 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java index 945277c678..e4caa84e1a 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java @@ -22,6 +22,7 @@ public enum SubSkillType { ARCHERY_DAZE, ARCHERY_SKILL_SHOT(20), ARCHERY_ARCHERY_LIMIT_BREAK(10), + ARCHERY_EXPLOSIVE_SHOT(1), /* Axes */ AXES_ARMOR_IMPACT(20), diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java index a4756c5f03..5c5728b0fb 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java @@ -10,6 +10,12 @@ import org.bukkit.entity.Player; public enum SuperAbilityType { + EXPLOSIVE_SHOT("Archery.Skills.ExplosiveShot.On", + "Archery.Skills.ExplosiveShot.Off", + "Archery.Skills.ExplosiveShot.Other.On", + "Archery.Skills.ExplosiveShot.Refresh", + "Archery.Skills.ExplosiveShot.Other.Off", + "Archery.SubSkill.ExplosiveShot.Name"), BERSERK( "Unarmed.Skills.Berserk.On", "Unarmed.Skills.Berserk.Off", @@ -190,6 +196,7 @@ public String toString() { public boolean getPermissions(Player player) { return switch (this) { case BERSERK -> Permissions.berserk(player); + case EXPLOSIVE_SHOT -> Permissions.explosiveShot(player); case BLAST_MINING -> Permissions.remoteDetonation(player); case GIGA_DRILL_BREAKER -> Permissions.gigaDrillBreaker(player); case GREEN_TERRA -> Permissions.greenTerra(player); @@ -211,25 +218,15 @@ public boolean getPermissions(Player player) { * @return true if the block is affected by this ability, false otherwise */ public boolean blockCheck(BlockState blockState) { - switch (this) { - case BERSERK: - return (BlockUtils.affectedByGigaDrillBreaker(blockState) || blockState.getType() == Material.SNOW || mcMMO.getMaterialMapStore().isGlass(blockState.getType())); - - case GIGA_DRILL_BREAKER: - return BlockUtils.affectedByGigaDrillBreaker(blockState); - - case GREEN_TERRA: - return BlockUtils.canMakeMossy(blockState); - - case SUPER_BREAKER: - return BlockUtils.affectedBySuperBreaker(blockState); - - case TREE_FELLER: - return BlockUtils.hasWoodcuttingXP(blockState); - - default: - return false; - } + return switch (this) { + case BERSERK -> + (BlockUtils.affectedByGigaDrillBreaker(blockState) || blockState.getType() == Material.SNOW || mcMMO.getMaterialMapStore().isGlass(blockState.getType())); + case GIGA_DRILL_BREAKER -> BlockUtils.affectedByGigaDrillBreaker(blockState); + case GREEN_TERRA -> BlockUtils.canMakeMossy(blockState); + case SUPER_BREAKER -> BlockUtils.affectedBySuperBreaker(blockState); + case TREE_FELLER -> BlockUtils.hasWoodcuttingXP(blockState); + default -> false; + }; } /** diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/ToolType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/ToolType.java index 3f96f851db..dd61867d58 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/ToolType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/ToolType.java @@ -11,7 +11,8 @@ public enum ToolType { PICKAXE("Mining.Ability.Lower", "Mining.Ability.Ready"), SHOVEL("Excavation.Ability.Lower", "Excavation.Ability.Ready"), SWORD("Swords.Ability.Lower", "Swords.Ability.Ready"), - CROSSBOWS("Crossbows.Ability.Lower", "Crossbows.Ability.Ready"), + CROSSBOW("Crossbows.Ability.Lower", "Crossbows.Ability.Ready"), + BOW("Archery.Ability.Lower", "Archery.Ability.Ready"), TRIDENTS("Tridents.Ability.Lower", "Tridents.Ability.Ready"); private final String lowerTool; @@ -40,7 +41,7 @@ public boolean inHand(ItemStack itemStack) { switch (this) { case AXE: return ItemUtils.isAxe(itemStack); - case CROSSBOWS: + case CROSSBOW: return ItemUtils.isCrossbow(itemStack); case TRIDENTS: return ItemUtils.isTrident(itemStack); diff --git a/src/main/java/com/gmail/nossr50/util/Permissions.java b/src/main/java/com/gmail/nossr50/util/Permissions.java index 616a6f68e2..e184ef8b93 100644 --- a/src/main/java/com/gmail/nossr50/util/Permissions.java +++ b/src/main/java/com/gmail/nossr50/util/Permissions.java @@ -180,6 +180,7 @@ public static boolean customXpBoost(Permissible permissible, PrimarySkillType sk public static boolean concoctions(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.alchemy.concoctions"); } /* ARCHERY */ + public static boolean explosiveShot(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.archery.explosiveshot"); } public static boolean arrowRetrieval(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.archery.trackarrows"); } public static boolean daze(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.archery.daze"); } diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 596aa8629e..553240d5b2 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -182,6 +182,11 @@ Archery.SubSkill.ArcheryLimitBreak.Description=Breaking your limits. Increased d Archery.SubSkill.ArcheryLimitBreak.Stat=Limit Break Max DMG Archery.Listener=Archery: Archery.SkillName=ARCHERY +Archery.Skills.ExplosiveShot.Off= +Archery.Skills.ExplosiveShot.On=&a**EXPLOSIVE SHOT ACTIVATED** +Archery.Skills.ExplosiveShot.Other.Off=Explosive Shot&a has worn off for &e{0} +Archery.Skills.ExplosiveShot.Other.On=&a{0}&2 has used &cExplosive Shot! +Archery.Skills.ExplosiveShot.Refresh=&aYour &Explosive Shot &ability is refreshed! #AXES Axes.Ability.Bonus.0=Axe Mastery Axes.Ability.Bonus.1=Bonus {0} damage diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 697d218fd9..e2fea0ae21 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -290,10 +290,13 @@ permissions: mcmmo.ability.archery.all: description: Allows access to all Archery abilities children: + mcmmo.ability.archery.explosiveshot: true mcmmo.ability.archery.skillshot: true mcmmo.ability.archery.daze: true mcmmo.ability.archery.arrowretrieval: true mcmmo.ability.archery.archerylimitbreak: true + mcmmo.ability.archery.explosiveshot: + description: Allows access to the Explosive Shot super ability for Archery mcmmo.ability.archery.archerylimitbreak: description: Adds damage to bows mcmmo.ability.archery.skillshot: diff --git a/src/main/resources/skillranks.yml b/src/main/resources/skillranks.yml index b2f26be30b..d214204cb1 100644 --- a/src/main/resources/skillranks.yml +++ b/src/main/resources/skillranks.yml @@ -31,6 +31,11 @@ Alchemy: Rank_7: 900 Rank_8: 1000 Archery: + ExplosiveShot: + Standard: + Rank_1: 5 + RetroMode: + Rank_1: 50 ArcheryLimitBreak: Standard: Rank_1: 10 From 7e3826a4d6f4d1c1601e9afd1b28f90cc540a71f Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 20 Dec 2023 19:26:22 -0800 Subject: [PATCH 41/75] WIP starting work on supers for archery/crossbow --- .../nossr50/datatypes/player/McMMOPlayer.java | 63 +++++++++++++++++++ .../datatypes/skills/SuperAbilityType.java | 5 ++ .../nossr50/listeners/PlayerListener.java | 7 +++ .../runnables/skills/AbilityCooldownTask.java | 4 +- .../com/gmail/nossr50/util/ItemUtils.java | 19 ++++++ .../nossr50/util/skills/CombatUtils.java | 8 +++ 6 files changed, 103 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index 5d6aa9e5b7..59c918a1e9 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -22,6 +22,7 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.party.ShareHandler; +import com.gmail.nossr50.runnables.skills.AbilityCooldownTask; import com.gmail.nossr50.runnables.skills.AbilityDisableTask; import com.gmail.nossr50.runnables.skills.ToolLowerTask; import com.gmail.nossr50.skills.SkillManager; @@ -389,6 +390,7 @@ public boolean getAbilityMode(SuperAbilityType ability) { * @param isActive True if the ability is active, false otherwise */ public void setAbilityMode(SuperAbilityType ability, boolean isActive) { + // TODO: This should reject "one and done" type abilities abilityMode.put(ability, isActive); } @@ -960,6 +962,67 @@ public void checkAbilityActivation(PrimarySkillType primarySkillType) { mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(player, new AbilityDisableTask(this, superAbilityType), (long) ticks * Misc.TICK_CONVERSION_FACTOR); } + /** + * Check to see if an ability can be activated. + * + * @param bowType The type of bow (crossbow, bow) + */ + public void checkAbilityActivationProjectiles(BowType bowType) { + PrimarySkillType primarySkillType = bowType == BowType.CROSSBOW ? PrimarySkillType.CROSSBOWS : PrimarySkillType.ARCHERY; + + // TODO: Refactor this crappy logic + ToolType tool = bowType == BowType.CROSSBOW ? ToolType.CROSSBOW : ToolType.BOW; + SuperAbilityType superAbilityType = bowType == BowType.CROSSBOW ? SuperAbilityType.SUPER_SHOTGUN : SuperAbilityType.EXPLOSIVE_SHOT; + SubSkillType subSkillType = superAbilityType.getSubSkillTypeDefinition(); + + if (getAbilityMode(superAbilityType) || !superAbilityType.getPermissions(player)) { + return; + } + + //TODO: This is hacky and temporary solution until skills are move to the new system + //Potential problems with this include skills with two super abilities (ie mining) + if(!RankUtils.hasUnlockedSubskill(player, subSkillType)) + { + int diff = RankUtils.getSuperAbilityUnlockRequirement(superAbilityType) - getSkillLevel(primarySkillType); + + //Inform the player they are not yet skilled enough + NotificationManager.sendPlayerInformation(player, + NotificationType.ABILITY_COOLDOWN, + "Skills.AbilityGateRequirementFail", + String.valueOf(diff), + mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType)); + return; + } + + // Call the event + if (EventUtils.callPlayerAbilityActivateEvent(player, primarySkillType).isCancelled()) { + return; + } + + if (useChatNotifications()) { + NotificationManager.sendPlayerInformation(player, NotificationType.SUPER_ABILITY, superAbilityType.getAbilityOn()); + } + + if (mcMMO.p.getAdvancedConfig().sendAbilityNotificationToOtherPlayers()) { + SkillUtils.sendSkillMessage(player, NotificationType.SUPER_ABILITY_ALERT_OTHERS, superAbilityType.getAbilityPlayer()); + } + + //Sounds + SoundManager.worldSendSound(player.getWorld(), player.getLocation(), SoundType.ABILITY_ACTIVATED_GENERIC); + + // TODO: Fire the ability + profile.setAbilityDATS(superAbilityType, System.currentTimeMillis()); + setAbilityMode(superAbilityType, true); + setToolPreparationMode(tool, false); + + if(!mcMMO.isServerShutdownExecuted()) { + mcMMO.p.getFoliaLib().getImpl().runAtEntityLater( + player, + new AbilityCooldownTask(this, superAbilityType), + (long) PerksUtils.handleCooldownPerks(player, superAbilityType.getCooldown()) * Misc.TICK_CONVERSION_FACTOR); + } + } + public void processAbilityActivation(@NotNull PrimarySkillType primarySkillType) { if (!mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(getPlayer(), primarySkillType)) { return; diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java index 5c5728b0fb..43e44a22f7 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java @@ -102,6 +102,7 @@ public enum SuperAbilityType { * Defining their associated SubSkillType definitions * This is a bit of a band-aid fix until the new skill system is in place */ + // TODO: This is stupid static { BERSERK.subSkillTypeDefinition = SubSkillType.UNARMED_BERSERK; SUPER_BREAKER.subSkillTypeDefinition = SubSkillType.MINING_SUPER_BREAKER; @@ -111,6 +112,8 @@ public enum SuperAbilityType { TREE_FELLER.subSkillTypeDefinition = SubSkillType.WOODCUTTING_TREE_FELLER; SERRATED_STRIKES.subSkillTypeDefinition = SubSkillType.SWORDS_SERRATED_STRIKES; BLAST_MINING.subSkillTypeDefinition = SubSkillType.MINING_BLAST_MINING; + TRIDENTS_SUPER_ABILITY.subSkillTypeDefinition = SubSkillType.TRIDENTS_TRIDENTS_SUPER_ABILITY; + SUPER_SHOTGUN.subSkillTypeDefinition = SubSkillType.CROSSBOWS_SUPER_SHOTGUN; } private final String abilityOn; @@ -193,6 +196,8 @@ public String toString() { * @param player Player to check permissions for * @return true if the player has permissions, false otherwise */ + // TODO: Add unit tests + // TODO: This is stupid public boolean getPermissions(Player player) { return switch (this) { case BERSERK -> Permissions.berserk(player); diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java index a63b7650ea..f27a69fcc2 100644 --- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java @@ -24,6 +24,7 @@ import com.gmail.nossr50.util.*; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; +import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.sounds.SoundManager; @@ -915,6 +916,12 @@ else if (herbalismManager.canUseShroomThumb(blockState)) { break; } + // Projectile Skills + // Check if the player is holding a bow or crossbow + if (ItemUtils.isCrossbow(heldItem) || ItemUtils.isBow(heldItem)) { + CombatUtils.processProjectileSkillSuperAbilityActivation(mcMMOPlayer, heldItem); + } + /* CALL OF THE WILD CHECKS */ Material type = heldItem.getType(); TamingManager tamingManager = mcMMOPlayer.getTamingManager(); diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/AbilityCooldownTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/AbilityCooldownTask.java index 69e080972e..9c7d8bfd8a 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/AbilityCooldownTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/AbilityCooldownTask.java @@ -21,9 +21,7 @@ public void run() { return; } - mcMMOPlayer.setAbilityInformed(ability, true); - + mcMMOPlayer.setAbilityInformed(ability, true); // TODO: ?? What does this do again? NotificationManager.sendPlayerInformation(mcMMOPlayer.getPlayer(), NotificationType.ABILITY_REFRESHED, ability.getAbilityRefresh()); - //mcMMOPlayer.getPlayer().sendMessage(ability.getAbilityRefresh()); } } diff --git a/src/main/java/com/gmail/nossr50/util/ItemUtils.java b/src/main/java/com/gmail/nossr50/util/ItemUtils.java index c41a3d4868..a6ad59a18f 100644 --- a/src/main/java/com/gmail/nossr50/util/ItemUtils.java +++ b/src/main/java/com/gmail/nossr50/util/ItemUtils.java @@ -36,14 +36,33 @@ private ItemUtils() {} * @param item Item to check * @return true if the item is a bow, false otherwise */ + // TODO: Unit tests public static boolean isBow(@NotNull ItemStack item) { return mcMMO.getMaterialMapStore().isBow(item.getType().getKey().getKey()); } + // TODO: Unit tests public static boolean isCrossbow(@NotNull ItemStack item) { return mcMMO.getMaterialMapStore().isCrossbow(item.getType().getKey().getKey()); } + // TODO: Unit tests + public static boolean isBowOrCrossbow(@NotNull ItemStack item) { + return isBow(item) || isCrossbow(item); + } + + // TODO: Unit tests + public static BowType getBowType(@NotNull ItemStack item) { + if (isBow(item)) { + return BowType.BOW; + } else if (isCrossbow(item)) { + return BowType.CROSSBOW; + } + + throw new IllegalArgumentException(item + " is not a bow or crossbow"); + } + + // TODO: Unit tests public static boolean isTrident(@NotNull ItemStack item) { return mcMMO.getMaterialMapStore().isTrident(item.getType().getKey().getKey()); } diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index e6397d9541..399a875ec5 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -49,6 +49,14 @@ private CombatUtils() {} return mcMMO.getMetadataService().getMobMetadataService(); } + // TODO: Unit tests + public static void processProjectileSkillSuperAbilityActivation(McMMOPlayer mmoPlayer, ItemStack heldItem) { + if (heldItem != null && mmoPlayer != null) { + if (ItemUtils.isBowOrCrossbow(heldItem)) + mmoPlayer.checkAbilityActivationProjectiles(ItemUtils.getBowType(heldItem)); + } + } + //Likely.. because who knows what plugins are throwing around public static boolean isDamageLikelyFromNormalCombat(@NotNull DamageCause damageCause) { return switch (damageCause) { From 7973ccc848c2adbd3676a97054843fb41dd09bfe Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 22 Dec 2023 11:05:26 -0800 Subject: [PATCH 42/75] Update FlatFile for new skill cds --- .../database/FlatFileDataProcessor.java | 1 + .../database/FlatFileDatabaseManager.java | 40 ++++++++--------- .../database/flatfile/FlatFileDataUtil.java | 1 + .../database/FlatFileDatabaseManagerTest.java | 44 +++++++------------ src/test/resources/healthydb.users | 6 +-- 5 files changed, 40 insertions(+), 52 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java index 6874434775..6f8c397e33 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java @@ -290,6 +290,7 @@ private void registerData(@NotNull FlatFileDataBuilder builder) { case COOLDOWN_CHIMAERA_WING: case COOLDOWN_SUPER_SHOTGUN: case COOLDOWN_TRIDENTS: + case COOLDOWN_ARCHERY: return ExpectedType.INTEGER; case EXP_MINING: case EXP_WOODCUTTING: diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index e547ab9640..d4d2e51b6f 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -86,10 +86,11 @@ public final class FlatFileDatabaseManager implements DatabaseManager { public static final int SKILLS_TRIDENTS = 48; public static final int COOLDOWN_SUPER_SHOTGUN = 49; public static final int COOLDOWN_TRIDENTS = 50; + public static final int COOLDOWN_ARCHERY = 51; + //Update this everytime new data is added + public static final int DATA_ENTRY_COUNT = COOLDOWN_ARCHERY + 1; - public static final int DATA_ENTRY_COUNT = COOLDOWN_TRIDENTS + 1; //Update this everytime new data is added - - protected FlatFileDatabaseManager(@NotNull File usersFile, @NotNull Logger logger, long purgeTime, int startingLevel, boolean testing) { + FlatFileDatabaseManager(@NotNull File usersFile, @NotNull Logger logger, long purgeTime, int startingLevel, boolean testing) { this.usersFile = usersFile; this.usersFilePath = usersFile.getPath(); this.logger = logger; @@ -105,7 +106,7 @@ protected FlatFileDatabaseManager(@NotNull File usersFile, @NotNull Logger logge List flatFileDataFlags = checkFileHealthAndStructure(); if(flatFileDataFlags != null) { - if(flatFileDataFlags.size() > 0) { + if(!flatFileDataFlags.isEmpty()) { logger.info("Detected "+flatFileDataFlags.size() + " data entries which need correction."); } } @@ -114,7 +115,7 @@ protected FlatFileDatabaseManager(@NotNull File usersFile, @NotNull Logger logge } } - protected FlatFileDatabaseManager(@NotNull String usersFilePath, @NotNull Logger logger, long purgeTime, int startingLevel) { + FlatFileDatabaseManager(@NotNull String usersFilePath, @NotNull Logger logger, long purgeTime, int startingLevel) { this(new File(usersFilePath), logger, purgeTime, startingLevel, false); } @@ -243,7 +244,7 @@ public void purgeOldUsers() { out.write(writer.toString()); if(testing) { - System.out.println(writer.toString()); + System.out.println(writer); } } catch (IOException e) { @@ -575,16 +576,11 @@ public void writeUserToLine(@NotNull PlayerProfile profile, @NotNull Appendable * @return a profile with the targets data or an unloaded profile if no data was found */ private @NotNull PlayerProfile processUserQuery(@NotNull UserQuery userQuery) throws RuntimeException { - switch(userQuery.getType()) { - case UUID_AND_NAME: - return queryByUUIDAndName((UserQueryFull) userQuery); - case UUID: - return queryByUUID((UserQueryUUID) userQuery); - case NAME: - return queryByName((UserQueryNameImpl) userQuery); - default: - throw new RuntimeException("No case for this UserQueryType!"); - } + return switch (userQuery.getType()) { + case UUID_AND_NAME -> queryByUUIDAndName((UserQueryFull) userQuery); + case UUID -> queryByUUID((UserQueryUUID) userQuery); + case NAME -> queryByName((UserQueryNameImpl) userQuery); + }; } private @NotNull PlayerProfile queryByName(@NotNull UserQueryName userQuery) { @@ -690,7 +686,7 @@ public void writeUserToLine(@NotNull PlayerProfile profile, @NotNull Appendable * No match was found in the file */ - return grabUnloadedProfile(uuid, "Player-Not-Found="+uuid.toString()); + return grabUnloadedProfile(uuid, "Player-Not-Found="+ uuid); } private @NotNull PlayerProfile queryByUUIDAndName(@NotNull UserQueryFull userQuery) { @@ -725,7 +721,7 @@ public void writeUserToLine(@NotNull PlayerProfile profile, @NotNull Appendable boolean matchingName = dbPlayerName.equalsIgnoreCase(playerName); if (!matchingName) { - logger.warning("When loading user: "+playerName +" with UUID of (" + uuid.toString() + logger.warning("When loading user: "+playerName +" with UUID of (" + uuid +") we found a mismatched name, the name in the DB will be replaced (DB name: "+dbPlayerName+")"); //logger.info("Name updated for player: " + rawSplitData[USERNAME_INDEX] + " => " + playerName); rawSplitData[USERNAME_INDEX] = playerName; @@ -1111,7 +1107,7 @@ private void initEmptyDB() { public @Nullable List checkFileHealthAndStructure() { ArrayList flagsFound = null; LogUtils.debug(logger, "(" + usersFile.getPath() + ") Validating database file.."); - FlatFileDataProcessor dataProcessor = null; + FlatFileDataProcessor dataProcessor; if (usersFile.exists()) { BufferedReader bufferedReader = null; @@ -1143,7 +1139,7 @@ private void initEmptyDB() { } //Only update the file if needed - if(dataProcessor.getFlatFileDataFlags().size() > 0) { + if(!dataProcessor.getFlatFileDataFlags().isEmpty()) { flagsFound = new ArrayList<>(dataProcessor.getFlatFileDataFlags()); logger.info("Updating FlatFile Database..."); fileWriter = new FileWriter(usersFilePath); @@ -1161,7 +1157,7 @@ private void initEmptyDB() { } } - if(flagsFound == null || flagsFound.size() == 0) { + if(flagsFound == null || flagsFound.isEmpty()) { return null; } else { return flagsFound; @@ -1251,7 +1247,7 @@ private PlayerProfile loadFromLine(@NotNull String[] character) { tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.BERSERK, COOLDOWN_BERSERK, username); tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.GREEN_TERRA, COOLDOWN_GREEN_TERRA, username); tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.GIGA_DRILL_BREAKER, COOLDOWN_GIGA_DRILL_BREAKER, username); - // Archery - Unused + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.EXPLOSIVE_SHOT, COOLDOWN_ARCHERY, username); tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SERRATED_STRIKES, COOLDOWN_SERRATED_STRIKES, username); tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SKULL_SPLITTER, COOLDOWN_SKULL_SPLITTER, username); // Acrobatics - Unused diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtil.java b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtil.java index 9ee75e581c..285c501fd3 100644 --- a/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtil.java +++ b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtil.java @@ -94,6 +94,7 @@ public class FlatFileDataUtil { case COOLDOWN_BLAST_MINING: case COOLDOWN_SUPER_SHOTGUN: case COOLDOWN_TRIDENTS: + case COOLDOWN_ARCHERY: case SCOREBOARD_TIPS: case COOLDOWN_CHIMAERA_WING: case EXP_MINING: diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index 8fd37ebc99..23463cbdb0 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -31,7 +31,6 @@ 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:140:14:150:15:1111:2222:"; + 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:"; @@ -64,7 +63,7 @@ class FlatFileDatabaseManagerTest { long expectedBerserkCd = 111, expectedGigaDrillBreakerCd = 222, expectedTreeFellerCd = 333, expectedGreenTerraCd = 444, expectedSerratedStrikesCd = 555, expectedSkullSplitterCd = 666, expectedSuperBreakerCd = 777, expectedBlastMiningCd = 888, expectedChimaeraWingCd = 999, - expectedSuperShotgunCd = 1111, expectedTridentSuperCd = 2222; + expectedSuperShotgunCd = 1111, expectedTridentSuperCd = 2222, expectedExplosiveShotCd = 3333; int expectedScoreboardTips = 1111; Long expectedLastLogin = 2020L; @@ -473,31 +472,22 @@ private void testHealthyDataProfileValues(@NotNull String playerName, @NotNull U } 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 SUPER_SHOTGUN: - return expectedSuperShotgunCd; - case TREE_FELLER: - return expectedTreeFellerCd; - case SERRATED_STRIKES: - return expectedSerratedStrikesCd; - case BLAST_MINING: - return expectedBlastMiningCd; - case TRIDENTS_SUPER_ABILITY: - return expectedTridentSuperCd; - } + 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"); + }; - throw new RuntimeException("Values not defined for super ability not defined please add " + - "values for " + superAbilityType.toString() + " to the test"); } private float getExpectedExperienceHealthyDBEntryOne(@NotNull PrimarySkillType primarySkillType) { diff --git a/src/test/resources/healthydb.users b/src/test/resources/healthydb.users index bba0c6f9bf..79a2c7e703 100644 --- a/src/test/resources/healthydb.users +++ b/src/test/resources/healthydb.users @@ -1,3 +1,3 @@ -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: -mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:3030:0:0:0:0:0:0: -powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1337:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:4040:0:0:0:0:0:0: \ No newline at end of file +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: +mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:3030:0:0:0:0:0:0:0: +powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1337:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:4040:0:0:0:0:0:0:0: \ No newline at end of file From 5f63faf65d8919473fb4852adbe12371a8ebc406 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 22 Dec 2023 11:37:17 -0800 Subject: [PATCH 43/75] Unit test refactor --- .../datatypes/skills/SuperAbilityType.java | 2 - .../gmail/nossr50/util/skills/SkillTools.java | 46 +---- .../gmail/nossr50/MMOMinimalPluginMock.java | 163 ++++++++++++++++++ .../com/gmail/nossr50/MMOTestEnvironment.java | 5 +- .../nossr50/skills/tridents/TridentsTest.java | 5 +- .../skills/woodcutting/WoodcuttingTest.java | 5 +- 6 files changed, 179 insertions(+), 47 deletions(-) create mode 100644 src/test/java/com/gmail/nossr50/MMOMinimalPluginMock.java diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java index 43e44a22f7..21bdc041c7 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java @@ -211,8 +211,6 @@ public boolean getPermissions(Player player) { case SUPER_SHOTGUN -> Permissions.superShotgun(player); case TREE_FELLER -> Permissions.treeFeller(player); case TRIDENTS_SUPER_ABILITY -> Permissions.tridentsSuper(player); - default -> - throw new RuntimeException("Unhandled SuperAbilityType in getPermissions(), devs need to add definition for " + this + "!"); }; } diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java index 7e743bb41c..6329b3934e 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java @@ -52,7 +52,7 @@ public class SkillTools { NON_CHILD_SKILLS = ImmutableList.copyOf(tempNonChildSkills); } - public SkillTools(@NotNull mcMMO pluginRef) { + public SkillTools(@NotNull mcMMO pluginRef) throws InvalidSkillException { this.pluginRef = pluginRef; /* @@ -198,8 +198,7 @@ public SkillTools(@NotNull mcMMO pluginRef) { case GIGA_DRILL_BREAKER -> PrimarySkillType.EXCAVATION; case SUPER_SHOTGUN -> PrimarySkillType.CROSSBOWS; case TRIDENTS_SUPER_ABILITY -> PrimarySkillType.TRIDENTS; - default -> - throw new InvalidSkillException("No parent defined for super ability! " + superAbilityType.toString()); + case EXPLOSIVE_SHOT -> PrimarySkillType.ARCHERY; }; } @@ -340,14 +339,10 @@ public double getXpModifier(PrimarySkillType primarySkillType) { // TODO: This is a little "hacky", we probably need to add something to distinguish child skills in the enum, or to use another enum for them public static boolean isChildSkill(PrimarySkillType primarySkillType) { - switch (primarySkillType) { - case SALVAGE: - case SMELTING: - return true; - - default: - return false; - } + return switch (primarySkillType) { + case SALVAGE, SMELTING -> true; + default -> false; + }; } /** @@ -412,34 +407,7 @@ public int getLevelCap(@NotNull PrimarySkillType primarySkillType) { * @return true if the player has permissions, false otherwise */ public boolean superAbilityPermissionCheck(SuperAbilityType superAbilityType, Player player) { - switch (superAbilityType) { - case BERSERK: - return Permissions.berserk(player); - - case BLAST_MINING: - return Permissions.remoteDetonation(player); - - case GIGA_DRILL_BREAKER: - return Permissions.gigaDrillBreaker(player); - - case GREEN_TERRA: - return Permissions.greenTerra(player); - - case SERRATED_STRIKES: - return Permissions.serratedStrikes(player); - - case SKULL_SPLITTER: - return Permissions.skullSplitter(player); - - case SUPER_BREAKER: - return Permissions.superBreaker(player); - - case TREE_FELLER: - return Permissions.treeFeller(player); - - default: - return false; - } + return superAbilityType.getPermissions(player); } public @NotNull List getChildSkills() { diff --git a/src/test/java/com/gmail/nossr50/MMOMinimalPluginMock.java b/src/test/java/com/gmail/nossr50/MMOMinimalPluginMock.java new file mode 100644 index 0000000000..1ecfce764f --- /dev/null +++ b/src/test/java/com/gmail/nossr50/MMOMinimalPluginMock.java @@ -0,0 +1,163 @@ +package com.gmail.nossr50; + +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.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 org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.plugin.PluginManager; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import java.util.logging.Logger; + +import static org.mockito.ArgumentMatchers.any; + +public abstract class MMOMinimalPluginMock { + protected MockedStatic mockedMcMMO; + protected MockedStatic mockedChatConfig; + protected MockedStatic experienceConfig; + protected MockedStatic mockedPermissions; + protected MockedStatic mockedRankUtils; + protected MockedStatic mockedUserManager; + protected MockedStatic mockedMisc; + protected MockedStatic mockedEventUtils; + protected TransientEntityTracker transientEntityTracker; + protected AdvancedConfig advancedConfig; + protected GeneralConfig generalConfig; + protected RankConfig rankConfig; + protected Server server; + protected PluginManager pluginManager; + protected World world; + + /* Mocks */ + protected ChunkManager chunkManager; + + protected void mockEnvironment(Logger logger) { + mockedMcMMO = Mockito.mockStatic(mcMMO.class); + mcMMO.p = Mockito.mock(mcMMO.class); + Mockito.when(mcMMO.p.getLogger()).thenReturn(logger); + + // place store + chunkManager = Mockito.mock(ChunkManager.class); + Mockito.when(mcMMO.getPlaceStore()).thenReturn(chunkManager); + + // shut off mod manager for woodcutting + Mockito.when(mcMMO.getModManager()).thenReturn(Mockito.mock(ModManager.class)); + Mockito.when(mcMMO.getModManager().isCustomLog(any())).thenReturn(false); + + // chat config + mockedChatConfig = Mockito.mockStatic(ChatConfig.class); + Mockito.when(ChatConfig.getInstance()).thenReturn(Mockito.mock(ChatConfig.class)); + + // general config + mockGeneralConfig(); + + // rank config + mockRankConfig(); + + // wire advanced config + mockAdvancedConfig(); + + // wire experience config + mockExperienceConfig(); + + this.transientEntityTracker = new TransientEntityTracker(); + Mockito.when(mcMMO.getTransientEntityTracker()).thenReturn(transientEntityTracker); + + mockPermissions(); + + mockedRankUtils = Mockito.mockStatic(RankUtils.class); + + // wire server + this.server = Mockito.mock(Server.class); + Mockito.when(mcMMO.p.getServer()).thenReturn(server); + + // wire plugin manager + this.pluginManager = Mockito.mock(PluginManager.class); + Mockito.when(server.getPluginManager()).thenReturn(pluginManager); + + // wire world + this.world = Mockito.mock(World.class); + + // wire Misc + this.mockedMisc = Mockito.mockStatic(Misc.class); + Mockito.when(Misc.getBlockCenter(any())).thenReturn(new Location(world, 0, 0, 0)); + + // wire user manager + this.mockedUserManager = Mockito.mockStatic(UserManager.class); + } + + private void mockPermissions() { + mockedPermissions = Mockito.mockStatic(Permissions.class); + Mockito.when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); + Mockito.when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn(true); + Mockito.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 = Mockito.mock(RankConfig.class); + } + + private void mockAdvancedConfig() { + this.advancedConfig = Mockito.mock(AdvancedConfig.class); + Mockito.when(mcMMO.p.getAdvancedConfig()).thenReturn(advancedConfig); + } + + private void mockGeneralConfig() { + generalConfig = Mockito.mock(GeneralConfig.class); + Mockito.when(generalConfig.getTreeFellerThreshold()).thenReturn(100); + Mockito.when(generalConfig.getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, Material.OAK_LOG)).thenReturn(true); + Mockito.when(generalConfig.getLocale()).thenReturn("en_US"); + Mockito.when(mcMMO.p.getGeneralConfig()).thenReturn(generalConfig); + } + + private void mockExperienceConfig() { + experienceConfig = Mockito.mockStatic(ExperienceConfig.class); + + Mockito.when(ExperienceConfig.getInstance()).thenReturn(Mockito.mock(ExperienceConfig.class)); + + // Combat + Mockito.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(); + } + } +} diff --git a/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java b/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java index 81e0f60942..7ba7ae97c7 100644 --- a/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java +++ b/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java @@ -1,5 +1,6 @@ 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; @@ -26,11 +27,11 @@ import org.mockito.Mockito; import java.util.UUID; +import java.util.logging.Logger; import static org.mockito.ArgumentMatchers.any; public abstract class MMOTestEnvironment { - private final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(MMOTestEnvironment.class.getName()); protected MockedStatic mockedMcMMO; protected MockedStatic mockedChatConfig; protected MockedStatic experienceConfig; @@ -62,7 +63,7 @@ public abstract class MMOTestEnvironment { protected ChunkManager chunkManager; - protected void mockBaseEnvironment() { + protected void mockBaseEnvironment(Logger logger) throws InvalidSkillException { mockedMcMMO = Mockito.mockStatic(mcMMO.class); mcMMO.p = Mockito.mock(mcMMO.class); Mockito.when(mcMMO.p.getLogger()).thenReturn(logger); diff --git a/src/test/java/com/gmail/nossr50/skills/tridents/TridentsTest.java b/src/test/java/com/gmail/nossr50/skills/tridents/TridentsTest.java index 194770f775..199c8e5541 100644 --- a/src/test/java/com/gmail/nossr50/skills/tridents/TridentsTest.java +++ b/src/test/java/com/gmail/nossr50/skills/tridents/TridentsTest.java @@ -1,6 +1,7 @@ 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; @@ -15,8 +16,8 @@ class TridentsTest extends MMOTestEnvironment { TridentsManager tridentsManager; ItemStack trident; @BeforeEach - void setUp() { - mockBaseEnvironment(); + void setUp() throws InvalidSkillException { + mockBaseEnvironment(logger); // setup player and player related mocks after everything else this.player = Mockito.mock(Player.class); diff --git a/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingTest.java b/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingTest.java index 8960ed8218..2715ead651 100644 --- a/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingTest.java +++ b/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingTest.java @@ -1,6 +1,7 @@ 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; @@ -24,8 +25,8 @@ class WoodcuttingTest extends MMOTestEnvironment { WoodcuttingManager woodcuttingManager; @BeforeEach - void setUp() { - mockBaseEnvironment(); + void setUp() throws InvalidSkillException { + mockBaseEnvironment(logger); Mockito.when(rankConfig.getSubSkillUnlockLevel(SubSkillType.WOODCUTTING_HARVEST_LUMBER, 1)).thenReturn(1); // wire advanced config From 967ffd6442468898f07174a38950358b6cddbfe0 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 22 Dec 2023 11:39:13 -0800 Subject: [PATCH 44/75] update Changelog.txt --- Changelog.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog.txt b/Changelog.txt index 2d98e7f99b..ce01f005a0 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,4 +1,6 @@ Version 2.2.000 + TODO: SQL DB update + TODO: SQL unit tests TODO: com/gmail/nossr50/database/FlatFileDatabaseManager.java:109 reporting data entries that need correction on each launch TODO: Add Xbows/Tridents to salvage/repair TODO: Add unit test for combat XP values From 9360e147ac6ce4d1eb9c05f3af0fb4b94a11ed72 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 22 Dec 2023 13:07:34 -0800 Subject: [PATCH 45/75] Fun with arrows --- .../commands/skills/TridentsCommand.java | 6 +-- .../datatypes/skills/SubSkillType.java | 3 +- .../datatypes/skills/SuperAbilityType.java | 2 +- .../nossr50/listeners/EntityListener.java | 51 +++++++++++++++++-- src/main/java/com/gmail/nossr50/mcMMO.java | 2 +- .../gmail/nossr50/util/MetadataConstants.java | 1 + .../resources/locale/locale_en_US.properties | 1 + 7 files changed, 54 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java index ef07c61f00..4acf203de4 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java @@ -2,11 +2,7 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.Permissions; -import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.CombatUtils; -import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -31,7 +27,7 @@ protected void permissionsCheck(Player player) {} protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { List messages = new ArrayList<>(); - if (canUseSubskill(player, SubSkillType.TRIDENTS_TRIDENTS_SUPER_ABILITY)) { + if (canUseSubskill(player, SubSkillType.TRIDENTS_SUPER)) { messages.add("Tridents Super Ability"); //TODO: Implement Tridents Super } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java index e4caa84e1a..0eaf303a30 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java @@ -35,6 +35,7 @@ public enum SubSkillType { /* CROSSBOWS */ CROSSBOWS_SUPER_SHOTGUN(1), CROSSBOWS_CROSSBOWS_LIMIT_BREAK(10), + CROSSBOWS_TRICK_SHOT(5), /* Excavation */ EXCAVATION_ARCHAEOLOGY(8), @@ -99,7 +100,7 @@ public enum SubSkillType { TAMING_THICK_FUR(1), /* Tridents */ - TRIDENTS_TRIDENTS_SUPER_ABILITY(1), + TRIDENTS_SUPER(1), TRIDENTS_TRIDENTS_LIMIT_BREAK(10), /* Unarmed */ diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java index 21bdc041c7..dab6d948d7 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java @@ -112,7 +112,7 @@ public enum SuperAbilityType { TREE_FELLER.subSkillTypeDefinition = SubSkillType.WOODCUTTING_TREE_FELLER; SERRATED_STRIKES.subSkillTypeDefinition = SubSkillType.SWORDS_SERRATED_STRIKES; BLAST_MINING.subSkillTypeDefinition = SubSkillType.MINING_BLAST_MINING; - TRIDENTS_SUPER_ABILITY.subSkillTypeDefinition = SubSkillType.TRIDENTS_TRIDENTS_SUPER_ABILITY; + TRIDENTS_SUPER_ABILITY.subSkillTypeDefinition = SubSkillType.TRIDENTS_SUPER; SUPER_SHOTGUN.subSkillTypeDefinition = SubSkillType.CROSSBOWS_SUPER_SHOTGUN; } diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index 7f71c13f70..fa1b4307ff 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -27,10 +27,7 @@ import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.worldguard.WorldGuardManager; import com.gmail.nossr50.worldguard.WorldGuardUtils; -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.OfflinePlayer; +import org.bukkit.*; import org.bukkit.attribute.Attribute; import org.bukkit.block.Block; import org.bukkit.enchantments.Enchantment; @@ -48,6 +45,7 @@ import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.projectiles.ProjectileSource; +import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; public class EntityListener implements Listener { @@ -1111,5 +1109,50 @@ public void onPotionSplash(PotionSplashEvent event) { } } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onProjectileHitEvent(ProjectileHitEvent event) { + /* WORLD BLACKLIST CHECK */ + if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) + return; + + if(event.getEntity() instanceof Arrow originalArrow && event.getHitBlock() != null) { + if (originalArrow.getShooter() instanceof Player) { + // Avoid infinite spawning of arrows + if (originalArrow.hasMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW)) { + return; + } + // Spawn a new arrow shooting in a random direction + spawnArrow(originalArrow, originalArrow.getLocation()); + spawnArrow(originalArrow, originalArrow.getLocation()); + spawnArrow(originalArrow, originalArrow.getLocation()); + spawnArrow(originalArrow, originalArrow.getLocation()); + spawnArrow(originalArrow, originalArrow.getLocation()); + spawnArrow(originalArrow, originalArrow.getLocation()); + spawnArrow(originalArrow, originalArrow.getLocation()); + spawnArrow(originalArrow, originalArrow.getLocation()); + spawnArrow(originalArrow, originalArrow.getLocation()); + spawnArrow(originalArrow, originalArrow.getLocation()); + spawnArrow(originalArrow, originalArrow.getLocation()); + } + } + } + + private void spawnArrow(Arrow originalArrow, Location origin) { + // TODO: Add an event for this for plugins to hook into + // Spawn a new arrow shooting in a random direction + ProjectileSource originalArrowShooter = originalArrow.getShooter(); + Arrow arrow = originalArrow.getWorld().spawnArrow(origin, + new Vector( + // TODO: Spawn arrow away from surface + Math.random() * 2 - 1, + Math.random() * 2 - 1, + Math.random() * 2 - 1), 1, 1); + arrow.setShooter(originalArrowShooter); + arrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, + new FixedMetadataValue(pluginRef, originalArrowShooter)); + arrow.setMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE, + new FixedMetadataValue(pluginRef, originalArrow.getMetadata( + MetadataConstants.METADATA_KEY_BOW_TYPE).get(0))); + } } diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index f6e96c3fb0..0b06663bc5 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -98,7 +98,7 @@ public class mcMMO extends JavaPlugin { private static CommandManager commandManager; //ACF private static TransientEntityTracker transientEntityTracker; - private @NotNull SkillTools skillTools; + private SkillTools skillTools; private static boolean serverShutdownExecuted = false; diff --git a/src/main/java/com/gmail/nossr50/util/MetadataConstants.java b/src/main/java/com/gmail/nossr50/util/MetadataConstants.java index 8bec613653..321dcf2a11 100644 --- a/src/main/java/com/gmail/nossr50/util/MetadataConstants.java +++ b/src/main/java/com/gmail/nossr50/util/MetadataConstants.java @@ -14,6 +14,7 @@ public class MetadataConstants { * Take great care if you ever modify the value of these keys */ public static final @NotNull String METADATA_KEY_REPLANT = "mcMMO: Recently Replanted"; + public static final @NotNull String METADATA_KEY_SPAWNED_ARROW = "mcMMO: Spawned Arrow"; public static final @NotNull String METADATA_KEY_BOW_TYPE = "mcMMO: Bow Type"; public static final @NotNull String METADATA_KEY_EXPLOSION_FROM_RUPTURE = "mcMMO: Rupture Explosion"; public static final @NotNull String METADATA_KEY_FISH_HOOK_REF = "mcMMO: Fish Hook Tracker"; diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 553240d5b2..afc91df236 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -182,6 +182,7 @@ Archery.SubSkill.ArcheryLimitBreak.Description=Breaking your limits. Increased d Archery.SubSkill.ArcheryLimitBreak.Stat=Limit Break Max DMG Archery.Listener=Archery: Archery.SkillName=ARCHERY +Archery.SubSkill.ExplosiveShot.Name=Explosive Shot Archery.Skills.ExplosiveShot.Off= Archery.Skills.ExplosiveShot.On=&a**EXPLOSIVE SHOT ACTIVATED** Archery.Skills.ExplosiveShot.Other.Off=Explosive Shot&a has worn off for &e{0} From 1799d455b770df07bd6aaf1ed570c809abd5f977 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sat, 23 Dec 2023 16:28:18 -0800 Subject: [PATCH 46/75] Deflect arrows off surfaces --- Changelog.txt | 1 + .../nossr50/listeners/EntityListener.java | 41 ++++++++++--------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index ce01f005a0..d2873c6bf1 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,4 +1,5 @@ Version 2.2.000 + TODO: Cleanup new arrow metadatas TODO: SQL DB update TODO: SQL unit tests TODO: com/gmail/nossr50/database/FlatFileDatabaseManager.java:109 reporting data entries that need correction on each launch diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index fa1b4307ff..fd0180134f 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -30,6 +30,7 @@ import org.bukkit.*; import org.bukkit.attribute.Attribute; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.*; import org.bukkit.event.Cancellable; @@ -1115,7 +1116,7 @@ public void onProjectileHitEvent(ProjectileHitEvent event) { if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) return; - if(event.getEntity() instanceof Arrow originalArrow && event.getHitBlock() != null) { + if(event.getEntity() instanceof Arrow originalArrow && event.getHitBlock() != null && event.getHitBlockFace() != null) { if (originalArrow.getShooter() instanceof Player) { // Avoid infinite spawning of arrows if (originalArrow.hasMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW)) { @@ -1123,34 +1124,36 @@ public void onProjectileHitEvent(ProjectileHitEvent event) { } // Spawn a new arrow shooting in a random direction - spawnArrow(originalArrow, originalArrow.getLocation()); - spawnArrow(originalArrow, originalArrow.getLocation()); - spawnArrow(originalArrow, originalArrow.getLocation()); - spawnArrow(originalArrow, originalArrow.getLocation()); - spawnArrow(originalArrow, originalArrow.getLocation()); - spawnArrow(originalArrow, originalArrow.getLocation()); - spawnArrow(originalArrow, originalArrow.getLocation()); - spawnArrow(originalArrow, originalArrow.getLocation()); - spawnArrow(originalArrow, originalArrow.getLocation()); - spawnArrow(originalArrow, originalArrow.getLocation()); - spawnArrow(originalArrow, originalArrow.getLocation()); + spawnArrow(originalArrow, originalArrow.getLocation(), getNormal(event.getHitBlockFace())); } } } - private void spawnArrow(Arrow originalArrow, Location origin) { + private Vector getNormal(BlockFace blockFace) { + return switch (blockFace) { + case UP -> new Vector(0, 1, 0); + case DOWN -> new Vector(0, -1, 0); + case NORTH -> new Vector(0, 0, -1); + case SOUTH -> new Vector(0, 0, 1); + case EAST -> new Vector(1, 0, 0); + case WEST -> new Vector(-1, 0, 0); + default -> new Vector(0, 0, 0); + }; + } + + private void spawnArrow(Arrow originalArrow, Location origin, Vector normal) { // TODO: Add an event for this for plugins to hook into - // Spawn a new arrow shooting in a random direction ProjectileSource originalArrowShooter = originalArrow.getShooter(); + Vector incomingDirection = originalArrow.getVelocity(); + Vector reflectedDirection = incomingDirection.subtract(normal.multiply(2 * incomingDirection.dot(normal))); + + // Spawn new arrow with the reflected direction Arrow arrow = originalArrow.getWorld().spawnArrow(origin, - new Vector( - // TODO: Spawn arrow away from surface - Math.random() * 2 - 1, - Math.random() * 2 - 1, - Math.random() * 2 - 1), 1, 1); + reflectedDirection, 1, 1); arrow.setShooter(originalArrowShooter); arrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, new FixedMetadataValue(pluginRef, originalArrowShooter)); + // TODO: This metadata needs to get cleaned up at some point arrow.setMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE, new FixedMetadataValue(pluginRef, originalArrow.getMetadata( MetadataConstants.METADATA_KEY_BOW_TYPE).get(0))); From afff3b4c50a814d0cd7162caefddb04f8295b160 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sat, 23 Dec 2023 17:04:19 -0800 Subject: [PATCH 47/75] Move projectile stuff to util --- .../nossr50/listeners/EntityListener.java | 41 ++++-------------- .../nossr50/util/skills/ProjectileUtils.java | 42 +++++++++++++++++++ 2 files changed, 49 insertions(+), 34 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index fd0180134f..8f1ac4432d 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -25,12 +25,12 @@ import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.CombatUtils; +import com.gmail.nossr50.util.skills.ProjectileUtils; import com.gmail.nossr50.worldguard.WorldGuardManager; import com.gmail.nossr50.worldguard.WorldGuardUtils; import org.bukkit.*; import org.bukkit.attribute.Attribute; import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.*; import org.bukkit.event.Cancellable; @@ -46,9 +46,11 @@ import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.projectiles.ProjectileSource; -import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; +import static com.gmail.nossr50.util.skills.ProjectileUtils.getNormal; +import static com.gmail.nossr50.util.skills.ProjectileUtils.spawnReflectedArrow; + public class EntityListener implements Listener { private final mcMMO pluginRef; private final @NotNull MobMetadataService mobMetadataService; @@ -1123,39 +1125,10 @@ public void onProjectileHitEvent(ProjectileHitEvent event) { return; } - // Spawn a new arrow shooting in a random direction - spawnArrow(originalArrow, originalArrow.getLocation(), getNormal(event.getHitBlockFace())); + // Spawn a new arrow shooting in the reflected direction + spawnReflectedArrow(pluginRef, originalArrow, originalArrow.getLocation(), + getNormal(event.getHitBlockFace())); } } } - - private Vector getNormal(BlockFace blockFace) { - return switch (blockFace) { - case UP -> new Vector(0, 1, 0); - case DOWN -> new Vector(0, -1, 0); - case NORTH -> new Vector(0, 0, -1); - case SOUTH -> new Vector(0, 0, 1); - case EAST -> new Vector(1, 0, 0); - case WEST -> new Vector(-1, 0, 0); - default -> new Vector(0, 0, 0); - }; - } - - private void spawnArrow(Arrow originalArrow, Location origin, Vector normal) { - // TODO: Add an event for this for plugins to hook into - ProjectileSource originalArrowShooter = originalArrow.getShooter(); - Vector incomingDirection = originalArrow.getVelocity(); - Vector reflectedDirection = incomingDirection.subtract(normal.multiply(2 * incomingDirection.dot(normal))); - - // Spawn new arrow with the reflected direction - Arrow arrow = originalArrow.getWorld().spawnArrow(origin, - reflectedDirection, 1, 1); - arrow.setShooter(originalArrowShooter); - arrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, - new FixedMetadataValue(pluginRef, originalArrowShooter)); - // TODO: This metadata needs to get cleaned up at some point - arrow.setMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE, - new FixedMetadataValue(pluginRef, originalArrow.getMetadata( - MetadataConstants.METADATA_KEY_BOW_TYPE).get(0))); - } } diff --git a/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java b/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java new file mode 100644 index 0000000000..6212b81393 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java @@ -0,0 +1,42 @@ +package com.gmail.nossr50.util.skills; + +import com.gmail.nossr50.util.MetadataConstants; +import org.bukkit.Location; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Arrow; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.plugin.Plugin; +import org.bukkit.projectiles.ProjectileSource; +import org.bukkit.util.Vector; + +public class ProjectileUtils { + public static Vector getNormal(BlockFace blockFace) { + return switch (blockFace) { + case UP -> new Vector(0, 1, 0); + case DOWN -> new Vector(0, -1, 0); + case NORTH -> new Vector(0, 0, -1); + case SOUTH -> new Vector(0, 0, 1); + case EAST -> new Vector(1, 0, 0); + case WEST -> new Vector(-1, 0, 0); + default -> new Vector(0, 0, 0); + }; + } + + public static void spawnReflectedArrow(Plugin pluginRef, Arrow originalArrow, Location origin, Vector normal) { + // TODO: Add an event for this for plugins to hook into + ProjectileSource originalArrowShooter = originalArrow.getShooter(); + Vector incomingDirection = originalArrow.getVelocity(); + Vector reflectedDirection = incomingDirection.subtract(normal.multiply(2 * incomingDirection.dot(normal))); + + // Spawn new arrow with the reflected direction + Arrow arrow = originalArrow.getWorld().spawnArrow(origin, + reflectedDirection, 1, 1); + arrow.setShooter(originalArrowShooter); + arrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, + new FixedMetadataValue(pluginRef, originalArrowShooter)); + // TODO: This metadata needs to get cleaned up at some point + arrow.setMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE, + new FixedMetadataValue(pluginRef, originalArrow.getMetadata( + MetadataConstants.METADATA_KEY_BOW_TYPE).get(0))); + } +} From 76d4b5055455e5fab1a4e87b6cbb697d8d4e5be6 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 27 Dec 2023 19:20:32 -0800 Subject: [PATCH 48/75] Refactor ricochet code, don't reflect shallow angles --- Changelog.txt | 2 + .../datatypes/skills/SubSkillType.java | 2 +- .../nossr50/listeners/EntityListener.java | 24 ++----- .../nossr50/skills/crossbows/Crossbows.java | 35 ++++++++++ .../skills/crossbows/CrossbowsManager.java | 40 +++++++++++ .../nossr50/util/skills/CombatUtils.java | 66 ++----------------- .../nossr50/util/skills/ProjectileUtils.java | 48 ++++++++------ 7 files changed, 119 insertions(+), 98 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java diff --git a/Changelog.txt b/Changelog.txt index d2873c6bf1..310194a2f2 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,4 +1,6 @@ Version 2.2.000 + TODO: Trickshot: locale, multiple bounces, does not hurt yourself or allies, reduced damage per bounce? + TODO: Add metadata cleanup unit tests TODO: Cleanup new arrow metadatas TODO: SQL DB update TODO: SQL unit tests diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java index 0eaf303a30..3dc587eaeb 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java @@ -35,7 +35,7 @@ public enum SubSkillType { /* CROSSBOWS */ CROSSBOWS_SUPER_SHOTGUN(1), CROSSBOWS_CROSSBOWS_LIMIT_BREAK(10), - CROSSBOWS_TRICK_SHOT(5), + CROSSBOWS_TRICK_SHOT(3), /* Excavation */ EXCAVATION_ARCHAEOLOGY(8), diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index 8f1ac4432d..0e4d50b51c 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -15,6 +15,7 @@ import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.runnables.TravelingBlockMetaCleanup; import com.gmail.nossr50.skills.archery.Archery; +import com.gmail.nossr50.skills.crossbows.Crossbows; import com.gmail.nossr50.skills.mining.BlastMining; import com.gmail.nossr50.skills.mining.MiningManager; import com.gmail.nossr50.skills.taming.Taming; @@ -28,7 +29,10 @@ import com.gmail.nossr50.util.skills.ProjectileUtils; import com.gmail.nossr50.worldguard.WorldGuardManager; import com.gmail.nossr50.worldguard.WorldGuardUtils; -import org.bukkit.*; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.OfflinePlayer; import org.bukkit.attribute.Attribute; import org.bukkit.block.Block; import org.bukkit.enchantments.Enchantment; @@ -48,9 +52,6 @@ import org.bukkit.projectiles.ProjectileSource; import org.jetbrains.annotations.NotNull; -import static com.gmail.nossr50.util.skills.ProjectileUtils.getNormal; -import static com.gmail.nossr50.util.skills.ProjectileUtils.spawnReflectedArrow; - public class EntityListener implements Listener { private final mcMMO pluginRef; private final @NotNull MobMetadataService mobMetadataService; @@ -411,7 +412,7 @@ public void onEntityDamageMonitor(EntityDamageByEntityEvent entityDamageEvent) { } if(entityDamageEvent.getDamager() instanceof Projectile) { - CombatUtils.cleanupArrowMetadata((Projectile) entityDamageEvent.getDamager()); + ProjectileUtils.cleanupProjectileMetadata((Projectile) entityDamageEvent.getDamager()); } if(entityDamageEvent.getEntity() instanceof Player player && entityDamageEvent.getDamager() instanceof Player) { @@ -1118,17 +1119,6 @@ public void onProjectileHitEvent(ProjectileHitEvent event) { if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) return; - if(event.getEntity() instanceof Arrow originalArrow && event.getHitBlock() != null && event.getHitBlockFace() != null) { - if (originalArrow.getShooter() instanceof Player) { - // Avoid infinite spawning of arrows - if (originalArrow.hasMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW)) { - return; - } - - // Spawn a new arrow shooting in the reflected direction - spawnReflectedArrow(pluginRef, originalArrow, originalArrow.getLocation(), - getNormal(event.getHitBlockFace())); - } - } + Crossbows.processCrossbows(event, pluginRef); } } diff --git a/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java b/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java new file mode 100644 index 0000000000..02ea5b24a3 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java @@ -0,0 +1,35 @@ +package com.gmail.nossr50.skills.crossbows; + +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.util.MetadataConstants; +import com.gmail.nossr50.util.player.UserManager; +import org.bukkit.entity.Arrow; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.ProjectileHitEvent; +import org.bukkit.plugin.Plugin; + +import static com.gmail.nossr50.util.skills.ProjectileUtils.getNormal; + +/** + * Util class for crossbows. + */ +public class Crossbows { + public static void processCrossbows(ProjectileHitEvent event, Plugin pluginRef) { + if(event.getEntity() instanceof Arrow originalArrow && event.getHitBlock() != null && event.getHitBlockFace() != null) { + if (originalArrow.getShooter() instanceof Player) { + // Avoid infinite spawning of arrows + if (originalArrow.hasMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW)) { + return; + } + + McMMOPlayer mmoPlayer = UserManager.getPlayer((Player) originalArrow.getShooter()); + if (mmoPlayer != null) { + mmoPlayer.getCrossbowsManager().handleRicochet( + pluginRef, + originalArrow, + getNormal(event.getHitBlockFace())); + } + } + } + } +} diff --git a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java index 29eb39d712..8cb3337ebe 100644 --- a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java @@ -3,9 +3,49 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.skills.SkillManager; +import com.gmail.nossr50.util.MetadataConstants; +import org.bukkit.Location; +import org.bukkit.entity.Arrow; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.plugin.Plugin; +import org.bukkit.projectiles.ProjectileSource; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; public class CrossbowsManager extends SkillManager { public CrossbowsManager(McMMOPlayer mmoPlayer) { super(mmoPlayer, PrimarySkillType.CROSSBOWS); } + + public void handleRicochet(@NotNull Plugin pluginRef, @NotNull Arrow originalArrow, @NotNull Vector hitBlockNormal) { + // Reflect arrow in new direction + // cleanup metadata on original arrow + // TODO: Add an event for this for plugins to hook into + spawnReflectedArrow(pluginRef, originalArrow, originalArrow.getLocation(), hitBlockNormal); + } + + public void spawnReflectedArrow(@NotNull Plugin pluginRef, @NotNull Arrow originalArrow, @NotNull Location origin, @NotNull Vector normal) { + final ProjectileSource originalArrowShooter = originalArrow.getShooter(); + final Vector arrowInBlockVector = originalArrow.getVelocity(); + final Vector reflectedDirection = arrowInBlockVector.subtract(normal.multiply(2 * arrowInBlockVector.dot(normal))); + final Vector inverseNormal = normal.multiply(-1); + + + // check the angle of the arrow against the inverse normal to see if the angle was too shallow + if (arrowInBlockVector.angle(inverseNormal) < Math.PI / 4) { + return; + } + + // Spawn new arrow with the reflected direction + Arrow arrow = originalArrow.getWorld().spawnArrow(origin, + reflectedDirection, 1, 1); + arrow.setShooter(originalArrowShooter); + arrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, + new FixedMetadataValue(pluginRef, originalArrowShooter)); + + // TODO: This metadata needs to get cleaned up at some point + arrow.setMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE, + new FixedMetadataValue(pluginRef, originalArrow.getMetadata( + MetadataConstants.METADATA_KEY_BOW_TYPE).get(0))); + } } diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index 399a875ec5..7b1d07d86c 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -161,16 +161,10 @@ private static void processCrossbowsCombat(@NotNull LivingEntity target, @NotNul //Make sure the profiles been loaded if(mcMMOPlayer == null) { - cleanupArrowMetadata(arrow); + ProjectileUtils.cleanupProjectileMetadata(arrow); return; } - // CrossbowsManager crossbowsManager = mcMMOPlayer.getCrossbowsManager(); - -// if (crossbowsManager.canActivateAbility()) { -// mcMMOPlayer.checkAbilityActivation(PrimarySkillType.CROSSBOWS); -// } - double boostedDamage = event.getDamage(); if(canUseLimitBreak(player, target, SubSkillType.CROSSBOWS_CROSSBOWS_LIMIT_BREAK)) { @@ -190,7 +184,7 @@ private static void processCrossbowsCombat(@NotNull LivingEntity target, @NotNul "Final Damage: "+boostedDamage); //Clean data - cleanupArrowMetadata(arrow); + ProjectileUtils.cleanupProjectileMetadata(arrow); } private static void processAxeCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) { @@ -327,7 +321,7 @@ private static void processArcheryCombat(@NotNull LivingEntity target, @NotNull //Make sure the profiles been loaded if(mcMMOPlayer == null) { - cleanupArrowMetadata(arrow); + ProjectileUtils.cleanupProjectileMetadata(arrow); return; } @@ -368,7 +362,7 @@ private static void processArcheryCombat(@NotNull LivingEntity target, @NotNull "Initial Damage: "+initialDamage, "Final Damage: "+boostedDamage); //Clean data - cleanupArrowMetadata(arrow); + ProjectileUtils.cleanupProjectileMetadata(arrow); } /** @@ -500,7 +494,7 @@ else if (entityType == EntityType.ARROW || entityType == EntityType.SPECTRAL_ARR } } else { //Cleanup Arrow - cleanupArrowMetadata(arrow); + ProjectileUtils.cleanupProjectileMetadata(arrow); } if (target.getType() != EntityType.CREEPER @@ -733,35 +727,6 @@ public static void dealNoInvulnerabilityTickDamageRupture(@NotNull LivingEntity } dealNoInvulnerabilityTickDamage(target, damage, attacker); - -// //IFrame storage -//// int noDamageTicks = target.getNoDamageTicks(); -// -//// String debug = "BLEED DMG RESULT: INC DMG:"+damage+", HP-Before:"+target.getHealth()+", HP-After:"; -// -//// double incDmg = getFakeDamageFinalResult(attacker, target, DamageCause.ENTITY_ATTACK, damage); -// -//// double newHealth = Math.max(0, target.getHealth() - incDmg); -// -// //Don't kill things with a stone or wooden weapon -//// if(toolTier < 3 && newHealth == 0) -//// return; -// -// target.setMetadata(mcMMO.CUSTOM_DAMAGE_METAKEY, mcMMO.metadataValue); -// -// if(newHealth == 0 && !(target instanceof Player)) -// { -// target.damage(99999, attacker); -// } -// else -// { -//// Vector beforeRuptureVec = new Vector(target.getVelocity().getX(), target.getVelocity().getY(), target.getVelocity().getZ()); ; -// target.damage(damage, attacker); -//// debug+=target.getHealth(); -// Bukkit.broadcastMessage(debug); -//// target.setNoDamageTicks(noDamageTicks); //Do not add additional IFrames -//// target.setVelocity(beforeRuptureVec); -// } } /** @@ -1062,31 +1027,12 @@ public static void modifyMoveSpeed(@NotNull LivingEntity livingEntity, double mu } } - /** - * Clean up metadata from a projectile - * - * @param entity projectile - */ - public static void cleanupArrowMetadata(@NotNull Projectile entity) { - if(entity.hasMetadata(MetadataConstants.METADATA_KEY_INF_ARROW)) { - entity.removeMetadata(MetadataConstants.METADATA_KEY_INF_ARROW, mcMMO.p); - } - - if(entity.hasMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE)) { - entity.removeMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, mcMMO.p); - } - - if(entity.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE)) { - entity.removeMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, mcMMO.p); - } - } - /** * Clean up metadata from a projectile after a minute has passed * * @param entity the projectile */ public static void delayArrowMetaCleanup(@NotNull Projectile entity) { - mcMMO.p.getFoliaLib().getImpl().runLater(() -> cleanupArrowMetadata(entity), 20*60); + mcMMO.p.getFoliaLib().getImpl().runLater(() -> ProjectileUtils.cleanupProjectileMetadata(entity), 20*60); } } diff --git a/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java b/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java index 6212b81393..0ef2ccd465 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java @@ -1,13 +1,11 @@ package com.gmail.nossr50.util.skills; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.MetadataConstants; -import org.bukkit.Location; import org.bukkit.block.BlockFace; -import org.bukkit.entity.Arrow; -import org.bukkit.metadata.FixedMetadataValue; -import org.bukkit.plugin.Plugin; -import org.bukkit.projectiles.ProjectileSource; +import org.bukkit.entity.Projectile; import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; public class ProjectileUtils { public static Vector getNormal(BlockFace blockFace) { @@ -22,21 +20,31 @@ public static Vector getNormal(BlockFace blockFace) { }; } - public static void spawnReflectedArrow(Plugin pluginRef, Arrow originalArrow, Location origin, Vector normal) { - // TODO: Add an event for this for plugins to hook into - ProjectileSource originalArrowShooter = originalArrow.getShooter(); - Vector incomingDirection = originalArrow.getVelocity(); - Vector reflectedDirection = incomingDirection.subtract(normal.multiply(2 * incomingDirection.dot(normal))); + /** + * Clean up all possible mcMMO related metadata for a projectile + * + * @param entity projectile + */ + // TODO: Add test + public static void cleanupProjectileMetadata(@NotNull Projectile entity) { + if(entity.hasMetadata(MetadataConstants.METADATA_KEY_INF_ARROW)) { + entity.removeMetadata(MetadataConstants.METADATA_KEY_INF_ARROW, mcMMO.p); + } - // Spawn new arrow with the reflected direction - Arrow arrow = originalArrow.getWorld().spawnArrow(origin, - reflectedDirection, 1, 1); - arrow.setShooter(originalArrowShooter); - arrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, - new FixedMetadataValue(pluginRef, originalArrowShooter)); - // TODO: This metadata needs to get cleaned up at some point - arrow.setMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE, - new FixedMetadataValue(pluginRef, originalArrow.getMetadata( - MetadataConstants.METADATA_KEY_BOW_TYPE).get(0))); + if(entity.hasMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE)) { + entity.removeMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, mcMMO.p); + } + + if(entity.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE)) { + entity.removeMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, mcMMO.p); + } + + if(entity.hasMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE)) { + entity.removeMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE, mcMMO.p); + } + + if(entity.hasMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW)) { + entity.removeMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, mcMMO.p); + } } } From dadc295431ca487f65617867815ba515741d82bf Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 27 Dec 2023 19:20:41 -0800 Subject: [PATCH 49/75] Trickshot boiler plate stuff --- src/main/resources/locale/locale_en_US.properties | 7 ++++++- src/main/resources/plugin.yml | 5 ++++- src/main/resources/skillranks.yml | 9 +++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index afc91df236..58943933ae 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -430,10 +430,15 @@ Crossbows.Skills.SSG.Refresh=&aYour &eSuper Shotgun &aability is refreshed! Crossbows.Skills.SSG.Other.On=&a{0}&2 used &Super Shotgun! Crossbows.SubSkill.SuperShotgun.Name=Super Shotgun Crossbows.SubSkill.SuperShotgun.Description=Shoot dozens of arrows at once -Crossbows.SubSkill.SuperShotgun.Stat=Per Projectile damage {0} +Crossbows.SubSkill.SuperShotgun.Stat=Per Projectile damage &a{0} Crossbows.SubSkill.CrossbowsLimitBreak.Name=Crossbows Limit Break Crossbows.SubSkill.CrossbowsLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether it will boost damage in PVE. Crossbows.SubSkill.CrossbowsLimitBreak.Stat=Limit Break Max DMG +Crossbows.SubSkill.TrickShot.Name=Trick Shot +Crossbows.SubSkill.TrickShot.Description=Richochet arrows with steep angles +Crossbows.SubSkill.TrickShot.Stat=Trick Shot Chance +Crossbows.SubSkill.TrickShot.Stat.Extra=Trick Shot Max Bounces: &a{0} +Crossbows.SubSkill.TrickShot.Stat.Extra2=Trick Shot Reduced DMG per Bounce: &a{0} Crossbows.Listener=Crossbows: #TRIDENTS diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index e2fea0ae21..a0e57eb5d8 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -339,11 +339,14 @@ permissions: description: Allows access to all Crossbows abilities children: mcmmo.ability.crossbows.supershotgun: true + mcmmo.ability.crossbows.trickshot: true mcmmo.ability.crossbows.crossbowslimitbreak: true mcmmo.ability.crossbows.supershotgun: - description: Allows access to the Super Shotgun ability + description: Allows access to the Super Shotgun super ability mcmmo.ability.crossbows.crossbowslimitbreak: description: Adds damage to crossbows + mcmmo.ability.crossbows.trickshot: + description: Allows access to the Trick Shot ability mcmmo.ability.excavation.*: default: false description: Allows access to all Excavation abilities diff --git a/src/main/resources/skillranks.yml b/src/main/resources/skillranks.yml index d214204cb1..5ad0e84ee2 100644 --- a/src/main/resources/skillranks.yml +++ b/src/main/resources/skillranks.yml @@ -207,6 +207,15 @@ Axes: Rank_3: 150 Rank_4: 200 Crossbows: + TrickShot: + Standard: + Rank_1: 5 + Rank_2: 20 + Rank_3: 40 + RetroMode: + Rank_1: 50 + Rank_2: 200 + Rank_3: 400 CrossbowsLimitBreak: Standard: Rank_1: 10 From b0efd465846a4fa0edde9e109b896be6e4e2ddbe Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 27 Dec 2023 21:14:14 -0800 Subject: [PATCH 50/75] starting work on sql unit tests --- pom.xml | 13 +- .../database/DatabaseManagerFactory.java | 5 +- .../nossr50/database/SQLDatabaseManager.java | 187 +++++++++++------- .../database/SQLDatabaseManagerTest.java | 145 ++++++++++++++ 4 files changed, 271 insertions(+), 79 deletions(-) create mode 100644 src/test/java/com/gmail/nossr50/database/SQLDatabaseManagerTest.java diff --git a/pom.xml b/pom.xml index c092e74948..26d3b2fc46 100644 --- a/pom.xml +++ b/pom.xml @@ -14,9 +14,9 @@ UTF-8 - 16 - 16 - 16 + 17 + 17 + 17 @@ -257,6 +257,13 @@ + + + com.h2database + h2 + 2.2.224 + test + me.clip placeholderapi diff --git a/src/main/java/com/gmail/nossr50/database/DatabaseManagerFactory.java b/src/main/java/com/gmail/nossr50/database/DatabaseManagerFactory.java index cb5025f6f1..df6c5a1580 100644 --- a/src/main/java/com/gmail/nossr50/database/DatabaseManagerFactory.java +++ b/src/main/java/com/gmail/nossr50/database/DatabaseManagerFactory.java @@ -10,6 +10,7 @@ public class DatabaseManagerFactory { private static Class customManager = null; + public static final String MYSQL_DRIVER = "com.mysql.cj.jdbc.Driver"; public static DatabaseManager getDatabaseManager(@NotNull String userFilePath, @NotNull Logger logger, long purgeTime, int startingLevel) { if (customManager != null) { @@ -27,7 +28,7 @@ public static DatabaseManager getDatabaseManager(@NotNull String userFilePath, @ LogUtils.debug(mcMMO.p.getLogger(), "Falling back on " + (mcMMO.p.getGeneralConfig().getUseMySQL() ? "SQL" : "Flatfile") + " database"); } - return mcMMO.p.getGeneralConfig().getUseMySQL() ? new SQLDatabaseManager() : new FlatFileDatabaseManager(userFilePath, logger, purgeTime, startingLevel); + return mcMMO.p.getGeneralConfig().getUseMySQL() ? new SQLDatabaseManager(logger, MYSQL_DRIVER) : new FlatFileDatabaseManager(userFilePath, logger, purgeTime, startingLevel); } /** @@ -68,7 +69,7 @@ public static Class getCustomDatabaseManagerClass() { case SQL: LogUtils.debug(mcMMO.p.getLogger(), "Using SQL Database"); - return new SQLDatabaseManager(); + return new SQLDatabaseManager(logger, "com.mysql.cj.jdbc.Driver"); case CUSTOM: try { diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index 0be013e7e4..a2e85bf263 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -24,6 +24,7 @@ import java.sql.*; import java.util.*; import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Logger; public final class SQLDatabaseManager implements DatabaseManager { private static final String ALL_QUERY_VERSION = "total"; @@ -45,23 +46,19 @@ public final class SQLDatabaseManager implements DatabaseManager { private final ReentrantLock massUpdateLock = new ReentrantLock(); private final String CHARSET_SQL = "utf8mb4"; //This is compliant with UTF-8 while "utf8" is not, confusing but this is how it is. - private String driverPath = "com.mysql.cj.jdbc.Driver"; //modern driver + private final Logger logger; + private final boolean h2; - protected SQLDatabaseManager() { - String connectionString = "jdbc:mysql://" + mcMMO.p.getGeneralConfig().getMySQLServerName() - + ":" + mcMMO.p.getGeneralConfig().getMySQLServerPort() + "/" + mcMMO.p.getGeneralConfig().getMySQLDatabaseName(); + SQLDatabaseManager(Logger logger, String driverPath) { + this(logger, driverPath, false); + } - if(!mcMMO.getCompatibilityManager().getMinecraftGameVersion().isAtLeast(1, 17, 0) //Temporary hack for SQL and 1.17 support - && mcMMO.p.getGeneralConfig().getMySQLSSL()) - connectionString += - "?verifyServerCertificate=false"+ - "&useSSL=true"+ - "&requireSSL=true"; - else - connectionString+= - "?useSSL=false"; + SQLDatabaseManager(Logger logger, String driverPath, boolean h2) { + this.logger = logger; + this.h2 = h2; + String connectionString = getConnectionString(h2); - if(mcMMO.p.getGeneralConfig().getMySQLPublicKeyRetrieval()) { + if(!h2 && mcMMO.p.getGeneralConfig().getMySQLPublicKeyRetrieval()) { connectionString+= "&allowPublicKeyRetrieval=true"; } @@ -76,7 +73,7 @@ protected SQLDatabaseManager() { } catch (ClassNotFoundException ex) { e.printStackTrace(); ex.printStackTrace(); - mcMMO.p.getLogger().severe("Neither driver found"); + logger.severe("Neither driver found"); return; } //throw e; // aborts onEnable() Riking if you want to do this, fully implement it. @@ -133,9 +130,30 @@ protected SQLDatabaseManager() { checkStructure(); } + @NotNull + private static String getConnectionString(boolean h2) { + if (h2) { + return "jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;MODE=MySQL"; + } + + String connectionString = "jdbc:mysql://" + mcMMO.p.getGeneralConfig().getMySQLServerName() + + ":" + mcMMO.p.getGeneralConfig().getMySQLServerPort() + "/" + mcMMO.p.getGeneralConfig().getMySQLDatabaseName(); + + if(!mcMMO.getCompatibilityManager().getMinecraftGameVersion().isAtLeast(1, 17, 0) //Temporary hack for SQL and 1.17 support + && mcMMO.p.getGeneralConfig().getMySQLSSL()) + connectionString += + "?verifyServerCertificate=false"+ + "&useSSL=true"+ + "&requireSSL=true"; + else + connectionString+= + "?useSSL=false"; + return connectionString; + } + public int purgePowerlessUsers() { massUpdateLock.lock(); - mcMMO.p.getLogger().info("Purging powerless users..."); + logger.info("Purging powerless users..."); Connection connection = null; Statement statement = null; @@ -165,13 +183,13 @@ public int purgePowerlessUsers() { massUpdateLock.unlock(); } - mcMMO.p.getLogger().info("Purged " + purged + " users from the database."); + logger.info("Purged " + purged + " users from the database."); return purged; } public void purgeOldUsers() { massUpdateLock.lock(); - mcMMO.p.getLogger().info("Purging inactive users older than " + (mcMMO.p.getPurgeTime() / 2630000000L) + " months..."); + logger.info("Purging inactive users older than " + (mcMMO.p.getPurgeTime() / 2630000000L) + " months..."); Connection connection = null; Statement statement = null; @@ -196,7 +214,7 @@ public void purgeOldUsers() { massUpdateLock.unlock(); } - mcMMO.p.getLogger().info("Purged " + purged + " users from the database."); + logger.info("Purged " + purged + " users from the database."); } public boolean removeUser(String playerName, UUID uuid) { @@ -253,7 +271,7 @@ public boolean saveUser(PlayerProfile profile) { if (id == -1) { id = newUser(connection, profile.getPlayerName(), profile.getUniqueId()); if (id == -1) { - mcMMO.p.getLogger().severe("Failed to create new account for " + profile.getPlayerName()); + logger.severe("Failed to create new account for " + profile.getPlayerName()); return false; } } @@ -263,7 +281,7 @@ public boolean saveUser(PlayerProfile profile) { success &= (statement.executeUpdate() != 0); statement.close(); if (!success) { - mcMMO.p.getLogger().severe("Failed to update last login for " + profile.getPlayerName()); + logger.severe("Failed to update last login for " + profile.getPlayerName()); return false; } @@ -293,7 +311,7 @@ public boolean saveUser(PlayerProfile profile) { success &= (statement.executeUpdate() != 0); statement.close(); if (!success) { - mcMMO.p.getLogger().severe("Failed to update skills for " + profile.getPlayerName()); + logger.severe("Failed to update skills for " + profile.getPlayerName()); return false; } @@ -319,7 +337,7 @@ public boolean saveUser(PlayerProfile profile) { success &= (statement.executeUpdate() != 0); statement.close(); if (!success) { - mcMMO.p.getLogger().severe("Failed to update experience for " + profile.getPlayerName()); + logger.severe("Failed to update experience for " + profile.getPlayerName()); return false; } @@ -340,7 +358,7 @@ public boolean saveUser(PlayerProfile profile) { success = (statement.executeUpdate() != 0); statement.close(); if (!success) { - mcMMO.p.getLogger().severe("Failed to update cooldowns for " + profile.getPlayerName()); + logger.severe("Failed to update cooldowns for " + profile.getPlayerName()); return false; } @@ -351,7 +369,7 @@ public boolean saveUser(PlayerProfile profile) { success = (statement.executeUpdate() != 0); statement.close(); if (!success) { - mcMMO.p.getLogger().severe("Failed to update hud settings for " + profile.getPlayerName()); + logger.severe("Failed to update hud settings for " + profile.getPlayerName()); return false; } } @@ -371,7 +389,7 @@ public boolean saveUser(PlayerProfile profile) { //Fix for a plugin that people are using that is throwing SQL errors if(skill != null && SkillTools.isChildSkill(skill)) { - mcMMO.p.getLogger().severe("A plugin hooking into mcMMO is being naughty with our database commands, update all plugins that hook into mcMMO and contact their devs!"); + logger.severe("A plugin hooking into mcMMO is being naughty with our database commands, update all plugins that hook into mcMMO and contact their devs!"); throw new InvalidSkillException("A plugin hooking into mcMMO that you are using is attempting to read leaderboard skills for child skills, child skills do not have leaderboards! This is NOT an mcMMO error!"); } @@ -560,7 +578,7 @@ private int newUser(Connection connection, String playerName, UUID uuid) { resultSet = statement.getGeneratedKeys(); if (!resultSet.next()) { - mcMMO.p.getLogger().severe("Unable to create new user account in DB"); + logger.severe("Unable to create new user account in DB"); return -1; } @@ -840,27 +858,30 @@ private void checkStructure() { try { connection = getConnection(PoolIdentifier.MISC); - statement = connection.prepareStatement("SELECT table_name FROM INFORMATION_SCHEMA.TABLES" - + " WHERE table_schema = ?" - + " AND table_name = ?"); - statement.setString(1, mcMMO.p.getGeneralConfig().getMySQLDatabaseName()); - statement.setString(2, tablePrefix + "users"); + String schemaQuery = this.h2 ? "SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_name = ?" + : "SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = ? AND table_name = ?"; + + statement = connection.prepareStatement(schemaQuery); + + setStatementQuery(statement, "users"); + resultSet = statement.executeQuery(); + if (!resultSet.next()) { createStatement = connection.createStatement(); - createStatement.executeUpdate("CREATE TABLE IF NOT EXISTS `" + tablePrefix + "users` (" - + "`id` int(10) unsigned NOT NULL AUTO_INCREMENT," - + "`user` varchar(40) NOT NULL," - + "`uuid` varchar(36) NULL DEFAULT NULL," - + "`lastlogin` int(32) unsigned NOT NULL," - + "PRIMARY KEY (`id`)," - + "INDEX(`user`(20) ASC)," - + "UNIQUE KEY `uuid` (`uuid`)) DEFAULT CHARSET=" + CHARSET_SQL + " AUTO_INCREMENT=1;"); + String sql = "CREATE TABLE IF NOT EXISTS `" + tablePrefix + "users` (" + + "`id` int AUTO_INCREMENT," + + "`user` varchar(40) NOT NULL," + + "`uuid` varchar(36)," + + "`lastlogin` bigint NOT NULL," + + "PRIMARY KEY (`id`)," + + "INDEX `user_index`(`user`)," + + "UNIQUE(`uuid`))"; + createStatement.executeUpdate(sql); tryClose(createStatement); } tryClose(resultSet); - statement.setString(1, mcMMO.p.getGeneralConfig().getMySQLDatabaseName()); - statement.setString(2, tablePrefix + "huds"); + setStatementQuery(statement, "huds"); resultSet = statement.executeQuery(); if (!resultSet.next()) { createStatement = connection.createStatement(); @@ -873,8 +894,7 @@ private void checkStructure() { tryClose(createStatement); } tryClose(resultSet); - statement.setString(1, mcMMO.p.getGeneralConfig().getMySQLDatabaseName()); - statement.setString(2, tablePrefix + "cooldowns"); + setStatementQuery(statement, "cooldowns"); resultSet = statement.executeQuery(); if (!resultSet.next()) { createStatement = connection.createStatement(); @@ -898,8 +918,7 @@ private void checkStructure() { tryClose(createStatement); } tryClose(resultSet); - statement.setString(1, mcMMO.p.getGeneralConfig().getMySQLDatabaseName()); - statement.setString(2, tablePrefix + "skills"); + setStatementQuery(statement, "skills"); resultSet = statement.executeQuery(); if (!resultSet.next()) { String startingLevel = "'" + mcMMO.p.getAdvancedConfig().getStartingLevel() + "'"; @@ -926,8 +945,7 @@ private void checkStructure() { tryClose(createStatement); } tryClose(resultSet); - statement.setString(1, mcMMO.p.getGeneralConfig().getMySQLDatabaseName()); - statement.setString(2, tablePrefix + "experience"); + setStatementQuery(statement, "experience"); resultSet = statement.executeQuery(); if (!resultSet.next()) { createStatement = connection.createStatement(); @@ -968,7 +986,7 @@ private void checkStructure() { } } - mcMMO.p.getLogger().info("Killing orphans"); + logger.info("Killing orphans"); createStatement = connection.createStatement(); createStatement.executeUpdate("DELETE FROM `" + tablePrefix + "experience` WHERE NOT EXISTS (SELECT * FROM `" + tablePrefix + "users` `u` WHERE `" + tablePrefix + "experience`.`user_id` = `u`.`id`)"); createStatement.executeUpdate("DELETE FROM `" + tablePrefix + "huds` WHERE NOT EXISTS (SELECT * FROM `" + tablePrefix + "users` `u` WHERE `" + tablePrefix + "huds`.`user_id` = `u`.`id`)"); @@ -987,7 +1005,18 @@ private void checkStructure() { } - private Connection getConnection(PoolIdentifier identifier) throws SQLException { + private void setStatementQuery(PreparedStatement statement, String tableName) throws SQLException { + if (!this.h2) { + // Set schema name for MySQL + statement.setString(1, mcMMO.p.getGeneralConfig().getMySQLDatabaseName()); + statement.setString(2, tablePrefix + tableName); + } else { + // For H2, the schema parameter is not needed + statement.setString(1, tablePrefix + tableName); + } + } + + Connection getConnection(PoolIdentifier identifier) throws SQLException { Connection connection = null; switch (identifier) { case LOAD: @@ -1013,7 +1042,7 @@ private Connection getConnection(PoolIdentifier identifier) throws SQLException */ private void checkDatabaseStructure(Connection connection, UpgradeType upgrade) { if (!mcMMO.getUpgradeManager().shouldUpgrade(upgrade)) { - LogUtils.debug(mcMMO.p.getLogger(), "Skipping " + upgrade.name() + " upgrade (unneeded)"); + LogUtils.debug(logger, "Skipping " + upgrade.name() + " upgrade (unneeded)"); return; } @@ -1196,17 +1225,27 @@ private PlayerProfile loadFromResult(String playerName, ResultSet result) throws } private void printErrors(SQLException ex) { - if (debug) { + if (debug || h2) { ex.printStackTrace(); + } else { + for (StackTraceElement element : ex.getStackTrace()) { + logger.severe("Location: " + element.getClassName() + " " + element.getMethodName() + " " + element.getLineNumber()); + } } - StackTraceElement element = ex.getStackTrace()[0]; - mcMMO.p.getLogger().severe("Location: " + element.getClassName() + " " + element.getMethodName() + " " + element.getLineNumber()); - mcMMO.p.getLogger().severe("SQLException: " + ex.getMessage()); - mcMMO.p.getLogger().severe("SQLState: " + ex.getSQLState()); - mcMMO.p.getLogger().severe("VendorError: " + ex.getErrorCode()); + // logger.severe("SQLException: " + ex.getMessage()); + logger.severe("SQLState: " + ex.getSQLState()); + logger.severe("VendorError: " + ex.getErrorCode()); + + // Handling SQLException chain + SQLException nextException = ex.getNextException(); + while (nextException != null) { + logger.severe("Caused by: " + nextException.getMessage()); + nextException = nextException.getNextException(); + } } + public DatabaseType getDatabaseType() { return DatabaseType.SQL; } @@ -1222,7 +1261,7 @@ private void checkNameUniqueness(final Statement statement) { return; } resultSet.close(); - mcMMO.p.getLogger().info("Updating mcMMO MySQL tables to drop name uniqueness..."); + logger.info("Updating mcMMO MySQL tables to drop name uniqueness..."); statement.execute("ALTER TABLE `" + tablePrefix + "users` " + "DROP INDEX `user`," + "ADD INDEX `user` (`user`(20) ASC)"); @@ -1240,7 +1279,7 @@ private void checkUpgradeAddAlchemy(final Statement statement) throws SQLExcepti mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_ALCHEMY); } catch (SQLException ex) { - mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Alchemy..."); + logger.info("Updating mcMMO MySQL tables for Alchemy..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "skills` ADD `alchemy` int(10) NOT NULL DEFAULT '0'"); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "experience` ADD `alchemy` int(10) NOT NULL DEFAULT '0'"); } @@ -1252,7 +1291,7 @@ private void checkUpgradeAddBlastMiningCooldown(final Statement statement) throw mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_BLAST_MINING_COOLDOWN); } catch (SQLException ex) { - mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Blast Mining..."); + logger.info("Updating mcMMO MySQL tables for Blast Mining..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "cooldowns` ADD `blast_mining` int(32) NOT NULL DEFAULT '0'"); } } @@ -1263,7 +1302,7 @@ private void checkUpgradeAddUniqueChimaeraWing(final Statement statement) throws mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_UNIQUE_PLAYER_DATA); } catch (SQLException ex) { - mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Chimaera Wing..."); + logger.info("Updating mcMMO MySQL tables for Chimaera Wing..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "cooldowns` ADD `chimaera_wing` int(32) NOT NULL DEFAULT '0'"); } } @@ -1274,7 +1313,7 @@ private void checkUpgradeAddFishing(final Statement statement) throws SQLExcepti mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_FISHING); } catch (SQLException ex) { - mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Fishing..."); + logger.info("Updating mcMMO MySQL tables for Fishing..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "skills` ADD `fishing` int(10) NOT NULL DEFAULT '0'"); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "experience` ADD `fishing` int(10) NOT NULL DEFAULT '0'"); } @@ -1286,7 +1325,7 @@ private void checkUpgradeAddMobHealthbars(final Statement statement) throws SQLE mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_MOB_HEALTHBARS); } catch (SQLException ex) { - mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for mob healthbars..."); + logger.info("Updating mcMMO MySQL tables for mob healthbars..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "huds` ADD `mobhealthbar` varchar(50) NOT NULL DEFAULT '" + mcMMO.p.getGeneralConfig().getMobHealthbarDefault() + "'"); } } @@ -1297,7 +1336,7 @@ private void checkUpgradeAddScoreboardTips(final Statement statement) throws SQL mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_SCOREBOARD_TIPS); } catch (SQLException ex) { - mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for scoreboard tips..."); + logger.info("Updating mcMMO MySQL tables for scoreboard tips..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "huds` ADD `scoreboardtips` int(10) NOT NULL DEFAULT '0' ;"); } } @@ -1310,7 +1349,7 @@ private void checkUpgradeAddSQLIndexes(final Statement statement) { resultSet.last(); if (resultSet.getRow() != SkillTools.NON_CHILD_SKILLS.size()) { - mcMMO.p.getLogger().info("Indexing tables, this may take a while on larger databases"); + logger.info("Indexing tables, this may take a while on larger databases"); for (PrimarySkillType skill : SkillTools.NON_CHILD_SKILLS) { String skill_name = skill.name().toLowerCase(Locale.ENGLISH); @@ -1351,7 +1390,7 @@ private void checkUpgradeAddUUIDs(final Statement statement) { } if (!column_exists) { - mcMMO.p.getLogger().info("Adding UUIDs to mcMMO MySQL user table..."); + logger.info("Adding UUIDs to mcMMO MySQL user table..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "users` ADD `uuid` varchar(36) NULL DEFAULT NULL"); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "users` ADD UNIQUE INDEX `uuid` (`uuid`) USING BTREE"); @@ -1420,7 +1459,7 @@ private void checkUpgradeDropPartyNames(final Statement statement) { } if (column_exists) { - mcMMO.p.getLogger().info("Removing party name from users table..."); + logger.info("Removing party name from users table..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "users` DROP COLUMN `party`"); } @@ -1454,7 +1493,7 @@ private void checkUpgradeSkillTotal(final Connection connection) throws SQLExcep } if (!column_exists) { - mcMMO.p.getLogger().info("Adding skill total column to skills table..."); + logger.info("Adding skill total column to skills table..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "skills` ADD COLUMN `total` int NOT NULL DEFAULT '0'"); statement.executeUpdate("UPDATE `" + tablePrefix + "skills` SET `total` = (taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy)"); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "skills` ADD INDEX `idx_total` (`total`) USING BTREE"); @@ -1490,7 +1529,7 @@ private void checkUpgradeDropSpout(final Statement statement) { } if (column_exists) { - mcMMO.p.getLogger().info("Removing Spout HUD type from huds table..."); + logger.info("Removing Spout HUD type from huds table..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "huds` DROP COLUMN `hudtype`"); } @@ -1577,7 +1616,7 @@ private void tryClose(AutoCloseable closeable) { @Override public void onDisable() { - LogUtils.debug(mcMMO.p.getLogger(), "Releasing connection pool resource..."); + LogUtils.debug(logger, "Releasing connection pool resource..."); miscPool.close(); loadPool.close(); savePool.close(); @@ -1619,19 +1658,19 @@ The following columns were set to use latin1 historically (now utf8mb4) */ //Alter users table - mcMMO.p.getLogger().info("SQL Converting tables from latin1 to utf8mb4"); + logger.info("SQL Converting tables from latin1 to utf8mb4"); //Update "user" column try { - mcMMO.p.getLogger().info("Updating user column to new encoding"); + logger.info("Updating user column to new encoding"); statement.executeUpdate(getUpdateUserInUsersTableSQLQuery()); //Update "uuid" column - mcMMO.p.getLogger().info("Updating user column to new encoding"); + logger.info("Updating user column to new encoding"); statement.executeUpdate(getUpdateUUIDInUsersTableSQLQuery()); //Update "mobhealthbar" column - mcMMO.p.getLogger().info("Updating mobhealthbar column to new encoding"); + logger.info("Updating mobhealthbar column to new encoding"); statement.executeUpdate(getUpdateMobHealthBarInHudsTableSQLQuery()); mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.SQL_CHARSET_UTF8MB4); diff --git a/src/test/java/com/gmail/nossr50/database/SQLDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/SQLDatabaseManagerTest.java new file mode 100644 index 0000000000..8240ba3e26 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/database/SQLDatabaseManagerTest.java @@ -0,0 +1,145 @@ +package com.gmail.nossr50.database; + +import com.gmail.nossr50.config.AdvancedConfig; +import com.gmail.nossr50.config.GeneralConfig; +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.platform.version.SimpleNumericVersion; +import com.gmail.nossr50.util.upgrade.UpgradeManager; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +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 mockedMcMMO; + SQLDatabaseManager sqlDatabaseManager; + static GeneralConfig generalConfig; + static AdvancedConfig advancedConfig; + static UpgradeManager upgradeManager; + static CompatibilityManager compatibilityManager; + + @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); + + // 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"); + } + + @BeforeEach + void setUp() { + assertNull(sqlDatabaseManager); + sqlDatabaseManager = new SQLDatabaseManager(logger, "org.h2.Driver", true); + } + + @AfterEach + void tearDown() { + sqlDatabaseManager = null; + } + + @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); + } +} \ No newline at end of file From a941a1cc7f943fdf3b21a73cdd43f6eda33bf839 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 27 Dec 2023 22:52:51 -0800 Subject: [PATCH 51/75] kill child.yml and more work on sql unit tests --- Changelog.txt | 5 +- .../com/gmail/nossr50/api/ExperienceAPI.java | 5 +- .../nossr50/commands/skills/SkillCommand.java | 3 +- .../nossr50/database/SQLDatabaseManager.java | 94 ++++++++++++++----- .../nossr50/datatypes/player/McMMOPlayer.java | 5 +- .../datatypes/player/PlayerProfile.java | 12 ++- src/main/java/com/gmail/nossr50/mcMMO.java | 3 - .../nossr50/skills/child/ChildConfig.java | 64 ------------- .../nossr50/skills/child/FamilyTree.java | 54 ----------- .../util/scoreboards/ScoreboardWrapper.java | 3 +- .../gmail/nossr50/util/skills/SkillTools.java | 23 +++-- src/main/resources/child.yml | 16 ---- .../database/SQLDatabaseManagerTest.java | 40 +++++++- 13 files changed, 139 insertions(+), 188 deletions(-) delete mode 100644 src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java delete mode 100644 src/main/java/com/gmail/nossr50/skills/child/FamilyTree.java delete mode 100644 src/main/resources/child.yml diff --git a/Changelog.txt b/Changelog.txt index 310194a2f2..45b3b08fab 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,15 +1,16 @@ Version 2.2.000 + TODO: More SQL unit tests + TODO: Test mysql/mariadb changes TODO: Trickshot: locale, multiple bounces, does not hurt yourself or allies, reduced damage per bounce? TODO: Add metadata cleanup unit tests TODO: Cleanup new arrow metadatas - TODO: SQL DB update - TODO: SQL unit tests TODO: com/gmail/nossr50/database/FlatFileDatabaseManager.java:109 reporting data entries that need correction on each launch TODO: Add Xbows/Tridents to salvage/repair TODO: Add unit test for combat XP values TODO: Add unit test to determine crossbow or bow skill TODO: Add unit test for trident xp processing TODO: Add missing entries to changelog + child.yml is gone now, its better this way 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 (API) 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 Treasure drop rate from Shake, Fishing, Hylian, and Excavation now benefit from the Luck perk diff --git a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java index f18cd18ca1..37b895db92 100644 --- a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java +++ b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java @@ -9,7 +9,6 @@ import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.skills.child.FamilyTree; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.SkillTools; @@ -706,7 +705,7 @@ public static void addLevelOffline(String playerName, String skillType, int leve PrimarySkillType skill = getSkillType(skillType); if (SkillTools.isChildSkill(skill)) { - Set parentSkills = FamilyTree.getParents(skill); + var parentSkills = mcMMO.p.getSkillTools().getChildSkillParents(skill); for (PrimarySkillType parentSkill : parentSkills) { profile.addLevels(parentSkill, (levels / parentSkills.size())); @@ -737,7 +736,7 @@ public static void addLevelOffline(UUID uuid, String skillType, int levels) { PrimarySkillType skill = getSkillType(skillType); if (SkillTools.isChildSkill(skill)) { - Set parentSkills = FamilyTree.getParents(skill); + var parentSkills = mcMMO.p.getSkillTools().getChildSkillParents(skill); for (PrimarySkillType parentSkill : parentSkills) { profile.addLevels(parentSkill, (levels / parentSkills.size())); diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java index 2f5a9c3cac..fac6a99eaf 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java @@ -5,7 +5,6 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.skills.child.FamilyTree; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.NotificationManager; @@ -171,7 +170,7 @@ private void sendSkillCommandHeader(Player player, McMMOPlayer mcMMOPlayer, int */ - Set parents = FamilyTree.getParents(skill); + var parents = mcMMO.p.getSkillTools().getChildSkillParents(skill); //TODO: Add JSON here /*player.sendMessage(parent.getName() + " - " + LocaleLoader.getString("Effects.Level.Overhaul", mcMMOPlayer.getSkillLevel(parent), mcMMOPlayer.getSkillXpLevel(parent), mcMMOPlayer.getXpToLevel(parent)))*/ diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index a2e85bf263..69dffb644f 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -33,6 +33,7 @@ public final class SQLDatabaseManager implements DatabaseManager { public static final String USER_VARCHAR = "VARCHAR(40)"; public static final int CHILD_SKILLS_SIZE = 2; public static final String LEGACY_DRIVER_PATH = "com.mysql.jdbc.Driver"; + public static final int MAGIC_NUMBER = 44; private final String tablePrefix = mcMMO.p.getGeneralConfig().getMySQLTablePrefix(); private final Map cachedUserIDs = new HashMap<>(); @@ -128,6 +129,7 @@ public final class SQLDatabaseManager implements DatabaseManager { loadPool = new DataSource(poolProperties); checkStructure(); + } @NotNull @@ -151,6 +153,7 @@ private static String getConnectionString(boolean h2) { return connectionString; } + // TODO: unit tests public int purgePowerlessUsers() { massUpdateLock.lock(); logger.info("Purging powerless users..."); @@ -167,7 +170,7 @@ public int purgePowerlessUsers() { + "taming = 0 AND mining = 0 AND woodcutting = 0 AND repair = 0 " + "AND unarmed = 0 AND herbalism = 0 AND excavation = 0 AND " + "archery = 0 AND swords = 0 AND axes = 0 AND acrobatics = 0 " - + "AND fishing = 0 AND alchemy = 0;"); + + "AND fishing = 0 AND alchemy = 0 AND crossbows = 0 AND tridents = 0;"); statement.executeUpdate("DELETE FROM `" + tablePrefix + "experience` WHERE NOT EXISTS (SELECT * FROM `" + tablePrefix + "skills` `s` WHERE `" + tablePrefix + "experience`.`user_id` = `s`.`user_id`)"); statement.executeUpdate("DELETE FROM `" + tablePrefix + "huds` WHERE NOT EXISTS (SELECT * FROM `" + tablePrefix + "skills` `s` WHERE `" + tablePrefix + "huds`.`user_id` = `s`.`user_id`)"); @@ -564,15 +567,20 @@ private int newUser(Connection connection, String playerName, UUID uuid) { try { statement = connection.prepareStatement( "UPDATE `" + tablePrefix + "users` " - + "SET user = ? " - + "WHERE user = ?"); + + "SET \"USER\" = ? " + + "WHERE \"USER\" = ?"); statement.setString(1, "_INVALID_OLD_USERNAME_"); statement.setString(2, playerName); statement.executeUpdate(); statement.close(); - statement = connection.prepareStatement("INSERT INTO " + tablePrefix + "users (user, uuid, lastlogin) VALUES (?, ?, UNIX_TIMESTAMP())", Statement.RETURN_GENERATED_KEYS); + + long currentTimeMillis = System.currentTimeMillis(); + + String sql = "INSERT INTO " + tablePrefix + "users (`user`, uuid, lastlogin) VALUES (?, ?, ?)"; + statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); statement.setString(1, playerName); statement.setString(2, uuid != null ? uuid.toString() : null); + statement.setLong(3, currentTimeMillis); statement.executeUpdate(); resultSet = statement.getGeneratedKeys(); @@ -640,17 +648,18 @@ private PlayerProfile loadPlayerFromDB(@Nullable UUID uuid, @Nullable String pla writeMissingRows(connection, id); statement = connection.prepareStatement( - "SELECT " - + "s.taming, s.mining, s.repair, s.woodcutting, s.unarmed, s.herbalism, s.excavation, s.archery, s.swords, s.axes, s.acrobatics, s.fishing, s.alchemy, " - + "e.taming, e.mining, e.repair, e.woodcutting, e.unarmed, e.herbalism, e.excavation, e.archery, e.swords, e.axes, e.acrobatics, e.fishing, e.alchemy, " - + "c.taming, c.mining, c.repair, c.woodcutting, c.unarmed, c.herbalism, c.excavation, c.archery, c.swords, c.axes, c.acrobatics, c.blast_mining, c.chimaera_wing, " - + "h.mobhealthbar, h.scoreboardtips, u.uuid, u.user " - + "FROM " + tablePrefix + "users u " - + "JOIN " + tablePrefix + "skills s ON (u.id = s.user_id) " - + "JOIN " + tablePrefix + "experience e ON (u.id = e.user_id) " - + "JOIN " + tablePrefix + "cooldowns c ON (u.id = c.user_id) " - + "JOIN " + tablePrefix + "huds h ON (u.id = h.user_id) " - + "WHERE u.id = ?"); + "SELECT " + + "S.TAMING, S.MINING, S.REPAIR, S.WOODCUTTING, S.UNARMED, S.HERBALISM, S.EXCAVATION, S.ARCHERY, S.SWORDS, S.AXES, S.ACROBATICS, S.FISHING, S.ALCHEMY, S.CROSSBOWS, S.TRIDENTS, " + + "E.TAMING, E.MINING, E.REPAIR, E.WOODCUTTING, E.UNARMED, E.HERBALISM, E.EXCAVATION, E.ARCHERY, E.SWORDS, E.AXES, E.ACROBATICS, E.FISHING, E.ALCHEMY, S.CROSSBOWS, S.TRIDENTS, " + + "C.TAMING, C.MINING, C.REPAIR, C.WOODCUTTING, C.UNARMED, C.HERBALISM, C.EXCAVATION, C.ARCHERY, C.SWORDS, C.AXES, C.ACROBATICS, C.BLAST_MINING, C.CHIMAERA_WING, C.CROSSBOWS, C.TRIDENTS, " + + "H.MOBHEALTHBAR, H.SCOREBOARDTIPS, U.UUID, U.\"USER\" " + + "FROM " + tablePrefix + "USERS U " + + "JOIN " + tablePrefix + "SKILLS S ON U.ID = S.USER_ID " + + "JOIN " + tablePrefix + "EXPERIENCE E ON U.ID = E.USER_ID " + + "JOIN " + tablePrefix + "COOLDOWNS C ON U.ID = C.USER_ID " + + "JOIN " + tablePrefix + "HUDS H ON U.ID = H.USER_ID " + + "WHERE U.ID = ?" + ); statement.setInt(1, id); resultSet = statement.executeQuery(); @@ -658,7 +667,7 @@ private PlayerProfile loadPlayerFromDB(@Nullable UUID uuid, @Nullable String pla if (resultSet.next()) { try { PlayerProfile profile = loadFromResult(playerName, resultSet); - String name = resultSet.getString(42); // TODO: Magic Number, make sure it stays updated + String name = resultSet.getString(MAGIC_NUMBER); // TODO: Magic Number, make sure it stays updated resultSet.close(); statement.close(); @@ -668,15 +677,15 @@ private PlayerProfile loadPlayerFromDB(@Nullable UUID uuid, @Nullable String pla && uuid != null) { statement = connection.prepareStatement( "UPDATE `" + tablePrefix + "users` " - + "SET user = ? " - + "WHERE user = ?"); + + "SET \"USER\" = ? " + + "WHERE \"USER\" = ?"); statement.setString(1, "_INVALID_OLD_USERNAME_"); statement.setString(2, name); statement.executeUpdate(); statement.close(); statement = connection.prepareStatement( "UPDATE `" + tablePrefix + "users` " - + "SET user = ?, uuid = ? " + + "SET \"USER\" = ?, uuid = ? " + "WHERE id = ?"); statement.setString(1, playerName); statement.setString(2, uuid.toString()); @@ -913,6 +922,8 @@ private void checkStructure() { + "`acrobatics` int(32) unsigned NOT NULL DEFAULT '0'," + "`blast_mining` int(32) unsigned NOT NULL DEFAULT '0'," + "`chimaera_wing` int(32) unsigned NOT NULL DEFAULT '0'," + + "`crossbows` int(32) unsigned NOT NULL DEFAULT '0'," + + "`tridents` int(32) unsigned NOT NULL DEFAULT '0'," + "PRIMARY KEY (`user_id`)) " + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); tryClose(createStatement); @@ -939,6 +950,8 @@ private void checkStructure() { + "`acrobatics` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," + "`fishing` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," + "`alchemy` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," + + "`crossbows` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," + + "`tridents` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," + "`total` int(10) unsigned NOT NULL DEFAULT "+totalLevel+"," + "PRIMARY KEY (`user_id`)) " + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); @@ -964,6 +977,8 @@ private void checkStructure() { + "`acrobatics` int(10) unsigned NOT NULL DEFAULT '0'," + "`fishing` int(10) unsigned NOT NULL DEFAULT '0'," + "`alchemy` int(10) unsigned NOT NULL DEFAULT '0'," + + "`crossbows` int(10) unsigned NOT NULL DEFAULT '0'," + + "`tridents` int(10) unsigned NOT NULL DEFAULT '0'," + "PRIMARY KEY (`user_id`)) " + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); tryClose(createStatement); @@ -986,7 +1001,8 @@ private void checkStructure() { } } - logger.info("Killing orphans"); + // TODO: refactor + LogUtils.debug(logger, "Killing orphans"); createStatement = connection.createStatement(); createStatement.executeUpdate("DELETE FROM `" + tablePrefix + "experience` WHERE NOT EXISTS (SELECT * FROM `" + tablePrefix + "users` `u` WHERE `" + tablePrefix + "experience`.`user_id` = `u`.`id`)"); createStatement.executeUpdate("DELETE FROM `" + tablePrefix + "huds` WHERE NOT EXISTS (SELECT * FROM `" + tablePrefix + "users` `u` WHERE `" + tablePrefix + "huds`.`user_id` = `u`.`id`)"); @@ -1016,7 +1032,7 @@ private void setStatementQuery(PreparedStatement statement, String tableName) th } } - Connection getConnection(PoolIdentifier identifier) throws SQLException { + protected Connection getConnection(PoolIdentifier identifier) throws SQLException { Connection connection = null; switch (identifier) { case LOAD: @@ -1161,9 +1177,9 @@ private PlayerProfile loadFromResult(String playerName, ResultSet result) throws final int OFFSET_SKILLS = 0; // TODO update these numbers when the query // changes (a new skill is added) - final int OFFSET_XP = 13; - final int OFFSET_DATS = 26; - final int OFFSET_OTHER = 39; + final int OFFSET_XP = 15; + final int OFFSET_DATS = 28; + final int OFFSET_OTHER = 41; skills.put(PrimarySkillType.TAMING, result.getInt(OFFSET_SKILLS + 1)); skills.put(PrimarySkillType.MINING, result.getInt(OFFSET_SKILLS + 2)); @@ -1178,6 +1194,8 @@ private PlayerProfile loadFromResult(String playerName, ResultSet result) throws skills.put(PrimarySkillType.ACROBATICS, result.getInt(OFFSET_SKILLS + 11)); skills.put(PrimarySkillType.FISHING, result.getInt(OFFSET_SKILLS + 12)); skills.put(PrimarySkillType.ALCHEMY, result.getInt(OFFSET_SKILLS + 13)); + skills.put(PrimarySkillType.CROSSBOWS, result.getInt(OFFSET_SKILLS + 14)); + skills.put(PrimarySkillType.TRIDENTS, result.getInt(OFFSET_SKILLS + 15)); skillsXp.put(PrimarySkillType.TAMING, result.getFloat(OFFSET_XP + 1)); skillsXp.put(PrimarySkillType.MINING, result.getFloat(OFFSET_XP + 2)); @@ -1192,6 +1210,8 @@ private PlayerProfile loadFromResult(String playerName, ResultSet result) throws skillsXp.put(PrimarySkillType.ACROBATICS, result.getFloat(OFFSET_XP + 11)); skillsXp.put(PrimarySkillType.FISHING, result.getFloat(OFFSET_XP + 12)); skillsXp.put(PrimarySkillType.ALCHEMY, result.getFloat(OFFSET_XP + 13)); + skillsXp.put(PrimarySkillType.ALCHEMY, result.getFloat(OFFSET_XP + 14)); + skillsXp.put(PrimarySkillType.ALCHEMY, result.getFloat(OFFSET_XP + 15)); // Taming - Unused - result.getInt(OFFSET_DATS + 1) skillsDATS.put(SuperAbilityType.SUPER_BREAKER, result.getInt(OFFSET_DATS + 2)); @@ -1206,6 +1226,8 @@ private PlayerProfile loadFromResult(String playerName, ResultSet result) throws // Acrobatics - Unused - result.getInt(OFFSET_DATS + 11) skillsDATS.put(SuperAbilityType.BLAST_MINING, result.getInt(OFFSET_DATS + 12)); uniqueData.put(UniqueDataType.CHIMAERA_WING_DATS, result.getInt(OFFSET_DATS + 13)); + skillsDATS.put(SuperAbilityType.SUPER_SHOTGUN, result.getInt(OFFSET_DATS + 14)); + skillsDATS.put(SuperAbilityType.TRIDENTS_SUPER_ABILITY, result.getInt(OFFSET_DATS + 15)); try { scoreboardTipsShown = result.getInt(OFFSET_OTHER + 2); @@ -1709,4 +1731,28 @@ private String getUpdateMobHealthBarInHudsTableSQLQuery() { " CHARACTER SET utf8mb4\n" + " COLLATE utf8mb4_unicode_ci;"; } + + public void printAllTablesWithColumns(Connection connection) { + try { + DatabaseMetaData metaData = connection.getMetaData(); + String[] types = {"TABLE"}; + ResultSet tables = metaData.getTables(null, null, "%", types); + + while (tables.next()) { + String tableName = tables.getString("TABLE_NAME"); + System.out.println("Table: " + tableName); + + ResultSet columns = metaData.getColumns(null, null, tableName, "%"); + while (columns.next()) { + String columnName = columns.getString("COLUMN_NAME"); + String columnType = columns.getString("TYPE_NAME"); + System.out.println(" Column: " + columnName + " Type: " + columnType); + } + columns.close(); + } + tables.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } } diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index 59c918a1e9..a89e9bab02 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -30,7 +30,6 @@ import com.gmail.nossr50.skills.alchemy.AlchemyManager; import com.gmail.nossr50.skills.archery.ArcheryManager; import com.gmail.nossr50.skills.axes.AxesManager; -import com.gmail.nossr50.skills.child.FamilyTree; import com.gmail.nossr50.skills.crossbows.CrossbowsManager; import com.gmail.nossr50.skills.excavation.ExcavationManager; import com.gmail.nossr50.skills.fishing.FishingManager; @@ -618,7 +617,7 @@ public void beginXpGain(PrimarySkillType skill, float xp, XPGainReason xpGainRea } if (SkillTools.isChildSkill(skill)) { - Set parentSkills = FamilyTree.getParents(skill); + var parentSkills = mcMMO.p.getSkillTools().getChildSkillParents(skill); float splitXp = xp / parentSkills.size(); for (PrimarySkillType parentSkill : parentSkills) { @@ -675,7 +674,7 @@ public void applyXpGain(PrimarySkillType primarySkillType, float xp, XPGainReaso xp = mcMMOPlayerPreXpGainEvent.getXpGained(); if (SkillTools.isChildSkill(primarySkillType)) { - Set parentSkills = FamilyTree.getParents(primarySkillType); + var parentSkills = mcMMO.p.getSkillTools().getChildSkillParents(primarySkillType); for (PrimarySkillType parentSkill : parentSkills) { applyXpGain(parentSkill, xp / parentSkills.size(), xpGainReason, xpGainSource); diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java index 65ebf4c856..74c15a27df 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java @@ -7,9 +7,9 @@ import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.player.PlayerProfileSaveTask; -import com.gmail.nossr50.skills.child.FamilyTree; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.SkillTools; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -363,7 +363,7 @@ public void addXp(PrimarySkillType skill, float xp) { markProfileDirty(); if (SkillTools.isChildSkill(skill)) { - Set parentSkills = FamilyTree.getParents(skill); + var parentSkills = mcMMO.p.getSkillTools().getChildSkillParents(skill); float dividedXP = (xp / parentSkills.size()); for (PrimarySkillType parentSkill : parentSkills) { @@ -431,8 +431,12 @@ public int getXpToLevel(PrimarySkillType primarySkillType) { return mcMMO.getFormulaManager().getXPtoNextLevel(level, formulaType); } - private int getChildSkillLevel(PrimarySkillType primarySkillType) { - Set parents = FamilyTree.getParents(primarySkillType); + private int getChildSkillLevel(@NotNull PrimarySkillType primarySkillType) throws IllegalArgumentException { + if (!SkillTools.isChildSkill(primarySkillType)) { + throw new IllegalArgumentException(primarySkillType + " is not a child skill!"); + } + + ImmutableList parents = mcMMO.p.getSkillTools().getChildSkillParents(primarySkillType); int sum = 0; for (PrimarySkillType parent : parents) { diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index 0b06663bc5..2cacfa3c70 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -30,7 +30,6 @@ import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask; import com.gmail.nossr50.runnables.player.PowerLevelUpdatingTask; import com.gmail.nossr50.skills.alchemy.Alchemy; -import com.gmail.nossr50.skills.child.ChildConfig; import com.gmail.nossr50.skills.repair.repairables.Repairable; import com.gmail.nossr50.skills.repair.repairables.RepairableManager; import com.gmail.nossr50.skills.repair.repairables.SimpleRepairableManager; @@ -563,8 +562,6 @@ private void loadConfigFiles() { SoundConfig.getInstance(); RankConfig.getInstance(); - new ChildConfig(); - List repairables = new ArrayList<>(); if (generalConfig.getToolModsEnabled()) { diff --git a/src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java b/src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java deleted file mode 100644 index 0e200bafaf..0000000000 --- a/src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.gmail.nossr50.skills.child; - -import com.gmail.nossr50.config.BukkitConfig; -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.LogUtils; -import com.gmail.nossr50.util.text.StringUtils; -import org.bukkit.configuration.file.YamlConfiguration; - -import java.util.EnumSet; -import java.util.Locale; - -public class ChildConfig extends BukkitConfig { - public ChildConfig() { - super("child.yml"); - loadKeys(); - } - - @Override - protected void loadKeys() { - config.setDefaults(YamlConfiguration.loadConfiguration(mcMMO.p.getResourceAsReader("child.yml"))); - - FamilyTree.clearRegistrations(); // when reloading, need to clear statics - - for (PrimarySkillType skill : mcMMO.p.getSkillTools().CHILD_SKILLS) { - LogUtils.debug(mcMMO.p.getLogger(), "Finding parents of " + skill.name()); - - EnumSet parentSkills = EnumSet.noneOf(PrimarySkillType.class); - boolean useDefaults = false; // If we had an error we back out and use defaults - - for (String name : config.getStringList(StringUtils.getCapitalized(skill.name()))) { - try { - PrimarySkillType parentSkill = PrimarySkillType.valueOf(name.toUpperCase(Locale.ENGLISH)); - FamilyTree.enforceNotChildSkill(parentSkill); - parentSkills.add(parentSkill); - } - catch (IllegalArgumentException ex) { - mcMMO.p.getLogger().warning(name + " is not a valid skill type, or is a child skill!"); - useDefaults = true; - break; - } - } - - if (useDefaults) { - parentSkills.clear(); - for (String name : config.getDefaults().getStringList(StringUtils.getCapitalized(skill.name()))) { - /* We do less checks in here because it's from inside our jar. - * If they're dedicated enough to have modified it, they can have the errors it may produce. - * Alternatively, this can be used to allow child skills to be parent skills, provided there are no circular dependencies this is an advanced sort of configuration. - */ - parentSkills.add(PrimarySkillType.valueOf(name.toUpperCase(Locale.ENGLISH))); - } - } - - // Register them - for (PrimarySkillType parentSkill : parentSkills) { - LogUtils.debug(mcMMO.p.getLogger(), "Registering " + parentSkill.name() + " as parent of " + skill.name()); - FamilyTree.registerParent(skill, parentSkill); - } - } - - FamilyTree.closeRegistration(); - } -} diff --git a/src/main/java/com/gmail/nossr50/skills/child/FamilyTree.java b/src/main/java/com/gmail/nossr50/skills/child/FamilyTree.java deleted file mode 100644 index 0be5336000..0000000000 --- a/src/main/java/com/gmail/nossr50/skills/child/FamilyTree.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.gmail.nossr50.skills.child; - -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -import com.gmail.nossr50.util.skills.SkillTools; - -import java.util.Collections; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Set; - -public class FamilyTree { - private static final HashMap> tree = new HashMap<>(); - - public static Set getParents(PrimarySkillType childSkill) { - enforceChildSkill(childSkill); - - // We do not check if we have the child skill in question, as not having it would mean we did something wrong, and an NPE is desired. - return tree.get(childSkill); - } - - protected static void registerParent(PrimarySkillType childSkill, PrimarySkillType parentSkill) { - enforceChildSkill(childSkill); - enforceNotChildSkill(parentSkill); - - if (!tree.containsKey(childSkill)) { - tree.put(childSkill, EnumSet.noneOf(PrimarySkillType.class)); - } - - tree.get(childSkill).add(parentSkill); - } - - protected static void closeRegistration() { - for (PrimarySkillType childSkill : tree.keySet()) { - Set immutableSet = Collections.unmodifiableSet(tree.get(childSkill)); - tree.put(childSkill, immutableSet); - } - } - - protected static void clearRegistrations() { - tree.clear(); - } - - protected static void enforceChildSkill(PrimarySkillType skill) { - if (!SkillTools.isChildSkill(skill)) { - throw new IllegalArgumentException(skill.name() + " is not a child skill!"); - } - } - - protected static void enforceNotChildSkill(PrimarySkillType skill) { - if (SkillTools.isChildSkill(skill)) { - throw new IllegalArgumentException(skill.name() + " is a child skill!"); - } - } -} diff --git a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java index 1237ce086c..4d2d515602 100644 --- a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java +++ b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java @@ -11,7 +11,6 @@ import com.gmail.nossr50.events.scoreboard.ScoreboardObjectiveEventReason; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.skills.child.FamilyTree; import com.gmail.nossr50.util.LogUtils; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.player.NotificationManager; @@ -495,7 +494,7 @@ private void updateSidebar() { sidebarObjective.getScore(ScoreboardManager.LABEL_REMAINING_XP).setScore(mcMMOPlayer.getXpToLevel(targetSkill) - currentXP); } else { - for (PrimarySkillType parentSkill : FamilyTree.getParents(targetSkill)) { + for (PrimarySkillType parentSkill : mcMMO.p.getSkillTools().getChildSkillParents(targetSkill)) { sidebarObjective.getScore(ScoreboardManager.skillLabels.get(parentSkill)).setScore(mcMMOPlayer.getSkillLevel(parentSkill)); } } diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java index 6329b3934e..985f93bce6 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java @@ -30,6 +30,8 @@ public class SkillTools { public final @NotNull ImmutableSet EXACT_SUBSKILL_NAMES; public final @NotNull ImmutableList CHILD_SKILLS; public final static @NotNull ImmutableList NON_CHILD_SKILLS; + public final static @NotNull ImmutableList SALVAGE_PARENTS; + public final static @NotNull ImmutableList SMELTING_PARENTS; public final @NotNull ImmutableList COMBAT_SKILLS; public final @NotNull ImmutableList GATHERING_SKILLS; public final @NotNull ImmutableList MISC_SKILLS; @@ -50,6 +52,8 @@ public class SkillTools { } NON_CHILD_SKILLS = ImmutableList.copyOf(tempNonChildSkills); + SALVAGE_PARENTS = ImmutableList.of(PrimarySkillType.REPAIR, PrimarySkillType.FISHING); + SMELTING_PARENTS = ImmutableList.of(PrimarySkillType.MINING, PrimarySkillType.REPAIR); } public SkillTools(@NotNull mcMMO pluginRef) throws InvalidSkillException { @@ -140,18 +144,13 @@ public SkillTools(@NotNull mcMMO pluginRef) throws InvalidSkillException { */ List childSkills = new ArrayList<>(); -// List nonChildSkills = new ArrayList<>(); for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { if (isChildSkill(primarySkillType)) childSkills.add(primarySkillType); -// } { -// nonChildSkills.add(primarySkillType); -// } } CHILD_SKILLS = ImmutableList.copyOf(childSkills); -// NON_CHILD_SKILLS = ImmutableList.copyOf(nonChildSkills); /* * Build categorized skill lists @@ -329,7 +328,6 @@ public ToolType getPrimarySkillToolType(PrimarySkillType primarySkillType) { } public Set getSubSkills(PrimarySkillType primarySkillType) { - //TODO: Cache this! return primarySkillChildrenMap.get(primarySkillType); } @@ -429,4 +427,17 @@ public boolean superAbilityPermissionCheck(SuperAbilityType superAbilityType, Pl public @NotNull ImmutableList getMiscSkills() { return MISC_SKILLS; } + + public @NotNull ImmutableList getChildSkillParents(PrimarySkillType childSkill) + throws IllegalArgumentException { + switch (childSkill) { + case SALVAGE -> { + return SALVAGE_PARENTS; + } + case SMELTING -> { + return SMELTING_PARENTS; + } + default -> throw new IllegalArgumentException("Skill " + childSkill + " is not a child skill"); + } + } } diff --git a/src/main/resources/child.yml b/src/main/resources/child.yml deleted file mode 100644 index 685a6ce714..0000000000 --- a/src/main/resources/child.yml +++ /dev/null @@ -1,16 +0,0 @@ -# -# mcMMO child skill configuration -# Last updated on ${project.version}-b${BUILD_NUMBER} -# -# You do not need to modify this file except to change parents of child skills -# -# If you wish a child skill to be the parent of another child skill, you must also make your changes to the child.yml within the jar -# WARNING: THIS IS NOT SUPPORTED, IF YOU DO SO YOU ARE RESPONSIBLE FOR THE ISSUES THAT MAY ARISE. That said, watch out for circular dependencies, those are bad. -# -##### -Salvage: - - Fishing - - Repair -Smelting: - - Mining - - Repair \ No newline at end of file diff --git a/src/test/java/com/gmail/nossr50/database/SQLDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/SQLDatabaseManagerTest.java index 8240ba3e26..d70332321a 100644 --- a/src/test/java/com/gmail/nossr50/database/SQLDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/SQLDatabaseManagerTest.java @@ -2,22 +2,27 @@ import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.config.GeneralConfig; +import com.gmail.nossr50.datatypes.MobHealthbarType; +import com.gmail.nossr50.datatypes.database.UpgradeType; +import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.LogUtils; import com.gmail.nossr50.util.compat.CompatibilityManager; import com.gmail.nossr50.util.platform.MinecraftGameVersion; import com.gmail.nossr50.util.platform.version.SimpleNumericVersion; +import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.util.upgrade.UpgradeManager; import org.bukkit.Material; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.*; import org.mockito.MockedStatic; import org.mockito.Mockito; +import java.sql.*; +import java.util.Locale; +import java.util.Set; import java.util.logging.Logger; import static org.junit.jupiter.api.Assertions.*; @@ -32,6 +37,7 @@ class SQLDatabaseManagerTest { static AdvancedConfig advancedConfig; static UpgradeManager upgradeManager; static CompatibilityManager compatibilityManager; + static SkillTools skillTools; @BeforeAll static void setUpAll() { @@ -50,6 +56,10 @@ static void setUpAll() { // 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); @@ -107,6 +117,9 @@ private static void mockGeneralConfig() { // host when(mcMMO.p.getGeneralConfig().getMySQLServerName()).thenReturn("localhost"); + + // unused mob health bar thingy + when(mcMMO.p.getGeneralConfig().getMobHealthbarDefault()).thenReturn(MobHealthbarType.HEARTS); } @BeforeEach @@ -120,6 +133,11 @@ void tearDown() { sqlDatabaseManager = null; } + @AfterAll + static void tearDownAll() { + mockedMcMMO.close(); + } + @Test void testGetConnectionMisc() throws Exception { assertNotNull(sqlDatabaseManager.getConnection(SQLDatabaseManager.PoolIdentifier.MISC)); @@ -142,4 +160,16 @@ void testNewUser() { when(player.getName()).thenReturn("nossr50"); sqlDatabaseManager.newUser(player); } -} \ No newline at end of file + + @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)); + } + } +} From 3fbb4827ca8511043871949b33dd182a5042e10a Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 3 Jan 2024 00:19:57 -0800 Subject: [PATCH 52/75] Update SQL schema when missing columns --- .../nossr50/database/SQLDatabaseManager.java | 97 +++++++++++++++---- .../skills/crossbows/CrossbowsManager.java | 35 ++++++- .../gmail/nossr50/util/MetadataConstants.java | 1 + .../com/gmail/nossr50/util/Permissions.java | 3 + 4 files changed, 110 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index 69dffb644f..deae24ee9a 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -567,8 +567,8 @@ private int newUser(Connection connection, String playerName, UUID uuid) { try { statement = connection.prepareStatement( "UPDATE `" + tablePrefix + "users` " - + "SET \"USER\" = ? " - + "WHERE \"USER\" = ?"); + + "SET `USER` = ? " + + "WHERE `USER` = ?"); statement.setString(1, "_INVALID_OLD_USERNAME_"); statement.setString(2, playerName); statement.executeUpdate(); @@ -650,9 +650,9 @@ private PlayerProfile loadPlayerFromDB(@Nullable UUID uuid, @Nullable String pla statement = connection.prepareStatement( "SELECT " + "S.TAMING, S.MINING, S.REPAIR, S.WOODCUTTING, S.UNARMED, S.HERBALISM, S.EXCAVATION, S.ARCHERY, S.SWORDS, S.AXES, S.ACROBATICS, S.FISHING, S.ALCHEMY, S.CROSSBOWS, S.TRIDENTS, " + - "E.TAMING, E.MINING, E.REPAIR, E.WOODCUTTING, E.UNARMED, E.HERBALISM, E.EXCAVATION, E.ARCHERY, E.SWORDS, E.AXES, E.ACROBATICS, E.FISHING, E.ALCHEMY, S.CROSSBOWS, S.TRIDENTS, " + + "E.TAMING, E.MINING, E.REPAIR, E.WOODCUTTING, E.UNARMED, E.HERBALISM, E.EXCAVATION, E.ARCHERY, E.SWORDS, E.AXES, E.ACROBATICS, E.FISHING, E.ALCHEMY, E.CROSSBOWS, E.TRIDENTS, " + "C.TAMING, C.MINING, C.REPAIR, C.WOODCUTTING, C.UNARMED, C.HERBALISM, C.EXCAVATION, C.ARCHERY, C.SWORDS, C.AXES, C.ACROBATICS, C.BLAST_MINING, C.CHIMAERA_WING, C.CROSSBOWS, C.TRIDENTS, " + - "H.MOBHEALTHBAR, H.SCOREBOARDTIPS, U.UUID, U.\"USER\" " + + "H.MOBHEALTHBAR, H.SCOREBOARDTIPS, U.UUID, U.`USER` " + "FROM " + tablePrefix + "USERS U " + "JOIN " + tablePrefix + "SKILLS S ON U.ID = S.USER_ID " + "JOIN " + tablePrefix + "EXPERIENCE E ON U.ID = E.USER_ID " + @@ -664,6 +664,7 @@ private PlayerProfile loadPlayerFromDB(@Nullable UUID uuid, @Nullable String pla resultSet = statement.executeQuery(); + if (resultSet.next()) { try { PlayerProfile profile = loadFromResult(playerName, resultSet); @@ -677,15 +678,15 @@ private PlayerProfile loadPlayerFromDB(@Nullable UUID uuid, @Nullable String pla && uuid != null) { statement = connection.prepareStatement( "UPDATE `" + tablePrefix + "users` " - + "SET \"USER\" = ? " - + "WHERE \"USER\" = ?"); + + "SET `USER` = ? " + + "WHERE `USER` = ?"); statement.setString(1, "_INVALID_OLD_USERNAME_"); statement.setString(2, name); statement.executeUpdate(); statement.close(); statement = connection.prepareStatement( "UPDATE `" + tablePrefix + "users` " - + "SET \"USER\" = ?, uuid = ? " + + "SET `USER` = ?, uuid = ? " + "WHERE id = ?"); statement.setString(1, playerName); statement.setString(2, uuid.toString()); @@ -859,7 +860,6 @@ public List getStoredUsers() { * Checks that the database structure is present and correct */ private void checkStructure() { - PreparedStatement statement = null; Statement createStatement = null; ResultSet resultSet = null; @@ -1019,6 +1019,68 @@ private void checkStructure() { tryClose(connection); } + updateStructure("SKILLS", "CROSSBOWS", String.valueOf(32)); + updateStructure("SKILLS", "TRIDENTS", String.valueOf(32)); + + updateStructure("EXPERIENCE", "CROSSBOWS", String.valueOf(10)); + updateStructure("EXPERIENCE", "TRIDENTS", String.valueOf(10)); + + updateStructure("COOLDOWNS", "CROSSBOWS", String.valueOf(10)); + updateStructure("COOLDOWNS", "TRIDENTS", String.valueOf(10)); + } + + private void updateStructure(String tableName, String columnName, String columnSize) { + boolean columnExists = false; + DatabaseMetaData metaData = null; + + try(Connection connection = getConnection(PoolIdentifier.MISC)) { + metaData = connection.getMetaData(); + ResultSet rs = null; + + try { + // Replace "YOUR_SCHEMA" with your database schema name if necessary, or use null to not filter by schema. + // Replace "YOUR_TABLE" with the actual table name, and "YOUR_COLUMN" with the column you're checking for. + rs = metaData.getColumns(null, null, tablePrefix + tableName, columnName); + + if (rs.next()) { + // If the result set is not empty, the column exists + columnExists = true; + } + } catch (SQLException e) { + e.printStackTrace(); // Handle the exception appropriately + } finally { + if (rs != null) { + try { + rs.close(); + } catch (SQLException e) { + e.printStackTrace(); // Handle the exception appropriately + } + } + } + + if (!columnExists) { + // Alter the table to add the column + Statement createStatement = null; + try { + createStatement = connection.createStatement(); + String startingLevel = "'" + mcMMO.p.getAdvancedConfig().getStartingLevel() + "'"; + createStatement.executeUpdate("ALTER TABLE `" + tablePrefix + tableName + "` " + + "ADD COLUMN `" + columnName + "` int(" + columnSize + ") unsigned NOT NULL DEFAULT " + startingLevel); + } catch (SQLException e) { + e.printStackTrace(); // Handle the exception appropriately + } finally { + if (createStatement != null) { + try { + createStatement.close(); + } catch (SQLException e) { + e.printStackTrace(); // Handle the exception appropriately + } + } + } + } + } catch (SQLException e) { + throw new RuntimeException(e); + } } private void setStatementQuery(PreparedStatement statement, String tableName) throws SQLException { @@ -1032,19 +1094,12 @@ private void setStatementQuery(PreparedStatement statement, String tableName) th } } - protected Connection getConnection(PoolIdentifier identifier) throws SQLException { - Connection connection = null; - switch (identifier) { - case LOAD: - connection = loadPool.getConnection(); - break; - case MISC: - connection = miscPool.getConnection(); - break; - case SAVE: - connection = savePool.getConnection(); - break; - } + Connection getConnection(PoolIdentifier identifier) throws SQLException { + Connection connection = switch (identifier) { + case LOAD -> loadPool.getConnection(); + case MISC -> miscPool.getConnection(); + case SAVE -> savePool.getConnection(); + }; if (connection == null) { throw new RuntimeException("getConnection() for " + identifier.name().toLowerCase(Locale.ENGLISH) + " pool timed out. Increase max connections settings."); } diff --git a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java index 8cb3337ebe..17918f4c37 100644 --- a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java @@ -2,8 +2,12 @@ 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.skills.SkillManager; import com.gmail.nossr50.util.MetadataConstants; +import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.random.ProbabilityUtil; +import com.gmail.nossr50.util.skills.RankUtils; import org.bukkit.Location; import org.bukkit.entity.Arrow; import org.bukkit.metadata.FixedMetadataValue; @@ -12,19 +16,34 @@ import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; +import static com.gmail.nossr50.util.random.ProbabilityUtil.isStaticSkillRNGSuccessful; + public class CrossbowsManager extends SkillManager { public CrossbowsManager(McMMOPlayer mmoPlayer) { super(mmoPlayer, PrimarySkillType.CROSSBOWS); } public void handleRicochet(@NotNull Plugin pluginRef, @NotNull Arrow originalArrow, @NotNull Vector hitBlockNormal) { - // Reflect arrow in new direction - // cleanup metadata on original arrow + // Check player permission + if (!Permissions.trickShot(mmoPlayer.getPlayer())) { + return; + } + // TODO: Add an event for this for plugins to hook into spawnReflectedArrow(pluginRef, originalArrow, originalArrow.getLocation(), hitBlockNormal); } - public void spawnReflectedArrow(@NotNull Plugin pluginRef, @NotNull Arrow originalArrow, @NotNull Location origin, @NotNull Vector normal) { + public void spawnReflectedArrow(@NotNull Plugin pluginRef, @NotNull Arrow originalArrow, + @NotNull Location origin, @NotNull Vector normal) { + int bounceCount = 0; + + if (originalArrow.hasMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT)) { + bounceCount = originalArrow.getMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT).get(0).asInt(); + if (bounceCount >= getTrickShotMaxBounceCount()) { + return; + } + } + final ProjectileSource originalArrowShooter = originalArrow.getShooter(); final Vector arrowInBlockVector = originalArrow.getVelocity(); final Vector reflectedDirection = arrowInBlockVector.subtract(normal.multiply(2 * arrowInBlockVector.dot(normal))); @@ -40,12 +59,18 @@ public void spawnReflectedArrow(@NotNull Plugin pluginRef, @NotNull Arrow origin Arrow arrow = originalArrow.getWorld().spawnArrow(origin, reflectedDirection, 1, 1); arrow.setShooter(originalArrowShooter); + arrow.setMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT, + new FixedMetadataValue(pluginRef, bounceCount + 1)); arrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, new FixedMetadataValue(pluginRef, originalArrowShooter)); - - // TODO: This metadata needs to get cleaned up at some point arrow.setMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE, new FixedMetadataValue(pluginRef, originalArrow.getMetadata( MetadataConstants.METADATA_KEY_BOW_TYPE).get(0))); + + originalArrow.remove(); + } + + public int getTrickShotMaxBounceCount() { + return RankUtils.getRank(mmoPlayer, SubSkillType.CROSSBOWS_TRICK_SHOT); } } diff --git a/src/main/java/com/gmail/nossr50/util/MetadataConstants.java b/src/main/java/com/gmail/nossr50/util/MetadataConstants.java index 321dcf2a11..48aaa8955e 100644 --- a/src/main/java/com/gmail/nossr50/util/MetadataConstants.java +++ b/src/main/java/com/gmail/nossr50/util/MetadataConstants.java @@ -15,6 +15,7 @@ public class MetadataConstants { */ public static final @NotNull String METADATA_KEY_REPLANT = "mcMMO: Recently Replanted"; public static final @NotNull String METADATA_KEY_SPAWNED_ARROW = "mcMMO: Spawned Arrow"; + public static final @NotNull String METADATA_KEY_BOUNCE_COUNT = "mcMMO: Arrow Bounce Count"; public static final @NotNull String METADATA_KEY_BOW_TYPE = "mcMMO: Bow Type"; public static final @NotNull String METADATA_KEY_EXPLOSION_FROM_RUPTURE = "mcMMO: Rupture Explosion"; public static final @NotNull String METADATA_KEY_FISH_HOOK_REF = "mcMMO: Fish Hook Tracker"; diff --git a/src/main/java/com/gmail/nossr50/util/Permissions.java b/src/main/java/com/gmail/nossr50/util/Permissions.java index e184ef8b93..c966711f36 100644 --- a/src/main/java/com/gmail/nossr50/util/Permissions.java +++ b/src/main/java/com/gmail/nossr50/util/Permissions.java @@ -228,6 +228,9 @@ public static boolean customXpBoost(Permissible permissible, PrimarySkillType sk public static boolean treeFeller(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.woodcutting.treefeller"); } /* CROSSBOWS */ public static boolean superShotgun(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.crossbows.supershotgun"); } + public static boolean trickShot(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.crossbows.trickshot"); } + + /* TRIDENTS */ public static boolean tridentsSuper(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.tridents.superability"); } public static boolean tridentsLimitBreak(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.tridents.superability"); } From 04c9db88abcd172f7efd5b64a149ffa6afe2ee97 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 3 Jan 2024 01:29:37 -0800 Subject: [PATCH 53/75] more h2 compatibility stuff --- .../nossr50/database/SQLDatabaseManager.java | 121 +++++++----------- .../database/SQLDatabaseManagerTest.java | 84 +++++++++++- 2 files changed, 124 insertions(+), 81 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index deae24ee9a..4a77ff1fcf 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -233,7 +233,7 @@ public boolean removeUser(String playerName, UUID uuid) { "JOIN " + tablePrefix + "huds h ON (u.id = h.user_id) " + "JOIN " + tablePrefix + "skills s ON (u.id = s.user_id) " + "JOIN " + tablePrefix + "cooldowns c ON (u.id = c.user_id) " + - "WHERE u.user = ?"); + "WHERE u.`USER` = ?"); statement.setString(1, playerName); @@ -292,7 +292,7 @@ public boolean saveUser(PlayerProfile profile) { + " taming = ?, mining = ?, repair = ?, woodcutting = ?" + ", unarmed = ?, herbalism = ?, excavation = ?" + ", archery = ?, swords = ?, axes = ?, acrobatics = ?" - + ", fishing = ?, alchemy = ?, total = ? WHERE user_id = ?"); + + ", fishing = ?, alchemy = ?, crossbows = ?, tridents = ?, total = ? WHERE user_id = ?"); statement.setInt(1, profile.getSkillLevel(PrimarySkillType.TAMING)); statement.setInt(2, profile.getSkillLevel(PrimarySkillType.MINING)); statement.setInt(3, profile.getSkillLevel(PrimarySkillType.REPAIR)); @@ -306,11 +306,13 @@ public boolean saveUser(PlayerProfile profile) { statement.setInt(11, profile.getSkillLevel(PrimarySkillType.ACROBATICS)); statement.setInt(12, profile.getSkillLevel(PrimarySkillType.FISHING)); statement.setInt(13, profile.getSkillLevel(PrimarySkillType.ALCHEMY)); + statement.setInt(14, profile.getSkillLevel(PrimarySkillType.CROSSBOWS)); + statement.setInt(15, profile.getSkillLevel(PrimarySkillType.TRIDENTS)); int total = 0; for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) total += profile.getSkillLevel(primarySkillType); - statement.setInt(14, total); - statement.setInt(15, id); + statement.setInt(16, total); + statement.setInt(17, id); success &= (statement.executeUpdate() != 0); statement.close(); if (!success) { @@ -322,7 +324,7 @@ public boolean saveUser(PlayerProfile profile) { + " taming = ?, mining = ?, repair = ?, woodcutting = ?" + ", unarmed = ?, herbalism = ?, excavation = ?" + ", archery = ?, swords = ?, axes = ?, acrobatics = ?" - + ", fishing = ?, alchemy = ? WHERE user_id = ?"); + + ", fishing = ?, alchemy = ?, crossbows = ?, tridents = ? WHERE user_id = ?"); statement.setInt(1, profile.getSkillXpLevel(PrimarySkillType.TAMING)); statement.setInt(2, profile.getSkillXpLevel(PrimarySkillType.MINING)); statement.setInt(3, profile.getSkillXpLevel(PrimarySkillType.REPAIR)); @@ -336,7 +338,9 @@ public boolean saveUser(PlayerProfile profile) { statement.setInt(11, profile.getSkillXpLevel(PrimarySkillType.ACROBATICS)); statement.setInt(12, profile.getSkillXpLevel(PrimarySkillType.FISHING)); statement.setInt(13, profile.getSkillXpLevel(PrimarySkillType.ALCHEMY)); - statement.setInt(14, id); + statement.setInt(14, profile.getSkillXpLevel(PrimarySkillType.CROSSBOWS)); + statement.setInt(15, profile.getSkillXpLevel(PrimarySkillType.TRIDENTS)); + statement.setInt(16, id); success &= (statement.executeUpdate() != 0); statement.close(); if (!success) { @@ -347,7 +351,7 @@ public boolean saveUser(PlayerProfile profile) { statement = connection.prepareStatement("UPDATE " + tablePrefix + "cooldowns SET " + " mining = ?, woodcutting = ?, unarmed = ?" + ", herbalism = ?, excavation = ?, swords = ?" - + ", axes = ?, blast_mining = ?, chimaera_wing = ? WHERE user_id = ?"); + + ", axes = ?, blast_mining = ?, chimaera_wing = ?, crossbows = ?, tridents = ? WHERE user_id = ?"); statement.setLong(1, profile.getAbilityDATS(SuperAbilityType.SUPER_BREAKER)); statement.setLong(2, profile.getAbilityDATS(SuperAbilityType.TREE_FELLER)); statement.setLong(3, profile.getAbilityDATS(SuperAbilityType.BERSERK)); @@ -357,7 +361,9 @@ public boolean saveUser(PlayerProfile profile) { statement.setLong(7, profile.getAbilityDATS(SuperAbilityType.SKULL_SPLITTER)); statement.setLong(8, profile.getAbilityDATS(SuperAbilityType.BLAST_MINING)); statement.setLong(9, profile.getUniqueData(UniqueDataType.CHIMAERA_WING_DATS)); - statement.setInt(10, id); + statement.setLong(10, profile.getAbilityDATS(SuperAbilityType.SUPER_SHOTGUN)); + statement.setLong(11, profile.getAbilityDATS(SuperAbilityType.TRIDENTS_SUPER_ABILITY)); + statement.setInt(12, id); success = (statement.executeUpdate() != 0); statement.close(); if (!success) { @@ -404,7 +410,7 @@ public boolean saveUser(PlayerProfile profile) { try { connection = getConnection(PoolIdentifier.MISC); - statement = connection.prepareStatement("SELECT " + query + ", user FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON (user_id = id) WHERE " + query + " > 0 AND NOT user = '\\_INVALID\\_OLD\\_USERNAME\\_' ORDER BY " + query + " DESC, user LIMIT ?, ?"); + statement = connection.prepareStatement("SELECT " + query + ", `USER` FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON (user_id = id) WHERE " + query + " > 0 AND NOT `USER` = '\\_INVALID\\_OLD\\_USERNAME\\_' ORDER BY " + query + " DESC, `USER` LIMIT ?, ?"); statement.setInt(1, (pageNumber * statsPerPage) - statsPerPage); statement.setInt(2, statsPerPage); resultSet = statement.executeQuery(); @@ -445,7 +451,7 @@ public Map readRank(String playerName) { // Get count of all users with higher skill level than player String sql = "SELECT COUNT(*) AS 'rank' FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE " + skillName + " > 0 " + "AND " + skillName + " > (SELECT " + skillName + " FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " + - "WHERE user = ?)"; + "WHERE `USER` = ?)"; statement = connection.prepareStatement(sql); statement.setString(1, playerName); @@ -458,7 +464,7 @@ public Map readRank(String playerName) { // Ties are settled by alphabetical order sql = "SELECT user, " + skillName + " FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE " + skillName + " > 0 " + "AND " + skillName + " = (SELECT " + skillName + " FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " + - "WHERE user = '" + playerName + "') ORDER BY user"; + "WHERE `USER` = '" + playerName + "') ORDER BY user"; resultSet.close(); statement.close(); @@ -481,7 +487,7 @@ public Map readRank(String playerName) { "WHERE " + ALL_QUERY_VERSION + " > 0 " + "AND " + ALL_QUERY_VERSION + " > " + "(SELECT " + ALL_QUERY_VERSION + " " + - "FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE user = ?)"; + "FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE `USER` = ?)"; statement = connection.prepareStatement(sql); statement.setString(1, playerName); @@ -499,7 +505,7 @@ public Map readRank(String playerName) { "WHERE " + ALL_QUERY_VERSION + " > 0 " + "AND " + ALL_QUERY_VERSION + " = " + "(SELECT " + ALL_QUERY_VERSION + " " + - "FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE user = ?) ORDER BY user"; + "FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE `USER` = ?) ORDER BY user"; statement = connection.prepareStatement(sql); statement.setString(1, playerName); @@ -734,7 +740,7 @@ public void convertUsers(DatabaseManager destination) { + "JOIN " + tablePrefix + "experience e ON (u.id = e.user_id) " + "JOIN " + tablePrefix + "cooldowns c ON (u.id = c.user_id) " + "JOIN " + tablePrefix + "huds h ON (u.id = h.user_id) " - + "WHERE u.user = ?"); + + "WHERE u.`USER` = ?"); List usernames = getStoredUsers(); int convertedUsers = 0; long startMillis = System.currentTimeMillis(); @@ -773,7 +779,7 @@ public boolean saveUserUUID(String userName, UUID uuid) { connection = getConnection(PoolIdentifier.MISC); statement = connection.prepareStatement( "UPDATE `" + tablePrefix + "users` SET " - + " uuid = ? WHERE user = ?"); + + " uuid = ? WHERE `USER` = ?"); statement.setString(1, uuid.toString()); statement.setString(2, userName); statement.execute(); @@ -797,7 +803,7 @@ public boolean saveUserUUIDs(Map fetchedUUIDs) { try { connection = getConnection(PoolIdentifier.MISC); - statement = connection.prepareStatement("UPDATE " + tablePrefix + "users SET uuid = ? WHERE user = ?"); + statement = connection.prepareStatement("UPDATE " + tablePrefix + "users SET uuid = ? WHERE `USER` = ?"); for (Map.Entry entry : fetchedUUIDs.entrySet()) { statement.setString(1, entry.getValue().toString()); @@ -839,7 +845,7 @@ public List getStoredUsers() { try { connection = getConnection(PoolIdentifier.MISC); statement = connection.createStatement(); - resultSet = statement.executeQuery("SELECT user FROM " + tablePrefix + "users"); + resultSet = statement.executeQuery("SELECT `USER` FROM " + tablePrefix + "users"); while (resultSet.next()) { users.add(resultSet.getString("user")); } @@ -1019,66 +1025,32 @@ private void checkStructure() { tryClose(connection); } - updateStructure("SKILLS", "CROSSBOWS", String.valueOf(32)); - updateStructure("SKILLS", "TRIDENTS", String.valueOf(32)); + String skills = "skills"; + String crossbows = "crossbows"; + String tridents = "tridents"; + String experience = "experience"; + String cooldowns = "cooldowns"; - updateStructure("EXPERIENCE", "CROSSBOWS", String.valueOf(10)); - updateStructure("EXPERIENCE", "TRIDENTS", String.valueOf(10)); + updateStructure(skills, crossbows, String.valueOf(32)); + updateStructure(skills, tridents, String.valueOf(32)); - updateStructure("COOLDOWNS", "CROSSBOWS", String.valueOf(10)); - updateStructure("COOLDOWNS", "TRIDENTS", String.valueOf(10)); + updateStructure(experience, crossbows, String.valueOf(10)); + updateStructure(experience, tridents, String.valueOf(10)); + + updateStructure(cooldowns, crossbows, String.valueOf(10)); + updateStructure(cooldowns, tridents, String.valueOf(10)); } private void updateStructure(String tableName, String columnName, String columnSize) { - boolean columnExists = false; - DatabaseMetaData metaData = null; - - try(Connection connection = getConnection(PoolIdentifier.MISC)) { - metaData = connection.getMetaData(); - ResultSet rs = null; + try (Connection connection = getConnection(PoolIdentifier.MISC); + Statement createStatement = connection.createStatement()) { - try { - // Replace "YOUR_SCHEMA" with your database schema name if necessary, or use null to not filter by schema. - // Replace "YOUR_TABLE" with the actual table name, and "YOUR_COLUMN" with the column you're checking for. - rs = metaData.getColumns(null, null, tablePrefix + tableName, columnName); + String startingLevel = "'" + mcMMO.p.getAdvancedConfig().getStartingLevel() + "'"; + createStatement.executeUpdate("ALTER TABLE `" + tablePrefix + tableName + "` " + + "ADD COLUMN IF NOT EXISTS `" + columnName + "` int(" + columnSize + ") unsigned NOT NULL DEFAULT " + startingLevel); - if (rs.next()) { - // If the result set is not empty, the column exists - columnExists = true; - } - } catch (SQLException e) { - e.printStackTrace(); // Handle the exception appropriately - } finally { - if (rs != null) { - try { - rs.close(); - } catch (SQLException e) { - e.printStackTrace(); // Handle the exception appropriately - } - } - } - - if (!columnExists) { - // Alter the table to add the column - Statement createStatement = null; - try { - createStatement = connection.createStatement(); - String startingLevel = "'" + mcMMO.p.getAdvancedConfig().getStartingLevel() + "'"; - createStatement.executeUpdate("ALTER TABLE `" + tablePrefix + tableName + "` " - + "ADD COLUMN `" + columnName + "` int(" + columnSize + ") unsigned NOT NULL DEFAULT " + startingLevel); - } catch (SQLException e) { - e.printStackTrace(); // Handle the exception appropriately - } finally { - if (createStatement != null) { - try { - createStatement.close(); - } catch (SQLException e) { - e.printStackTrace(); // Handle the exception appropriately - } - } - } - } } catch (SQLException e) { + e.printStackTrace(); // Consider more robust logging throw new RuntimeException(e); } } @@ -1112,6 +1084,7 @@ Connection getConnection(PoolIdentifier identifier) throws SQLException { * @param upgrade Upgrade to attempt to apply */ private void checkDatabaseStructure(Connection connection, UpgradeType upgrade) { + // TODO: Rewrite / Refactor if (!mcMMO.getUpgradeManager().shouldUpgrade(upgrade)) { LogUtils.debug(logger, "Skipping " + upgrade.name() + " upgrade (unneeded)"); return; @@ -1265,8 +1238,8 @@ private PlayerProfile loadFromResult(String playerName, ResultSet result) throws skillsXp.put(PrimarySkillType.ACROBATICS, result.getFloat(OFFSET_XP + 11)); skillsXp.put(PrimarySkillType.FISHING, result.getFloat(OFFSET_XP + 12)); skillsXp.put(PrimarySkillType.ALCHEMY, result.getFloat(OFFSET_XP + 13)); - skillsXp.put(PrimarySkillType.ALCHEMY, result.getFloat(OFFSET_XP + 14)); - skillsXp.put(PrimarySkillType.ALCHEMY, result.getFloat(OFFSET_XP + 15)); + skillsXp.put(PrimarySkillType.CROSSBOWS, result.getFloat(OFFSET_XP + 14)); + skillsXp.put(PrimarySkillType.TRIDENTS, result.getFloat(OFFSET_XP + 15)); // Taming - Unused - result.getInt(OFFSET_DATS + 1) skillsDATS.put(SuperAbilityType.SUPER_BREAKER, result.getInt(OFFSET_DATS + 2)); @@ -1631,7 +1604,7 @@ private int getUserID(final Connection connection, final String playerName, fina PreparedStatement statement = null; try { - statement = connection.prepareStatement("SELECT id, user FROM " + tablePrefix + "users WHERE uuid = ? OR (uuid IS NULL AND user = ?)"); + statement = connection.prepareStatement("SELECT id, `USER` FROM " + tablePrefix + "users WHERE uuid = ? OR (uuid IS NULL AND `USER` = ?)"); statement.setString(1, uuid.toString()); statement.setString(2, playerName); resultSet = statement.executeQuery(); @@ -1660,7 +1633,7 @@ private int getUserIDByName(final Connection connection, final String playerName PreparedStatement statement = null; try { - statement = connection.prepareStatement("SELECT id, user FROM " + tablePrefix + "users WHERE user = ?"); + statement = connection.prepareStatement("SELECT id, `USER` FROM " + tablePrefix + "users WHERE `USER` = ?"); statement.setString(1, playerName); resultSet = statement.executeQuery(); @@ -1761,7 +1734,7 @@ The following columns were set to use latin1 historically (now utf8mb4) private String getUpdateUserInUsersTableSQLQuery() { return "ALTER TABLE\n" + " " + tablePrefix + "users\n" + - " CHANGE user user\n" + + " CHANGE `USER` user\n" + " " + USER_VARCHAR + "\n" + " CHARACTER SET utf8mb4\n" + " COLLATE utf8mb4_unicode_ci;"; diff --git a/src/test/java/com/gmail/nossr50/database/SQLDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/SQLDatabaseManagerTest.java index d70332321a..9a183f2e40 100644 --- a/src/test/java/com/gmail/nossr50/database/SQLDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/SQLDatabaseManagerTest.java @@ -3,26 +3,19 @@ import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.config.GeneralConfig; import com.gmail.nossr50.datatypes.MobHealthbarType; -import com.gmail.nossr50.datatypes.database.UpgradeType; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.LogUtils; import com.gmail.nossr50.util.compat.CompatibilityManager; import com.gmail.nossr50.util.platform.MinecraftGameVersion; -import com.gmail.nossr50.util.platform.version.SimpleNumericVersion; import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.util.upgrade.UpgradeManager; -import org.bukkit.Material; 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.sql.*; -import java.util.Locale; -import java.util.Set; import java.util.logging.Logger; import static org.junit.jupiter.api.Assertions.*; @@ -172,4 +165,81 @@ void testNewUserGetSkillLevel() { 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)); + } + } } From 4ba0f76eb94c890407566c1b48177431363c4e2c Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 3 Jan 2024 01:51:59 -0800 Subject: [PATCH 54/75] Bouncing --- .../gmail/nossr50/skills/crossbows/Crossbows.java | 5 ----- .../skills/crossbows/CrossbowsManager.java | 15 ++++++++++++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java b/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java index 02ea5b24a3..35f9aa2aa9 100644 --- a/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java +++ b/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java @@ -17,11 +17,6 @@ public class Crossbows { public static void processCrossbows(ProjectileHitEvent event, Plugin pluginRef) { if(event.getEntity() instanceof Arrow originalArrow && event.getHitBlock() != null && event.getHitBlockFace() != null) { if (originalArrow.getShooter() instanceof Player) { - // Avoid infinite spawning of arrows - if (originalArrow.hasMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW)) { - return; - } - McMMOPlayer mmoPlayer = UserManager.getPlayer((Player) originalArrow.getShooter()); if (mmoPlayer != null) { mmoPlayer.getCrossbowsManager().handleRicochet( diff --git a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java index 17918f4c37..28bf16fd3a 100644 --- a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java @@ -4,10 +4,12 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.skills.SkillManager; +import com.gmail.nossr50.util.BowType; import com.gmail.nossr50.util.MetadataConstants; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.RankUtils; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Arrow; import org.bukkit.metadata.FixedMetadataValue; @@ -39,9 +41,13 @@ public void spawnReflectedArrow(@NotNull Plugin pluginRef, @NotNull Arrow origin if (originalArrow.hasMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT)) { bounceCount = originalArrow.getMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT).get(0).asInt(); + Bukkit.broadcastMessage("Bounce count: " + bounceCount); if (bounceCount >= getTrickShotMaxBounceCount()) { + Bukkit.broadcastMessage("No more bounces."); return; } + } else { + Bukkit.broadcastMessage("No bounce count metadata"); } final ProjectileSource originalArrowShooter = originalArrow.getShooter(); @@ -51,8 +57,12 @@ public void spawnReflectedArrow(@NotNull Plugin pluginRef, @NotNull Arrow origin // check the angle of the arrow against the inverse normal to see if the angle was too shallow - if (arrowInBlockVector.angle(inverseNormal) < Math.PI / 4) { + // only checks angle on the first bounce + if (bounceCount == 0 && arrowInBlockVector.angle(inverseNormal) < Math.PI / 4) { + Bukkit.broadcastMessage("No bouncing."); return; + } else { + Bukkit.broadcastMessage("Bouncing."); } // Spawn new arrow with the reflected direction @@ -64,8 +74,7 @@ public void spawnReflectedArrow(@NotNull Plugin pluginRef, @NotNull Arrow origin arrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, new FixedMetadataValue(pluginRef, originalArrowShooter)); arrow.setMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE, - new FixedMetadataValue(pluginRef, originalArrow.getMetadata( - MetadataConstants.METADATA_KEY_BOW_TYPE).get(0))); + new FixedMetadataValue(pluginRef, BowType.CROSSBOW)); originalArrow.remove(); } From 826d16d916ab1032102f6f7285b81749b7bd844b Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 4 Jan 2024 12:39:26 -0800 Subject: [PATCH 55/75] More work on Crossbows & Tridents --- .../commands/skills/CrossbowsCommand.java | 34 ++++++++++ .../nossr50/commands/skills/SkillCommand.java | 12 ---- .../commands/skills/SwordsCommand.java | 9 +-- .../commands/skills/TridentsCommand.java | 5 +- .../gmail/nossr50/config/AdvancedConfig.java | 9 +++ .../datatypes/skills/SubSkillType.java | 2 + .../skills/crossbows/CrossbowsManager.java | 29 ++++++-- .../skills/tridents/TridentsManager.java | 14 ++++ .../com/gmail/nossr50/util/Permissions.java | 1 + .../nossr50/util/skills/CombatUtils.java | 14 +++- .../gmail/nossr50/util/skills/SkillUtils.java | 12 ++++ .../resources/locale/locale_en_US.properties | 7 ++ src/main/resources/plugin.yml | 6 ++ src/main/resources/skillranks.yml | 66 +++++++++++++++++++ 14 files changed, 193 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java index 05e7ecabee..11cdb67a53 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java @@ -1,8 +1,14 @@ package com.gmail.nossr50.commands.skills; +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.locale.LocaleLoader; +import com.gmail.nossr50.skills.archery.Archery; import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.random.ProbabilityUtil; +import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; @@ -13,6 +19,9 @@ public class CrossbowsCommand extends SkillCommand { private boolean canSSG; + private boolean canTrickShot; + private boolean canPoweredShot; + private int bounceCount; public CrossbowsCommand() { super(PrimarySkillType.CROSSBOWS); @@ -27,17 +36,42 @@ protected void dataCalculations(Player player, float skillValue) { protected void permissionsCheck(Player player) { canSSG = RankUtils.hasUnlockedSubskill(player, SubSkillType.CROSSBOWS_SUPER_SHOTGUN) && Permissions.superShotgun(player); + + canTrickShot = RankUtils.hasUnlockedSubskill(player, SubSkillType.CROSSBOWS_TRICK_SHOT) + && Permissions.trickShot(player); + + canPoweredShot = RankUtils.hasUnlockedSubskill(player, SubSkillType.CROSSBOWS_POWERED_SHOT) + && Permissions.poweredShot(player); } @Override protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { List messages = new ArrayList<>(); + McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + if (mmoPlayer == null) { + return messages; + } + + if (canPoweredShot) { + messages.add(getStatMessage(SubSkillType.ARCHERY_SKILL_SHOT, percent.format(mmoPlayer.getCrossbowsManager().getDamageBonusPercent(player)))); + } + if (canSSG) { messages.add("Super Shotgun"); //TODO: Implement SSG } + if (canTrickShot) { + messages.add(getStatMessage(SubSkillType.CROSSBOWS_TRICK_SHOT, + String.valueOf(mmoPlayer.getCrossbowsManager().getTrickShotMaxBounceCount()))); + } + + if(Permissions.canUseSubSkill(player, SubSkillType.CROSSBOWS_CROSSBOWS_LIMIT_BREAK)) { + messages.add(getStatMessage(SubSkillType.CROSSBOWS_CROSSBOWS_LIMIT_BREAK, + String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, SubSkillType.CROSSBOWS_CROSSBOWS_LIMIT_BREAK, 1000)))); + } + return messages; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java index fac6a99eaf..61b2f7ae43 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java @@ -11,7 +11,6 @@ import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.gmail.nossr50.util.skills.PerksUtils; -import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.util.text.StringUtils; import com.gmail.nossr50.util.text.TextComponentFactory; @@ -29,7 +28,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; -import java.util.Set; public abstract class SkillCommand implements TabExecutor { protected PrimarySkillType skill; @@ -294,14 +292,4 @@ protected String getLimitBreakDescriptionParameter() { protected abstract List getTextComponents(Player player); - /** - * Checks if a player can use a skill - * @param player target player - * @param subSkillType target subskill - * @return true if the player has permission and has the skill unlocked - */ - protected boolean canUseSubskill(Player player, SubSkillType subSkillType) - { - return Permissions.isSubSkillEnabled(player, subSkillType) && RankUtils.hasUnlockedSubskill(player, subSkillType); - } } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java index b59eae4c29..03d15d4ce8 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java @@ -9,6 +9,7 @@ import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; +import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -69,8 +70,8 @@ protected void dataCalculations(Player player, float skillValue) { @Override protected void permissionsCheck(Player player) { - canRupture = canUseSubskill(player, SubSkillType.SWORDS_RUPTURE); - canCounter = canUseSubskill(player, SubSkillType.SWORDS_COUNTER_ATTACK); + canRupture = SkillUtils.canUseSubskill(player, SubSkillType.SWORDS_RUPTURE); + canCounter = SkillUtils.canUseSubskill(player, SubSkillType.SWORDS_COUNTER_ATTACK); canSerratedStrike = RankUtils.hasUnlockedSubskill(player, SubSkillType.SWORDS_SERRATED_STRIKES) && Permissions.serratedStrikes(player); } @@ -101,13 +102,13 @@ protected List statsDisplay(Player player, float skillValue, boolean has + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", serratedStrikesLengthEndurance) : "")); } - if(canUseSubskill(player, SubSkillType.SWORDS_STAB)) + if(SkillUtils.canUseSubskill(player, SubSkillType.SWORDS_STAB)) { messages.add(getStatMessage(SubSkillType.SWORDS_STAB, String.valueOf(UserManager.getPlayer(player).getSwordsManager().getStabDamage()))); } - if(canUseSubskill(player, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK)) { + if(SkillUtils.canUseSubskill(player, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK)) { messages.add(getStatMessage(SubSkillType.SWORDS_SWORDS_LIMIT_BREAK, String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK, 1000)))); } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java index 4acf203de4..01379aca26 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java @@ -3,6 +3,7 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.util.skills.CombatUtils; +import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -27,12 +28,12 @@ protected void permissionsCheck(Player player) {} protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { List messages = new ArrayList<>(); - if (canUseSubskill(player, SubSkillType.TRIDENTS_SUPER)) { + if (SkillUtils.canUseSubskill(player, SubSkillType.TRIDENTS_SUPER)) { messages.add("Tridents Super Ability"); //TODO: Implement Tridents Super } - if(canUseSubskill(player, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK)) { + if(SkillUtils.canUseSubskill(player, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK)) { messages.add(getStatMessage(SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK, String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK, 1000)))); } diff --git a/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java b/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java index 04cca138a7..d10569dc46 100644 --- a/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java +++ b/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java @@ -693,6 +693,15 @@ public double getSkullSplitterModifier() { return config.getDouble("Skills.Axes.SkullSplitter.DamageModifier", 2.0D); } + /* CROSSBOWS */ + public double getPoweredShotRankDamageMultiplier() { + return config.getDouble("Skills.Crossbows.PoweredShot.RankDamageMultiplier", 10.0D); + } + + public double getPoweredShotDamageMax() { + return config.getDouble("Skills.Archery.SkillShot.MaxDamage", 9.0D); + } + /* EXCAVATION */ //Nothing to configure, everything is already configurable in config.yml diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java index 3dc587eaeb..b388ecb4ee 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java @@ -36,6 +36,7 @@ public enum SubSkillType { CROSSBOWS_SUPER_SHOTGUN(1), CROSSBOWS_CROSSBOWS_LIMIT_BREAK(10), CROSSBOWS_TRICK_SHOT(3), + CROSSBOWS_POWERED_SHOT(20), /* Excavation */ EXCAVATION_ARCHAEOLOGY(8), @@ -101,6 +102,7 @@ public enum SubSkillType { /* Tridents */ TRIDENTS_SUPER(1), + TRIDENTS_IMPALE(10), TRIDENTS_TRIDENTS_LIMIT_BREAK(10), /* Unarmed */ diff --git a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java index 28bf16fd3a..54fdf4849b 100644 --- a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java @@ -3,7 +3,9 @@ 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.mcMMO; import com.gmail.nossr50.skills.SkillManager; +import com.gmail.nossr50.skills.archery.Archery; import com.gmail.nossr50.util.BowType; import com.gmail.nossr50.util.MetadataConstants; import com.gmail.nossr50.util.Permissions; @@ -12,6 +14,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Arrow; +import org.bukkit.entity.Player; import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.plugin.Plugin; import org.bukkit.projectiles.ProjectileSource; @@ -41,13 +44,9 @@ public void spawnReflectedArrow(@NotNull Plugin pluginRef, @NotNull Arrow origin if (originalArrow.hasMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT)) { bounceCount = originalArrow.getMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT).get(0).asInt(); - Bukkit.broadcastMessage("Bounce count: " + bounceCount); if (bounceCount >= getTrickShotMaxBounceCount()) { - Bukkit.broadcastMessage("No more bounces."); return; } - } else { - Bukkit.broadcastMessage("No bounce count metadata"); } final ProjectileSource originalArrowShooter = originalArrow.getShooter(); @@ -59,10 +58,7 @@ public void spawnReflectedArrow(@NotNull Plugin pluginRef, @NotNull Arrow origin // check the angle of the arrow against the inverse normal to see if the angle was too shallow // only checks angle on the first bounce if (bounceCount == 0 && arrowInBlockVector.angle(inverseNormal) < Math.PI / 4) { - Bukkit.broadcastMessage("No bouncing."); return; - } else { - Bukkit.broadcastMessage("Bouncing."); } // Spawn new arrow with the reflected direction @@ -82,4 +78,23 @@ public void spawnReflectedArrow(@NotNull Plugin pluginRef, @NotNull Arrow origin public int getTrickShotMaxBounceCount() { return RankUtils.getRank(mmoPlayer, SubSkillType.CROSSBOWS_TRICK_SHOT); } + + public double getPoweredShotBonusDamage(Player player, double oldDamage) + { + double damageBonusPercent = getDamageBonusPercent(player); + double newDamage = oldDamage + (oldDamage * damageBonusPercent); + return Math.min(newDamage, (oldDamage + mcMMO.p.getAdvancedConfig().getPoweredShotDamageMax())); + } + + public double getDamageBonusPercent(Player player) { + return ((RankUtils.getRank(player, SubSkillType.CROSSBOWS_POWERED_SHOT)) * (mcMMO.p.getAdvancedConfig().getPoweredShotRankDamageMultiplier()) / 100.0D); + } + + public double poweredShot(double oldDamage) { + if (ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.CROSSBOWS_POWERED_SHOT, getPlayer())) { + return Archery.getSkillShotBonusDamage(getPlayer(), oldDamage); + } else { + return oldDamage; + } + } } diff --git a/src/main/java/com/gmail/nossr50/skills/tridents/TridentsManager.java b/src/main/java/com/gmail/nossr50/skills/tridents/TridentsManager.java index 22ae802cb2..bd4296d0f6 100644 --- a/src/main/java/com/gmail/nossr50/skills/tridents/TridentsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/tridents/TridentsManager.java @@ -2,9 +2,11 @@ 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.datatypes.skills.ToolType; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.skills.RankUtils; public class TridentsManager extends SkillManager { public TridentsManager(McMMOPlayer mmoPlayer) { @@ -18,4 +20,16 @@ public TridentsManager(McMMOPlayer mmoPlayer) { public boolean canActivateAbility() { return mmoPlayer.getToolPreparationMode(ToolType.TRIDENTS) && Permissions.tridentsSuper(getPlayer()); } + + public double impaleDamageBonus() { + int rank = RankUtils.getRank(getPlayer(), SubSkillType.TRIDENTS_IMPALE); + + if(rank > 1) { + return (1.0D + (rank * .5D)); + } else if(rank == 1) { + return 1.0D; + } + + return 0.0D; + } } diff --git a/src/main/java/com/gmail/nossr50/util/Permissions.java b/src/main/java/com/gmail/nossr50/util/Permissions.java index c966711f36..b5e6a5c110 100644 --- a/src/main/java/com/gmail/nossr50/util/Permissions.java +++ b/src/main/java/com/gmail/nossr50/util/Permissions.java @@ -229,6 +229,7 @@ public static boolean customXpBoost(Permissible permissible, PrimarySkillType sk /* CROSSBOWS */ public static boolean superShotgun(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.crossbows.supershotgun"); } public static boolean trickShot(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.crossbows.trickshot"); } + public static boolean poweredShot(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.crossbows.poweredshot"); } /* TRIDENTS */ public static boolean tridentsSuper(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.tridents.superability"); } diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index 7b1d07d86c..485ef96da5 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -144,8 +144,12 @@ private static void processTridentCombat(@NotNull LivingEntity target, @NotNull mcMMOPlayer.checkAbilityActivation(PrimarySkillType.TRIDENTS); } + if (SkillUtils.canUseSubskill(player, SubSkillType.TRIDENTS_IMPALE)) { + boostedDamage += (tridentsManager.impaleDamageBonus() * mcMMOPlayer.getAttackStrength()); + } + if(canUseLimitBreak(player, target, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK)) { - boostedDamage+=(getLimitBreakDamage(player, target, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK) * mcMMOPlayer.getAttackStrength()); + boostedDamage += (getLimitBreakDamage(player, target, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK) * mcMMOPlayer.getAttackStrength()); } event.setDamage(boostedDamage); @@ -154,7 +158,8 @@ private static void processTridentCombat(@NotNull LivingEntity target, @NotNull printFinalDamageDebug(player, event, mcMMOPlayer); } - private static void processCrossbowsCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event, @NotNull Projectile arrow) { + private static void processCrossbowsCombat(@NotNull LivingEntity target, @NotNull Player player, + @NotNull EntityDamageByEntityEvent event, @NotNull Projectile arrow) { double initialDamage = event.getDamage(); McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); @@ -167,6 +172,11 @@ private static void processCrossbowsCombat(@NotNull LivingEntity target, @NotNul double boostedDamage = event.getDamage(); + if (SkillUtils.canUseSubskill(player, SubSkillType.CROSSBOWS_POWERED_SHOT)) { + //Not Additive + boostedDamage = mcMMOPlayer.getCrossbowsManager().poweredShot(initialDamage); + } + if(canUseLimitBreak(player, target, SubSkillType.CROSSBOWS_CROSSBOWS_LIMIT_BREAK)) { boostedDamage+=getLimitBreakDamage(player, target, SubSkillType.CROSSBOWS_CROSSBOWS_LIMIT_BREAK); } diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java index d685d231a2..5efc2422ec 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java @@ -13,6 +13,7 @@ import com.gmail.nossr50.metadata.ItemMetadataService; import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.text.StringUtils; @@ -352,4 +353,15 @@ public static int getRepairAndSalvageQuantities(Material itemMaterial, Material return quantity; } + + /** + * Checks if a player can use a skill + * @param player target player + * @param subSkillType target subskill + * @return true if the player has permission and has the skill unlocked + */ + public static boolean canUseSubskill(Player player, SubSkillType subSkillType) + { + return Permissions.isSubSkillEnabled(player, subSkillType) && RankUtils.hasUnlockedSubskill(player, subSkillType); + } } diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 58943933ae..b56bf20f43 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -183,6 +183,7 @@ Archery.SubSkill.ArcheryLimitBreak.Stat=Limit Break Max DMG Archery.Listener=Archery: Archery.SkillName=ARCHERY Archery.SubSkill.ExplosiveShot.Name=Explosive Shot +Archery.SubSkill.ExplosiveShot.Description=Fire an explosive arrow Archery.Skills.ExplosiveShot.Off= Archery.Skills.ExplosiveShot.On=&a**EXPLOSIVE SHOT ACTIVATED** Archery.Skills.ExplosiveShot.Other.Off=Explosive Shot&a has worn off for &e{0} @@ -428,6 +429,9 @@ Crossbows.Ability.Lower=&7You lower your crossbow. Crossbows.Ability.Ready=&3You &6ready&3 your Crossbow. Crossbows.Skills.SSG.Refresh=&aYour &eSuper Shotgun &aability is refreshed! Crossbows.Skills.SSG.Other.On=&a{0}&2 used &Super Shotgun! +Crossbows.SubSkill.PoweredShot.Name=Powered Shot +Crossbows.SubSkill.PoweredShot.Description=Increases damage done with crossbows +Crossbows.SubSkill.PoweredShot.Stat=Powered Shot Bonus Damage Crossbows.SubSkill.SuperShotgun.Name=Super Shotgun Crossbows.SubSkill.SuperShotgun.Description=Shoot dozens of arrows at once Crossbows.SubSkill.SuperShotgun.Stat=Per Projectile damage &a{0} @@ -450,6 +454,9 @@ Tridents.Skills.TA.Other.On=&a{0}&2 used Trident &Super! Tridents.SubSkill.SuperAbility.Name=Tridents Super Ability Tridents.SubSkill.SuperAbility.Description=N/A Tridents.SubSkill.SuperAbility.Stat=N/A +Trients.SubSkill.Impale.Name=Impale +Tridents.SubSkill.Impale.Description=Increases damage done with tridents +Tridents.SubSkill.Impale.Stat=Impale Bonus Damage Tridents.SubSkill.TridentsLimitBreak.Name=Tridents Limit Break Tridents.SubSkill.TridentsLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether it will boost damage in PVE. Tridents.SubSkill.TridentsLimitBreak.Stat=Limit Break Max DMG diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index a0e57eb5d8..21ba26247d 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -340,6 +340,7 @@ permissions: children: mcmmo.ability.crossbows.supershotgun: true mcmmo.ability.crossbows.trickshot: true + mcmmo.ability.crossbows.poweredshot: true mcmmo.ability.crossbows.crossbowslimitbreak: true mcmmo.ability.crossbows.supershotgun: description: Allows access to the Super Shotgun super ability @@ -347,6 +348,8 @@ permissions: description: Adds damage to crossbows mcmmo.ability.crossbows.trickshot: description: Allows access to the Trick Shot ability + mcmmo.ability.crossbows.poweredshot: + description: Allows access to the Powered Shot ability mcmmo.ability.excavation.*: default: false description: Allows access to all Excavation abilities @@ -720,9 +723,12 @@ permissions: description: Allows access to all Trident abilities children: mcmmo.ability.tridents.superability: true + mcmmo.ability.tridents.impale: true mcmmo.ability.tridents.tridentslimitbreak: true mcmmo.ability.tridents.superability: description: Allows access to tridents super ability + mcmmo.ability.tridents.impale: + description: Allows access to tridents Impale ability mcmmo.ability.tridents.tridentslimitbreak: description: Adds damage to tridents mcmmo.ability.unarmed.*: diff --git a/src/main/resources/skillranks.yml b/src/main/resources/skillranks.yml index 5ad0e84ee2..a41e55fb12 100644 --- a/src/main/resources/skillranks.yml +++ b/src/main/resources/skillranks.yml @@ -216,6 +216,49 @@ Crossbows: Rank_1: 50 Rank_2: 200 Rank_3: 400 + PoweredShot: + Standard: + Rank_1: 1 + Rank_2: 10 + Rank_3: 15 + Rank_4: 20 + Rank_5: 25 + Rank_6: 30 + Rank_7: 35 + Rank_8: 40 + Rank_9: 45 + Rank_10: 50 + Rank_11: 55 + Rank_12: 60 + Rank_13: 65 + Rank_14: 70 + Rank_15: 75 + Rank_16: 80 + Rank_17: 85 + Rank_18: 90 + Rank_19: 95 + Rank_20: 100 + RetroMode: + Rank_1: 1 + Rank_2: 100 + Rank_3: 150 + Rank_4: 200 + Rank_5: 250 + Rank_6: 300 + Rank_7: 350 + Rank_8: 400 + Rank_9: 450 + Rank_10: 500 + Rank_11: 550 + Rank_12: 600 + Rank_13: 650 + Rank_14: 700 + Rank_15: 750 + Rank_16: 800 + Rank_17: 850 + Rank_18: 900 + Rank_19: 950 + Rank_20: 1000 CrossbowsLimitBreak: Standard: Rank_1: 10 @@ -273,6 +316,29 @@ Tridents: Rank_1: 5 RetroMode: Rank_1: 50 + Impale: + Standard: + Rank_1: 5 + Rank_2: 15 + Rank_3: 25 + Rank_4: 35 + Rank_5: 45 + Rank_6: 55 + Rank_7: 65 + Rank_8: 75 + Rank_9: 85 + Rank_10: 100 + RetroMode: + Rank_1: 50 + Rank_2: 150 + Rank_3: 250 + Rank_4: 350 + Rank_5: 450 + Rank_6: 550 + Rank_7: 650 + Rank_8: 750 + Rank_9: 850 + Rank_10: 1000 Taming: BeastLore: Standard: From fdc308762c66fff45be69a0a1b6867e9af3c651a Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 14 Jan 2024 08:51:23 -0800 Subject: [PATCH 56/75] Hack to disable supers that aren't ready yet --- .../com/gmail/nossr50/util/Permissions.java | 17 ++++++++++++++--- .../gmail/nossr50/util/skills/SkillUtils.java | 7 +++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/util/Permissions.java b/src/main/java/com/gmail/nossr50/util/Permissions.java index b5e6a5c110..5e0eef63ca 100644 --- a/src/main/java/com/gmail/nossr50/util/Permissions.java +++ b/src/main/java/com/gmail/nossr50/util/Permissions.java @@ -168,7 +168,12 @@ public static boolean customXpBoost(Permissible permissible, PrimarySkillType sk public static boolean skillEnabled(Permissible permissible, PrimarySkillType skill) {return permissible.hasPermission("mcmmo.skills." + skill.toString().toLowerCase(Locale.ENGLISH)); } public static boolean vanillaXpBoost(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.ability." + skill.toString().toLowerCase(Locale.ENGLISH) + ".vanillaxpboost"); } - public static boolean isSubSkillEnabled(Permissible permissible, SubSkillType subSkillType) { return permissible.hasPermission(subSkillType.getPermissionNodeAddress()); } + public static boolean isSubSkillEnabled(Permissible permissible, SubSkillType subSkillType) { + // hack to disable supers that aren't coded yet + if(subSkillType == SubSkillType.TRIDENTS_SUPER || subSkillType == SubSkillType.CROSSBOWS_SUPER_SHOTGUN) + return false; + return permissible.hasPermission(subSkillType.getPermissionNodeAddress()); + } /* ACROBATICS */ public static boolean dodge(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.acrobatics.dodge"); } @@ -227,12 +232,18 @@ public static boolean customXpBoost(Permissible permissible, PrimarySkillType sk /* WOODCUTTING */ public static boolean treeFeller(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.woodcutting.treefeller"); } /* CROSSBOWS */ - public static boolean superShotgun(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.crossbows.supershotgun"); } + public static boolean superShotgun(Permissible permissible) { + return false; + // return permissible.hasPermission("mcmmo.ability.crossbows.supershotgun"); + } public static boolean trickShot(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.crossbows.trickshot"); } public static boolean poweredShot(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.crossbows.poweredshot"); } /* TRIDENTS */ - public static boolean tridentsSuper(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.tridents.superability"); } + public static boolean tridentsSuper(Permissible permissible) { + return false; + // return permissible.hasPermission("mcmmo.ability.tridents.superability"); + } public static boolean tridentsLimitBreak(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.tridents.superability"); } /* diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java index 5efc2422ec..e849c7a0fa 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java @@ -34,6 +34,8 @@ import java.util.Iterator; +import static java.util.Objects.requireNonNull; + public final class SkillUtils { /** * This is a static utility class, therefore we don't want any instances of @@ -362,6 +364,11 @@ public static int getRepairAndSalvageQuantities(Material itemMaterial, Material */ public static boolean canUseSubskill(Player player, SubSkillType subSkillType) { + requireNonNull(subSkillType, "subSkillType cannot be null"); + // hack to disable supers that aren't coded yet + if(subSkillType == SubSkillType.TRIDENTS_SUPER || subSkillType == SubSkillType.CROSSBOWS_SUPER_SHOTGUN) + return false; + return Permissions.isSubSkillEnabled(player, subSkillType) && RankUtils.hasUnlockedSubskill(player, subSkillType); } } From 9cbe10827f1d55aae72eb5fc00e9e5e5665a050b Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 14 Jan 2024 09:27:04 -0800 Subject: [PATCH 57/75] Buff end game skills --- .../commands/skills/TridentsCommand.java | 30 +++++++++++++++---- src/main/resources/advanced.yml | 8 ++--- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java index 01379aca26..63ec410372 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java @@ -1,16 +1,22 @@ package com.gmail.nossr50.commands.skills; +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.player.UserManager; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; +import org.bukkit.ChatColor; +import org.bukkit.entity.Cat; import org.bukkit.entity.Player; import java.util.ArrayList; import java.util.List; +import static com.gmail.nossr50.datatypes.skills.SubSkillType.*; + public class TridentsCommand extends SkillCommand { @@ -27,15 +33,27 @@ protected void permissionsCheck(Player player) {} @Override protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { List messages = new ArrayList<>(); + McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + if (mmoPlayer == null) { + return messages; + } + + messages.add(ChatColor.DARK_AQUA + "Reminder: " + ChatColor.GOLD + "This is a BETA version of mcMMO, please report any bugs you find!"); + messages.add(ChatColor.GOLD + "Tridents is a " + ChatColor.RED + "WIP" +ChatColor.GOLD + " skill that is still being developed, please leave feedback in our discord!"); + +// if (SkillUtils.canUseSubskill(player, TRIDENTS_SUPER)) { +// messages.add("Tridents Super Ability"); +// //TODO: Implement Tridents Super +// } - if (SkillUtils.canUseSubskill(player, SubSkillType.TRIDENTS_SUPER)) { - messages.add("Tridents Super Ability"); - //TODO: Implement Tridents Super + if(SkillUtils.canUseSubskill(player, TRIDENTS_TRIDENTS_LIMIT_BREAK)) { + messages.add(getStatMessage(TRIDENTS_TRIDENTS_LIMIT_BREAK, + String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, TRIDENTS_TRIDENTS_LIMIT_BREAK, 1000)))); } - if(SkillUtils.canUseSubskill(player, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK)) { - messages.add(getStatMessage(SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK, - String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK, 1000)))); + if(SkillUtils.canUseSubskill(player, TRIDENTS_IMPALE)) { + messages.add(getStatMessage(TRIDENTS_IMPALE, + String.valueOf(mmoPlayer.getTridentsManager().impaleDamageBonus()))); } return messages; diff --git a/src/main/resources/advanced.yml b/src/main/resources/advanced.yml index b5662f2611..fb8d739dcf 100644 --- a/src/main/resources/advanced.yml +++ b/src/main/resources/advanced.yml @@ -265,7 +265,7 @@ Skills: Standard: 100 RetroMode: 1000 VerdantBounty: - ChanceMax: 15.0 + ChanceMax: 50.0 MaxBonusLevel: Standard: 1000 RetroMode: 10000 @@ -293,7 +293,7 @@ Skills: MaxBonusLevel: Standard: 1000 RetroMode: 10000 - ChanceMax: 15.0 + ChanceMax: 50.0 SuperBreaker: AllowTripleDrops: true DoubleDrops: @@ -621,8 +621,8 @@ Skills: # Triple Drops CleanCuts: # ChanceMax: Maximum chance of receiving triple drops (100 = 100%) - # MaxBonusLevel: Level when the maximum chance of receiving double drops is reached - ChanceMax: 15.0 + # MaxBonusLevel: Level when the maximum chance of receiving triple drops is reached + ChanceMax: 50.0 MaxBonusLevel: Standard: 1000 RetroMode: 10000 From efabaf1466cfb32727fa6aaa9f38f0d9b353afa2 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 14 Jan 2024 09:43:30 -0800 Subject: [PATCH 58/75] more work on end game update --- Changelog.txt | 66 ++++++++----------- pom.xml | 2 +- .../com/gmail/nossr50/api/ExperienceAPI.java | 1 - .../commands/skills/CrossbowsCommand.java | 37 ++++++----- .../commands/skills/HerbalismCommand.java | 15 +++-- .../commands/skills/PowerLevelCommand.java | 9 ++- .../nossr50/commands/skills/SkillCommand.java | 6 ++ .../nossr50/datatypes/player/McMMOPlayer.java | 1 - .../datatypes/player/PlayerProfile.java | 5 +- .../nossr50/listeners/CommandListener.java | 40 ----------- .../nossr50/skills/crossbows/Crossbows.java | 1 - .../skills/crossbows/CrossbowsManager.java | 3 - .../com/gmail/nossr50/util/Permissions.java | 13 +++- .../nossr50/util/random/ProbabilityUtil.java | 7 +- .../resources/locale/locale_en_US.properties | 11 +++- 15 files changed, 99 insertions(+), 118 deletions(-) delete mode 100644 src/main/java/com/gmail/nossr50/listeners/CommandListener.java diff --git a/Changelog.txt b/Changelog.txt index 49d3fdc63d..19c98d31cd 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,7 +1,7 @@ Version 2.2.000 + TODO: Add check to archery arrow retrieval to not work for crossbows TODO: More SQL unit tests TODO: Test mysql/mariadb changes - TODO: Trickshot: locale, multiple bounces, does not hurt yourself or allies, reduced damage per bounce? TODO: Add metadata cleanup unit tests TODO: Cleanup new arrow metadatas TODO: com/gmail/nossr50/database/FlatFileDatabaseManager.java:109 reporting data entries that need correction on each launch @@ -10,57 +10,45 @@ Version 2.2.000 TODO: Add unit test to determine crossbow or bow skill TODO: Add unit test for trident xp processing TODO: Add missing entries to changelog - child.yml is gone now, its better this way 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 - (API) 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 Treasure drop rate from Shake, Fishing, Hylian, and Excavation now benefit from the Luck perk Added 'Send_To_Console' settings to chat.yml to toggle sending party or admin chat messages to console - Added a set of "mastery" subskills meant for end game progression - Added the mastery subskill 'Mother Lode' to Mining - Added the mastery subskill 'Clean Cuts' to Woodcutting - Added the mastery subskill 'Verdant Bounty' to Herbalism - All new skills have had settings added to advanced.yml + Added a set of "triple drop" sub skills to a few gathering skills, this is meant for "end game" progression + Added the end game oriented subskill 'Mother Lode' to Mining + Added the end game oriented subskill 'Clean Cuts' to Woodcutting + Added the end game oriented subskill 'Verdant Bounty' to Herbalism + Added Crossbows Skill and various sub skills + Updated advanced.yml with entries for the new skills + (API) 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 Added /mmopower command (aliases /mmopowerlevel /powerlevel) Added 'mcmmo.commands.mmopower' permission node Added 'mcmmo.ability.herbalism.verdantbounty' permission node Added 'mcmmo.ability.mining.motherlode' permission node Added 'mcmmo.ability.woodcutting.cleancuts' permission node - Added 'Mining.SubSkill.MotherLode.Name' to locale - Added 'Mining.SubSkill.MotherLode.Stat' to locale - Added 'Mining.SubSkill.MotherLode.Description' to locale - Added 'Woodcutting.SubSkill.CleanCuts.Name' to locale - Added 'Woodcutting.SubSkill.CleanCuts.Stat' to locale - Added 'Woodcutting.SubSkill.CleanCuts.Description' to locale - Added 'Herbalism.SubSkill.VerdantBounty.Name' to locale - Added 'Herbalism.SubSkill.VerdantBounty.Stat' to locale - Added 'Herbalism.SubSkill.VerdantBounty.Description' to locale - (Codebase) Major rewrite for how random chance was handled in the code - - Added 'General.PowerLevel.Skill_Mastery.Enabled' to config.yml which is used to enable or disable the mastery skills wholesale (will also disable the new power level command) + Added 'mcmmo.commands.crossbows' permission node + Added 'mcmmo.ability.crossbows.supershotgun' permission node + Added 'mcmmo.ability.crossbows.trickshot' permission node + Added 'mcmmo.ability.crossbows.crossbowslimitbreak' permission node + Added 'mcmmo.commands.mmopower' permission node + Added locale entries for motherlode, cleancuts, and verdant bounty + Major rewrite for how random chance was handled in the code + child.yml is gone now, its better this way NOTES: - The goal of this update is to provide a small benefit to each skill and a reason to grind past the "maximum", ideally for a long while. - Most skills have a mastery sub-skill, this mastery subskill provides a small benefit that scales to level 10,000 (or 1,000 for standard) and does not have ranks (other than the initial rank to unlock it) - Mastery skills unlock at level 1000 for RetroMode (the default setting), and 100 for Standard, you can edit this via skillranks.yml - Mastery skills are meant to provide an "end-game" to skills, a reason to continue leveling a skill past its "max". + Crossbows is a WIP skill, and I will add to it in future updates. + Tridents is not ready for this update, so its been disabled for now. + The goal of this update is to provide a small benefit to some skills and a reason to grind past the "maximum", ideally for a long while. + Most skills have an end game oriented sub-skill, these new subskills provide a small benefit 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 end game sub skills unlock at level 1000 for RetroMode (the default setting), and 100 for Standard, you can edit this via skillranks.yml + These new sub skills are meant to provide an "end-game" to skills, a reason to continue leveling a skill past its "max". This system is brand new, it is entirely possible I will completely change, remove, or add more mastery skills in the future. - The section below assumes RetroMode, if you are using Standard mode (1-100) just divide level examples by 10. - - Mastery Skills - Mining / Mother Lode: With default settings, when players hit level 1,000 they will unlock this sub-skill, it will add a 1% chance to get triple drops while mining (this can be edited in advanced.yml), this skill maxes out at 10.0% chance at level 10,000. - This skill respects double drop settings from the config files. - Double drops will only get checked if the Triple Drops fail for players that have Mother Lode unlocked, these two skills do not stack. - - Woodcutting / Clean Cuts: With default settings, when players hit level 1,000 they will unlock this sub-skill, it will add a 1% chance to get triple drops while woodcutting or using Tree Feller (this can be edited in advanced.yml), this skill maxes out at 10.0% chance at level 10,000. - This skill respects double drop settings from the config files. - Double Drops (Harvest Lumber) will only get checked if the Triple Drops fail for players that have Clean Cuts unlocked, these two skills do not stack. + More info for Mother Lode, Clean Cuts, Verdant Bounty: + These skill respects double drop settings from config.yml just like the Double Drop skills do + Double Drops and Triple Drops do not stack, mcMMO checks for triple drops first, then double drops + New Power Level Command, for now this skill just shows you your current power level. This might be removed later. + Currently these skills scale up to a maximum 50% chance if a player has 10,000 skill, you can adjust this in advanced.yml - Herbalism / Verdant Bounty: With default settings, when players hit level 1,000 they will unlock this sub-skill, it will add a 1% chance to get triple drops when harvesting crops (this can be edited in advanced.yml), this skill maxes out at 10.0% chance at level 10,000. - This skill respects double drop settings from the config files. - Double Drops only occur if the Triple Drops fail, these two skills do not stack. - New Power Level Command - This power level command gives you a view of all your current masteries, it also provides a summary of your power level. Version 2.1.227 Fixed bug where some text would not be displayed to players (Adventure dependency update) diff --git a/pom.xml b/pom.xml index 7397f69392..82b20119ba 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.2.000-BETA-SNAPSHOT + 2.2.000-BETA-01-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java index 37b895db92..c626810ece 100644 --- a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java +++ b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java @@ -19,7 +19,6 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; -import java.util.Set; import java.util.UUID; public final class ExperienceAPI { diff --git a/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java index 11cdb67a53..97bfcbc644 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java @@ -2,26 +2,24 @@ 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.locale.LocaleLoader; -import com.gmail.nossr50.skills.archery.Archery; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; -import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; +import org.bukkit.ChatColor; import org.bukkit.entity.Player; import java.util.ArrayList; import java.util.List; +import static com.gmail.nossr50.datatypes.skills.SubSkillType.*; + public class CrossbowsCommand extends SkillCommand { private boolean canSSG; private boolean canTrickShot; private boolean canPoweredShot; - private int bounceCount; public CrossbowsCommand() { super(PrimarySkillType.CROSSBOWS); @@ -34,13 +32,13 @@ protected void dataCalculations(Player player, float skillValue) { @Override protected void permissionsCheck(Player player) { - canSSG = RankUtils.hasUnlockedSubskill(player, SubSkillType.CROSSBOWS_SUPER_SHOTGUN) - && Permissions.superShotgun(player); +// canSSG = RankUtils.hasUnlockedSubskill(player, CROSSBOWS_SUPER_SHOTGUN) +// && Permissions.superShotgun(player); - canTrickShot = RankUtils.hasUnlockedSubskill(player, SubSkillType.CROSSBOWS_TRICK_SHOT) + canTrickShot = RankUtils.hasUnlockedSubskill(player, CROSSBOWS_TRICK_SHOT) && Permissions.trickShot(player); - canPoweredShot = RankUtils.hasUnlockedSubskill(player, SubSkillType.CROSSBOWS_POWERED_SHOT) + canPoweredShot = RankUtils.hasUnlockedSubskill(player, CROSSBOWS_POWERED_SHOT) && Permissions.poweredShot(player); } @@ -53,23 +51,26 @@ protected List statsDisplay(Player player, float skillValue, boolean has return messages; } + messages.add(ChatColor.DARK_AQUA + "Reminder: " + ChatColor.GOLD + "This is a BETA version of mcMMO, please report any bugs you find!"); + messages.add(ChatColor.GOLD + "Crossbows is a " + ChatColor.RED + "WIP" +ChatColor.GOLD + " skill that is still being developed, please leave feedback in our discord!"); + if (canPoweredShot) { - messages.add(getStatMessage(SubSkillType.ARCHERY_SKILL_SHOT, percent.format(mmoPlayer.getCrossbowsManager().getDamageBonusPercent(player)))); + messages.add(getStatMessage(ARCHERY_SKILL_SHOT, percent.format(mmoPlayer.getCrossbowsManager().getDamageBonusPercent(player)))); } - if (canSSG) { - messages.add("Super Shotgun"); - //TODO: Implement SSG - } +// if (canSSG) { +// messages.add("Super Shotgun"); +// //TODO: Implement SSG +// } if (canTrickShot) { - messages.add(getStatMessage(SubSkillType.CROSSBOWS_TRICK_SHOT, + messages.add(getStatMessage(CROSSBOWS_TRICK_SHOT, String.valueOf(mmoPlayer.getCrossbowsManager().getTrickShotMaxBounceCount()))); } - if(Permissions.canUseSubSkill(player, SubSkillType.CROSSBOWS_CROSSBOWS_LIMIT_BREAK)) { - messages.add(getStatMessage(SubSkillType.CROSSBOWS_CROSSBOWS_LIMIT_BREAK, - String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, SubSkillType.CROSSBOWS_CROSSBOWS_LIMIT_BREAK, 1000)))); + if(Permissions.canUseSubSkill(player, CROSSBOWS_CROSSBOWS_LIMIT_BREAK)) { + messages.add(getStatMessage(CROSSBOWS_CROSSBOWS_LIMIT_BREAK, + String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, CROSSBOWS_CROSSBOWS_LIMIT_BREAK, 1000)))); } return messages; diff --git a/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java index eeb1bdd59f..8bb236d391 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java @@ -24,6 +24,8 @@ public class HerbalismCommand extends SkillCommand { private int farmersDietRank; private String doubleDropChance; private String doubleDropChanceLucky; + private String tripleDropChance; + private String tripleDropChanceLucky; private String hylianLuckChance; private String hylianLuckChanceLucky; private String shroomThumbChance; @@ -54,8 +56,8 @@ protected void dataCalculations(Player player, float skillValue) { if (canTripleDrop) { String[] tripleDropStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.HERBALISM_VERDANT_BOUNTY); - doubleDropChance = tripleDropStrings[0]; - doubleDropChanceLucky = tripleDropStrings[1]; + tripleDropChance = tripleDropStrings[0]; + tripleDropChanceLucky = tripleDropStrings[1]; } // FARMERS DIET @@ -113,11 +115,16 @@ protected List statsDisplay(Player player, float skillValue, boolean has messages.add(getStatMessage(SubSkillType.HERBALISM_DOUBLE_DROPS, doubleDropChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", doubleDropChanceLucky) : "")); } - + + if (canTripleDrop) { + messages.add(getStatMessage(SubSkillType.HERBALISM_VERDANT_BOUNTY, tripleDropChance) + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", tripleDropChanceLucky) : "")); + } + if (canFarmersDiet) { messages.add(getStatMessage(false, true, SubSkillType.HERBALISM_FARMERS_DIET, String.valueOf(farmersDietRank))); } - + if (canGreenTerra) { messages.add(getStatMessage(SubSkillType.HERBALISM_GREEN_TERRA, greenTerraLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", greenTerraLengthEndurance) : "")); diff --git a/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java index 42e9a2c13f..6b99e1fa27 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java @@ -10,6 +10,7 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.player.UserManager; +import org.bukkit.ChatColor; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -28,14 +29,18 @@ public void processCommand(String[] args) { BukkitCommandIssuer bukkitCommandIssuer = (BukkitCommandIssuer) getCurrentCommandIssuer(); Player player = bukkitCommandIssuer.getPlayer(); McMMOPlayer mmoPlayer = UserManager.getPlayer(player); //Should never be null at this point because its caught in an ACF validation + if (mmoPlayer == null) { + return; + } + int powerLevel = mmoPlayer.getPowerLevel(); //TODO: impl - mmoPlayer.getPlayer().sendMessage("Your power level is: "+powerLevel); //This is not gonna stay, just to show that the command executes in debug + mmoPlayer.getPlayer().sendMessage(ChatColor.DARK_AQUA + "Your " + ChatColor.GOLD + "[mcMMO]" + ChatColor.DARK_AQUA + " power level is: " + ChatColor.GREEN + powerLevel); //This is not gonna stay, just to show that the command executes in debug //Send the players a few blank lines to make finding the top of the skill command easier if (mcMMO.p.getAdvancedConfig().doesSkillCommandSendBlankLines()) { - for (int i = 0; i < 2; i++) { + for (int i = 0; i < 1; i++) { player.sendMessage(""); } } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java index 61b2f7ae43..d48a6608d2 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java @@ -62,6 +62,12 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command return true; } + // Tridents skill is not ready yet + if (skill == PrimarySkillType.TRIDENTS) { + sender.sendMessage(ChatColor.RED + "Tridents will come in a future version!"); + return true; + } + if (args.length == 0) { boolean isLucky = Permissions.lucky(player, skill); boolean hasEndurance = PerksUtils.handleActivationPerks(player, 0, 0) != 0; diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index a89e9bab02..bfb441c0f3 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -69,7 +69,6 @@ import java.util.EnumMap; import java.util.Map; -import java.util.Set; import java.util.UUID; public class McMMOPlayer implements Identified { diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java index 74c15a27df..71abb64181 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java @@ -14,7 +14,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.EnumMap; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; import java.util.concurrent.DelayQueue; public class PlayerProfile { diff --git a/src/main/java/com/gmail/nossr50/listeners/CommandListener.java b/src/main/java/com/gmail/nossr50/listeners/CommandListener.java deleted file mode 100644 index 484faa5bb3..0000000000 --- a/src/main/java/com/gmail/nossr50/listeners/CommandListener.java +++ /dev/null @@ -1,40 +0,0 @@ -//package com.gmail.nossr50.listeners; -// -//import com.gmail.nossr50.datatypes.player.McMMOPlayer; -//import com.gmail.nossr50.datatypes.skills.SuperAbilityType; -//import com.gmail.nossr50.mcMMO; -//import com.gmail.nossr50.util.player.UserManager; -//import com.gmail.nossr50.util.skills.SkillUtils; -//import org.bukkit.Bukkit; -//import org.bukkit.entity.Player; -//import org.bukkit.event.EventHandler; -//import org.bukkit.event.EventPriority; -//import org.bukkit.event.Listener; -//import org.bukkit.event.player.PlayerCommandPreprocessEvent; -// -//public class CommandListener implements Listener { -// -// private final mcMMO pluginRef; -// -// public CommandListener(mcMMO plugin) { -// this.pluginRef = plugin; -// } -// -// @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) -// public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { -// Player player = event.getPlayer(); -// -// SkillUtils.removeAbilityBoostsFromInventory(player); -// -// McMMOPlayer mmoPlayer = UserManager.getPlayer(player); -// -// if(mmoPlayer == null) -// return; -// -// Bukkit.getServer().getScheduler().runTaskLater(pluginRef, () -> { -// if(mmoPlayer.getAbilityMode(SuperAbilityType.GIGA_DRILL_BREAKER) || mmoPlayer.getAbilityMode(SuperAbilityType.SUPER_BREAKER)) { -// SkillUtils.handleAbilitySpeedIncrease(player); -// } -// }, 5); -// } -//} diff --git a/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java b/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java index 35f9aa2aa9..33604948ef 100644 --- a/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java +++ b/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.skills.crossbows; import com.gmail.nossr50.datatypes.player.McMMOPlayer; -import com.gmail.nossr50.util.MetadataConstants; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.entity.Arrow; import org.bukkit.entity.Player; diff --git a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java index 54fdf4849b..a7e9ae508f 100644 --- a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java @@ -11,7 +11,6 @@ import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.RankUtils; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Arrow; import org.bukkit.entity.Player; @@ -21,8 +20,6 @@ import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; -import static com.gmail.nossr50.util.random.ProbabilityUtil.isStaticSkillRNGSuccessful; - public class CrossbowsManager extends SkillManager { public CrossbowsManager(McMMOPlayer mmoPlayer) { super(mmoPlayer, PrimarySkillType.CROSSBOWS); diff --git a/src/main/java/com/gmail/nossr50/util/Permissions.java b/src/main/java/com/gmail/nossr50/util/Permissions.java index 5e0eef63ca..fbc39f32b1 100644 --- a/src/main/java/com/gmail/nossr50/util/Permissions.java +++ b/src/main/java/com/gmail/nossr50/util/Permissions.java @@ -166,7 +166,14 @@ public static boolean customXpBoost(Permissible permissible, PrimarySkillType sk * SKILLS */ - public static boolean skillEnabled(Permissible permissible, PrimarySkillType skill) {return permissible.hasPermission("mcmmo.skills." + skill.toString().toLowerCase(Locale.ENGLISH)); } + public static boolean skillEnabled(Permissible permissible, PrimarySkillType skill) { + // hack to disable tridents for now + if (skill == PrimarySkillType.TRIDENTS) + return false; + + return permissible.hasPermission("mcmmo.skills." + skill.toString().toLowerCase(Locale.ENGLISH)); + } + public static boolean vanillaXpBoost(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.ability." + skill.toString().toLowerCase(Locale.ENGLISH) + ".vanillaxpboost"); } public static boolean isSubSkillEnabled(Permissible permissible, SubSkillType subSkillType) { // hack to disable supers that aren't coded yet @@ -286,6 +293,10 @@ private static void addDynamicPermission(String permissionName, PermissionDefaul * @return true if the player has permission and has the skill unlocked */ public static boolean canUseSubSkill(@NotNull Player player, @NotNull SubSkillType subSkillType) { + // Hack to disable tridents for now + if (subSkillType.getParentSkill() == PrimarySkillType.TRIDENTS) + return false; + return isSubSkillEnabled(player, subSkillType) && RankUtils.hasUnlockedSubskill(player, subSkillType); } } diff --git a/src/main/java/com/gmail/nossr50/util/random/ProbabilityUtil.java b/src/main/java/com/gmail/nossr50/util/random/ProbabilityUtil.java index ba3ce84e14..bc757506c7 100644 --- a/src/main/java/com/gmail/nossr50/util/random/ProbabilityUtil.java +++ b/src/main/java/com/gmail/nossr50/util/random/ProbabilityUtil.java @@ -84,11 +84,10 @@ static SkillProbabilityType getProbabilityType(@NotNull SubSkillType subSkillTyp if (player != null) { McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - if(mmoPlayer != null) { - xPos = mmoPlayer.getSkillLevel(subSkillType.getParentSkill()); - } else { - xPos = 0; + if (mmoPlayer == null) { + return Probability.ofPercent(0); } + xPos = mmoPlayer.getSkillLevel(subSkillType.getParentSkill()); } else { xPos = 0; } diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index b56bf20f43..692914b355 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -440,7 +440,7 @@ Crossbows.SubSkill.CrossbowsLimitBreak.Description=Breaking your limits. Increas Crossbows.SubSkill.CrossbowsLimitBreak.Stat=Limit Break Max DMG Crossbows.SubSkill.TrickShot.Name=Trick Shot Crossbows.SubSkill.TrickShot.Description=Richochet arrows with steep angles -Crossbows.SubSkill.TrickShot.Stat=Trick Shot Chance +Crossbows.SubSkill.TrickShot.Stat=Trick Shot Max Bounces Crossbows.SubSkill.TrickShot.Stat.Extra=Trick Shot Max Bounces: &a{0} Crossbows.SubSkill.TrickShot.Stat.Extra2=Trick Shot Reduced DMG per Bounce: &a{0} Crossbows.Listener=Crossbows: @@ -454,7 +454,7 @@ Tridents.Skills.TA.Other.On=&a{0}&2 used Trident &Super! Tridents.SubSkill.SuperAbility.Name=Tridents Super Ability Tridents.SubSkill.SuperAbility.Description=N/A Tridents.SubSkill.SuperAbility.Stat=N/A -Trients.SubSkill.Impale.Name=Impale +Tridents.SubSkill.Impale.Name=Impale Tridents.SubSkill.Impale.Description=Increases damage done with tridents Tridents.SubSkill.Impale.Stat=Impale Bonus Damage Tridents.SubSkill.TridentsLimitBreak.Name=Tridents Limit Break @@ -1033,6 +1033,13 @@ Guides.Woodcutting.Section.0=&3About Woodcutting:\n&eWoodcutting is all about ch Guides.Woodcutting.Section.1=&3How does Tree Feller work?\n&eTree Feller is an active ability, you can right-click\n&ewhile holding an ax to activate Tree Feller. This will\n&ecause the entire tree to break instantly, dropping all\n&eof its logs at once. Guides.Woodcutting.Section.2=&3How does Leaf Blower work?\n&eLeaf Blower is a passive ability that will cause leaf\n&eblocks to break instantly when hit with an axe. By default,\nðis ability unlocks at level 100. Guides.Woodcutting.Section.3=&3How do Double Drops work?\n&eThis passive ability gives you a chance to obtain an extra\n&eblock for every log you chop. +# Crossbows +Guides.Crossbows.Section.0=&3About Crossbows:\n&eCrossbows is all about shooting with your crossbow.\n\n&3XP GAIN:\n&eXP is gained whenever you shoot mobs with a crossbow. +Guides.Crossbows.Section.1=&3How does Trickshot work?\n&eTrickshot is an passive ability, you shoot your bolts at a shallow angle with a crossbow to attempt a Trickshot. This will cause the arrow to ricochet off of blocks and potentially hit a target. The number of potential bounces from a ricochet depend on the rank of Trickshot. +# Tridents +Guides.Tridents.Section.0=&3About Tridents:\n&eTridents skill involves impaling foes with your trident.\n\n&3XP GAIN:\n&eXP is gained whenever you hit mobs with a trident. + + #INSPECT Inspect.Offline= &cYou do not have permission to inspect offline players! Inspect.OfflineStats=mcMMO Stats for Offline Player &e{0} From 33cad7c2f112904aa3ede917f4d9e0050f7daea4 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 14 Jan 2024 09:45:40 -0800 Subject: [PATCH 59/75] typos --- Changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changelog.txt b/Changelog.txt index 19c98d31cd..0d809d772f 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -44,7 +44,7 @@ Version 2.2.000 This system is brand new, it is entirely possible I will completely change, remove, or add more mastery skills in the future. More info for Mother Lode, Clean Cuts, Verdant Bounty: - These skill respects double drop settings from config.yml just like the Double Drop skills do + These skills respect double drop settings from config.yml just like the Double Drop skills do Double Drops and Triple Drops do not stack, mcMMO checks for triple drops first, then double drops New Power Level Command, for now this skill just shows you your current power level. This might be removed later. Currently these skills scale up to a maximum 50% chance if a player has 10,000 skill, you can adjust this in advanced.yml From 009d809d761eb0db74672c1d4010c6e039c40cc9 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 15 Jan 2024 10:19:03 -0800 Subject: [PATCH 60/75] Fix bug with Excavation drop rate and misc mysql changes --- pom.xml | 2 +- .../nossr50/database/SQLDatabaseManager.java | 59 ++++----- .../nossr50/datatypes/treasure/Treasure.java | 4 +- .../skills/excavation/ExcavationManager.java | 39 ++++-- .../skills/excavation/ExcavationTest.java | 120 ++++++++++++++++++ 5 files changed, 178 insertions(+), 46 deletions(-) create mode 100644 src/test/java/com/gmail/nossr50/skills/excavation/ExcavationTest.java diff --git a/pom.xml b/pom.xml index 82b20119ba..ae782333e7 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.2.000-BETA-01-SNAPSHOT + 2.2.000-BETA-02-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index 4a77ff1fcf..dfc7c843c6 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -233,7 +233,7 @@ public boolean removeUser(String playerName, UUID uuid) { "JOIN " + tablePrefix + "huds h ON (u.id = h.user_id) " + "JOIN " + tablePrefix + "skills s ON (u.id = s.user_id) " + "JOIN " + tablePrefix + "cooldowns c ON (u.id = c.user_id) " + - "WHERE u.`USER` = ?"); + "WHERE u.`user` = ?"); statement.setString(1, playerName); @@ -402,7 +402,6 @@ public boolean saveUser(PlayerProfile profile) { throw new InvalidSkillException("A plugin hooking into mcMMO that you are using is attempting to read leaderboard skills for child skills, child skills do not have leaderboards! This is NOT an mcMMO error!"); } - String query = skill == null ? ALL_QUERY_VERSION : skill.name().toLowerCase(Locale.ENGLISH); ResultSet resultSet = null; PreparedStatement statement = null; @@ -410,7 +409,7 @@ public boolean saveUser(PlayerProfile profile) { try { connection = getConnection(PoolIdentifier.MISC); - statement = connection.prepareStatement("SELECT " + query + ", `USER` FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON (user_id = id) WHERE " + query + " > 0 AND NOT `USER` = '\\_INVALID\\_OLD\\_USERNAME\\_' ORDER BY " + query + " DESC, `USER` LIMIT ?, ?"); + statement = connection.prepareStatement("SELECT " + query + ", `user` FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON (user_id = id) WHERE " + query + " > 0 AND NOT `user` = '\\_INVALID\\_OLD\\_USERNAME\\_' ORDER BY " + query + " DESC, `user` LIMIT ?, ?"); statement.setInt(1, (pageNumber * statsPerPage) - statsPerPage); statement.setInt(2, statsPerPage); resultSet = statement.executeQuery(); @@ -451,7 +450,7 @@ public Map readRank(String playerName) { // Get count of all users with higher skill level than player String sql = "SELECT COUNT(*) AS 'rank' FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE " + skillName + " > 0 " + "AND " + skillName + " > (SELECT " + skillName + " FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " + - "WHERE `USER` = ?)"; + "WHERE `user` = ?)"; statement = connection.prepareStatement(sql); statement.setString(1, playerName); @@ -464,7 +463,7 @@ public Map readRank(String playerName) { // Ties are settled by alphabetical order sql = "SELECT user, " + skillName + " FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE " + skillName + " > 0 " + "AND " + skillName + " = (SELECT " + skillName + " FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " + - "WHERE `USER` = '" + playerName + "') ORDER BY user"; + "WHERE `user` = '" + playerName + "') ORDER BY user"; resultSet.close(); statement.close(); @@ -487,7 +486,7 @@ public Map readRank(String playerName) { "WHERE " + ALL_QUERY_VERSION + " > 0 " + "AND " + ALL_QUERY_VERSION + " > " + "(SELECT " + ALL_QUERY_VERSION + " " + - "FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE `USER` = ?)"; + "FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE `user` = ?)"; statement = connection.prepareStatement(sql); statement.setString(1, playerName); @@ -505,7 +504,7 @@ public Map readRank(String playerName) { "WHERE " + ALL_QUERY_VERSION + " > 0 " + "AND " + ALL_QUERY_VERSION + " = " + "(SELECT " + ALL_QUERY_VERSION + " " + - "FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE `USER` = ?) ORDER BY user"; + "FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE `user` = ?) ORDER BY user"; statement = connection.prepareStatement(sql); statement.setString(1, playerName); @@ -573,8 +572,8 @@ private int newUser(Connection connection, String playerName, UUID uuid) { try { statement = connection.prepareStatement( "UPDATE `" + tablePrefix + "users` " - + "SET `USER` = ? " - + "WHERE `USER` = ?"); + + "SET `user` = ? " + + "WHERE `user` = ?"); statement.setString(1, "_INVALID_OLD_USERNAME_"); statement.setString(2, playerName); statement.executeUpdate(); @@ -632,7 +631,6 @@ private int newUser(Connection connection, String playerName, UUID uuid) { return loadPlayerFromDB(uuid, null); } - private PlayerProfile loadPlayerFromDB(@Nullable UUID uuid, @Nullable String playerName) throws RuntimeException { if(uuid == null && playerName == null) { throw new RuntimeException("Error looking up player, both UUID and playerName are null and one must not be."); @@ -655,22 +653,21 @@ private PlayerProfile loadPlayerFromDB(@Nullable UUID uuid, @Nullable String pla statement = connection.prepareStatement( "SELECT " + - "S.TAMING, S.MINING, S.REPAIR, S.WOODCUTTING, S.UNARMED, S.HERBALISM, S.EXCAVATION, S.ARCHERY, S.SWORDS, S.AXES, S.ACROBATICS, S.FISHING, S.ALCHEMY, S.CROSSBOWS, S.TRIDENTS, " + - "E.TAMING, E.MINING, E.REPAIR, E.WOODCUTTING, E.UNARMED, E.HERBALISM, E.EXCAVATION, E.ARCHERY, E.SWORDS, E.AXES, E.ACROBATICS, E.FISHING, E.ALCHEMY, E.CROSSBOWS, E.TRIDENTS, " + - "C.TAMING, C.MINING, C.REPAIR, C.WOODCUTTING, C.UNARMED, C.HERBALISM, C.EXCAVATION, C.ARCHERY, C.SWORDS, C.AXES, C.ACROBATICS, C.BLAST_MINING, C.CHIMAERA_WING, C.CROSSBOWS, C.TRIDENTS, " + - "H.MOBHEALTHBAR, H.SCOREBOARDTIPS, U.UUID, U.`USER` " + - "FROM " + tablePrefix + "USERS U " + - "JOIN " + tablePrefix + "SKILLS S ON U.ID = S.USER_ID " + - "JOIN " + tablePrefix + "EXPERIENCE E ON U.ID = E.USER_ID " + - "JOIN " + tablePrefix + "COOLDOWNS C ON U.ID = C.USER_ID " + - "JOIN " + tablePrefix + "HUDS H ON U.ID = H.USER_ID " + - "WHERE U.ID = ?" + "s.taming, s.mining, s.repair, s.woodcutting, s.unarmed, s.herbalism, s.excavation, s.archery, s.swords, s.axes, s.acrobatics, s.fishing, s.alchemy, s.crossbows, s.tridents, " + + "e.taming, e.mining, e.repair, e.woodcutting, e.unarmed, e.herbalism, e.excavation, e.archery, e.swords, e.axes, e.acrobatics, e.fishing, e.alchemy, e.crossbows, e.tridents, " + + "c.taming, c.mining, c.repair, c.woodcutting, c.unarmed, c.herbalism, c.excavation, c.archery, c.swords, c.axes, c.acrobatics, c.blast_mining, c.chimaera_wing, c.crossbows, c.tridents, " + + "h.mobhealthbar, h.scoreboardtips, u.uuid, u.`user` " + + "FROM " + tablePrefix + "users u " + + "JOIN " + tablePrefix + "skills s ON (u.id = s.user_id) " + + "JOIN " + tablePrefix + "experience e ON (u.id = e.user_id) " + + "JOIN " + tablePrefix + "cooldowns c ON (u.id = c.user_id) " + + "JOIN " + tablePrefix + "huds h ON (u.id = h.user_id) " + + "WHERE u.id = ?" ); statement.setInt(1, id); resultSet = statement.executeQuery(); - if (resultSet.next()) { try { PlayerProfile profile = loadFromResult(playerName, resultSet); @@ -684,15 +681,15 @@ private PlayerProfile loadPlayerFromDB(@Nullable UUID uuid, @Nullable String pla && uuid != null) { statement = connection.prepareStatement( "UPDATE `" + tablePrefix + "users` " - + "SET `USER` = ? " - + "WHERE `USER` = ?"); + + "SET `user` = ? " + + "WHERE `user` = ?"); statement.setString(1, "_INVALID_OLD_USERNAME_"); statement.setString(2, name); statement.executeUpdate(); statement.close(); statement = connection.prepareStatement( "UPDATE `" + tablePrefix + "users` " - + "SET `USER` = ?, uuid = ? " + + "SET `user` = ?, uuid = ? " + "WHERE id = ?"); statement.setString(1, playerName); statement.setString(2, uuid.toString()); @@ -740,7 +737,7 @@ public void convertUsers(DatabaseManager destination) { + "JOIN " + tablePrefix + "experience e ON (u.id = e.user_id) " + "JOIN " + tablePrefix + "cooldowns c ON (u.id = c.user_id) " + "JOIN " + tablePrefix + "huds h ON (u.id = h.user_id) " - + "WHERE u.`USER` = ?"); + + "WHERE u.`user` = ?"); List usernames = getStoredUsers(); int convertedUsers = 0; long startMillis = System.currentTimeMillis(); @@ -779,7 +776,7 @@ public boolean saveUserUUID(String userName, UUID uuid) { connection = getConnection(PoolIdentifier.MISC); statement = connection.prepareStatement( "UPDATE `" + tablePrefix + "users` SET " - + " uuid = ? WHERE `USER` = ?"); + + " uuid = ? WHERE `user` = ?"); statement.setString(1, uuid.toString()); statement.setString(2, userName); statement.execute(); @@ -803,7 +800,7 @@ public boolean saveUserUUIDs(Map fetchedUUIDs) { try { connection = getConnection(PoolIdentifier.MISC); - statement = connection.prepareStatement("UPDATE " + tablePrefix + "users SET uuid = ? WHERE `USER` = ?"); + statement = connection.prepareStatement("UPDATE " + tablePrefix + "users SET uuid = ? WHERE `user` = ?"); for (Map.Entry entry : fetchedUUIDs.entrySet()) { statement.setString(1, entry.getValue().toString()); @@ -845,7 +842,7 @@ public List getStoredUsers() { try { connection = getConnection(PoolIdentifier.MISC); statement = connection.createStatement(); - resultSet = statement.executeQuery("SELECT `USER` FROM " + tablePrefix + "users"); + resultSet = statement.executeQuery("SELECT `user` FROM " + tablePrefix + "users"); while (resultSet.next()) { users.add(resultSet.getString("user")); } @@ -1604,7 +1601,7 @@ private int getUserID(final Connection connection, final String playerName, fina PreparedStatement statement = null; try { - statement = connection.prepareStatement("SELECT id, `USER` FROM " + tablePrefix + "users WHERE uuid = ? OR (uuid IS NULL AND `USER` = ?)"); + statement = connection.prepareStatement("SELECT id, `user` FROM " + tablePrefix + "users WHERE uuid = ? OR (uuid IS NULL AND `user` = ?)"); statement.setString(1, uuid.toString()); statement.setString(2, playerName); resultSet = statement.executeQuery(); @@ -1633,7 +1630,7 @@ private int getUserIDByName(final Connection connection, final String playerName PreparedStatement statement = null; try { - statement = connection.prepareStatement("SELECT id, `USER` FROM " + tablePrefix + "users WHERE `USER` = ?"); + statement = connection.prepareStatement("SELECT id, `user` FROM " + tablePrefix + "users WHERE `user` = ?"); statement.setString(1, playerName); resultSet = statement.executeQuery(); @@ -1734,7 +1731,7 @@ The following columns were set to use latin1 historically (now utf8mb4) private String getUpdateUserInUsersTableSQLQuery() { return "ALTER TABLE\n" + " " + tablePrefix + "users\n" + - " CHANGE `USER` user\n" + + " CHANGE `user` user\n" + " " + USER_VARCHAR + "\n" + " CHARACTER SET utf8mb4\n" + " COLLATE utf8mb4_unicode_ci;"; diff --git a/src/main/java/com/gmail/nossr50/datatypes/treasure/Treasure.java b/src/main/java/com/gmail/nossr50/datatypes/treasure/Treasure.java index 78b1adef04..659a94fc17 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/treasure/Treasure.java +++ b/src/main/java/com/gmail/nossr50/datatypes/treasure/Treasure.java @@ -16,7 +16,7 @@ public Treasure(ItemStack drop, int xp, double dropChance, int dropLevel) { this.drop = drop; this.xp = xp; this.dropChance = dropChance; - this.dropProbability = Probability.ofPercent(dropChance / 100); + this.dropProbability = Probability.ofPercent(dropChance); this.dropLevel = dropLevel; } @@ -46,7 +46,7 @@ public double getDropChance() { public void setDropChance(double dropChance) { this.dropChance = dropChance; - this.dropProbability = Probability.ofPercent(dropChance / 100); + this.dropProbability = Probability.ofPercent(dropChance); } public int getDropLevel() { diff --git a/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java b/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java index b487553f8e..bc9120e12f 100644 --- a/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java +++ b/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java @@ -2,6 +2,7 @@ import com.gmail.nossr50.api.ItemSpawnReason; import com.gmail.nossr50.datatypes.experience.XPGainReason; +import com.gmail.nossr50.datatypes.experience.XPGainSource; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; @@ -16,9 +17,13 @@ import org.bukkit.Location; import org.bukkit.block.BlockState; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.VisibleForTesting; import java.util.List; +import static java.util.Objects.requireNonNull; + public class ExcavationManager extends SkillManager { public ExcavationManager(McMMOPlayer mcMMOPlayer) { super(mcMMOPlayer, PrimarySkillType.EXCAVATION); @@ -30,10 +35,9 @@ public ExcavationManager(McMMOPlayer mcMMOPlayer) { * @param blockState The {@link BlockState} to check ability activation for */ public void excavationBlockCheck(BlockState blockState) { - int xp = Excavation.getBlockXP(blockState); - + requireNonNull(blockState, "excavationBlockCheck: blockState cannot be null"); if (Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.EXCAVATION_ARCHAEOLOGY)) { - List treasures = Excavation.getTreasures(blockState); + List treasures = getTreasures(blockState); if (!treasures.isEmpty()) { int skillLevel = getSkillLevel(); @@ -42,20 +46,31 @@ public void excavationBlockCheck(BlockState blockState) { for (ExcavationTreasure treasure : treasures) { if (skillLevel >= treasure.getDropLevel() && ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.EXCAVATION, getPlayer(), treasure.getDropProbability())) { - - //Spawn Vanilla XP orbs if a dice roll succeeds - if(ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.EXCAVATION, getPlayer(), getArchaelogyExperienceOrbChance())) { - Misc.spawnExperienceOrb(location, getExperienceOrbsReward()); - } - - xp += treasure.getXp(); - Misc.spawnItem(getPlayer(), location, treasure.getDrop(), ItemSpawnReason.EXCAVATION_TREASURE); + processExcavationBonusesOnBlock(blockState, treasure, location); } } } } + } + + @VisibleForTesting + public List getTreasures(@NotNull BlockState blockState) { + requireNonNull(blockState, "blockState cannot be null"); + return Excavation.getTreasures(blockState); + } + + @VisibleForTesting + public void processExcavationBonusesOnBlock(BlockState blockState, ExcavationTreasure treasure, Location location) { + int xp = Excavation.getBlockXP(blockState); + + //Spawn Vanilla XP orbs if a dice roll succeeds + if(ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.EXCAVATION, getPlayer(), getArchaelogyExperienceOrbChance())) { + Misc.spawnExperienceOrb(location, getExperienceOrbsReward()); + } - applyXpGain(xp, XPGainReason.PVE); + xp += treasure.getXp(); + Misc.spawnItem(getPlayer(), location, treasure.getDrop(), ItemSpawnReason.EXCAVATION_TREASURE); + applyXpGain(xp, XPGainReason.PVE, XPGainSource.SELF); } public int getExperienceOrbsReward() { diff --git a/src/test/java/com/gmail/nossr50/skills/excavation/ExcavationTest.java b/src/test/java/com/gmail/nossr50/skills/excavation/ExcavationTest.java new file mode 100644 index 0000000000..631696f0a9 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/skills/excavation/ExcavationTest.java @@ -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 getGuaranteedTreasureDrops() { + List treasures = new ArrayList<>();; + treasures.add(new ExcavationTreasure(new ItemStack(Material.CAKE), 1, 100, 1)); + return treasures; + } + + private List getImpossibleTreasureDrops() { + List treasures = new ArrayList<>();; + treasures.add(new ExcavationTreasure(new ItemStack(Material.CAKE), 1, 0, 1)); + return treasures; + } +} From dda5b45bb1f08ab1f895261767eae18c2f81e4e8 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 15 Jan 2024 10:21:30 -0800 Subject: [PATCH 61/75] improve SQL exceptions to be more easily debuggable --- .../com/gmail/nossr50/database/SQLDatabaseManager.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index dfc7c843c6..64aeab1ad6 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -129,7 +129,6 @@ public final class SQLDatabaseManager implements DatabaseManager { loadPool = new DataSource(poolProperties); checkStructure(); - } @NotNull @@ -1272,13 +1271,7 @@ private PlayerProfile loadFromResult(String playerName, ResultSet result) throws } private void printErrors(SQLException ex) { - if (debug || h2) { - ex.printStackTrace(); - } else { - for (StackTraceElement element : ex.getStackTrace()) { - logger.severe("Location: " + element.getClassName() + " " + element.getMethodName() + " " + element.getLineNumber()); - } - } + ex.printStackTrace(); // logger.severe("SQLException: " + ex.getMessage()); logger.severe("SQLState: " + ex.getSQLState()); From 377bf1be4d0e0ac2e75d2fd88caedb8de5fd2a7a Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 15 Jan 2024 10:47:45 -0800 Subject: [PATCH 62/75] Tree Feller non-wood drop rate reduced by 90% --- Changelog.txt | 1 + pom.xml | 2 +- .../woodcutting/WoodcuttingManager.java | 8 +-- .../com/gmail/nossr50/MMOTestEnvironment.java | 55 ++++++++++--------- 4 files changed, 36 insertions(+), 30 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 0d809d772f..4b4411717a 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -10,6 +10,7 @@ Version 2.2.000 TODO: Add unit test to determine crossbow or bow skill TODO: Add unit test for trident xp processing TODO: Add missing entries to changelog + Tree Feller now drops 90% less non-wood blocks (leaves/etc) on average 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 Treasure drop rate from Shake, Fishing, Hylian, and Excavation now benefit from the Luck perk Added 'Send_To_Console' settings to chat.yml to toggle sending party or admin chat messages to console diff --git a/pom.xml b/pom.xml index ae782333e7..7cc845fe91 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.2.000-BETA-02-SNAPSHOT + 2.2.000-BETA-04-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java index 403f23a970..2c7d9f72cc 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java @@ -34,6 +34,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; //TODO: Seems to not be using the item drop event for bonus drops, may want to change that.. or may not be able to be changed? public class WoodcuttingManager extends SkillManager { @@ -323,10 +324,7 @@ private void dropTreeFellerLootFromBlocks(@NotNull Set treeFellerBlo processBonusDropCheck(blockState); } else if (BlockUtils.isNonWoodPartOfTree(blockState)) { //Drop displaced non-woodcutting XP blocks - if(RankUtils.hasUnlockedSubskill(player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) { - Misc.spawnItemsFromCollection(getPlayer(), Misc.getBlockCenter(blockState), block.getDrops(itemStack), ItemSpawnReason.TREE_FELLER_DISPLACED_BLOCK); - if(RankUtils.hasReachedRank(2, player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) { if(mcMMO.p.getAdvancedConfig().isKnockOnWoodXPOrbEnabled()) { //TODO: Test the results of this RNG, should be 10% @@ -336,8 +334,10 @@ private void dropTreeFellerLootFromBlocks(@NotNull Set treeFellerBlo } } } + } - } else { + // 90% of the time do not drop leaf blocks + if (ThreadLocalRandom.current().nextInt(100) > 90) { Misc.spawnItemsFromCollection(getPlayer(), Misc.getBlockCenter(blockState), block.getDrops(itemStack), ItemSpawnReason.TREE_FELLER_DISPLACED_BLOCK, 1); } } diff --git a/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java b/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java index 7ba7ae97c7..973cf0f282 100644 --- a/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java +++ b/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java @@ -30,6 +30,7 @@ import java.util.logging.Logger; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; public abstract class MMOTestEnvironment { protected MockedStatic mockedMcMMO; @@ -62,23 +63,24 @@ public abstract class MMOTestEnvironment { 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); - Mockito.when(mcMMO.p.getLogger()).thenReturn(logger); + when(mcMMO.p.getLogger()).thenReturn(logger); // place store chunkManager = Mockito.mock(ChunkManager.class); - Mockito.when(mcMMO.getPlaceStore()).thenReturn(chunkManager); + when(mcMMO.getPlaceStore()).thenReturn(chunkManager); // shut off mod manager for woodcutting - Mockito.when(mcMMO.getModManager()).thenReturn(Mockito.mock(ModManager.class)); - Mockito.when(mcMMO.getModManager().isCustomLog(any())).thenReturn(false); + when(mcMMO.getModManager()).thenReturn(Mockito.mock(ModManager.class)); + when(mcMMO.getModManager().isCustomLog(any())).thenReturn(false); // chat config mockedChatConfig = Mockito.mockStatic(ChatConfig.class); - Mockito.when(ChatConfig.getInstance()).thenReturn(Mockito.mock(ChatConfig.class)); + when(ChatConfig.getInstance()).thenReturn(Mockito.mock(ChatConfig.class)); // general config mockGeneralConfig(); @@ -94,10 +96,10 @@ protected void mockBaseEnvironment(Logger logger) throws InvalidSkillException { // wire skill tools this.skillTools = new SkillTools(mcMMO.p); - Mockito.when(mcMMO.p.getSkillTools()).thenReturn(skillTools); + when(mcMMO.p.getSkillTools()).thenReturn(skillTools); this.transientEntityTracker = new TransientEntityTracker(); - Mockito.when(mcMMO.getTransientEntityTracker()).thenReturn(transientEntityTracker); + when(mcMMO.getTransientEntityTracker()).thenReturn(transientEntityTracker); mockPermissions(); @@ -105,26 +107,26 @@ protected void mockBaseEnvironment(Logger logger) throws InvalidSkillException { // wire server this.server = Mockito.mock(Server.class); - Mockito.when(mcMMO.p.getServer()).thenReturn(server); + when(mcMMO.p.getServer()).thenReturn(server); // wire plugin manager this.pluginManager = Mockito.mock(PluginManager.class); - Mockito.when(server.getPluginManager()).thenReturn(pluginManager); + when(server.getPluginManager()).thenReturn(pluginManager); // wire world this.world = Mockito.mock(World.class); // wire Misc this.mockedMisc = Mockito.mockStatic(Misc.class); - Mockito.when(Misc.getBlockCenter(any())).thenReturn(new Location(world, 0, 0, 0)); + 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); - Mockito.when(player.getUniqueId()).thenReturn(playerUUID); + when(player.getUniqueId()).thenReturn(playerUUID); // wire inventory this.playerInventory = Mockito.mock(PlayerInventory.class); - Mockito.when(player.getInventory()).thenReturn(playerInventory); + when(player.getInventory()).thenReturn(playerInventory); // PlayerProfile and McMMOPlayer are partially mocked playerProfile = new PlayerProfile("testPlayer", player.getUniqueId(), 0); @@ -132,16 +134,19 @@ protected void mockBaseEnvironment(Logger logger) throws InvalidSkillException { // wire user manager this.mockedUserManager = Mockito.mockStatic(UserManager.class); - Mockito.when(UserManager.getPlayer(player)).thenReturn(mmoPlayer); + when(UserManager.getPlayer(player)).thenReturn(mmoPlayer); + + this.materialMapStore = new MaterialMapStore(); + when(mcMMO.getMaterialMapStore()).thenReturn(materialMapStore); } private void mockPermissions() { mockedPermissions = Mockito.mockStatic(Permissions.class); - Mockito.when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); - Mockito.when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn(true); - Mockito.when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); - Mockito.when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn(true); - Mockito.when(Permissions.lucky(player, PrimarySkillType.WOODCUTTING)).thenReturn(false); // player is not lucky + 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() { @@ -150,24 +155,24 @@ private void mockRankConfig() { private void mockAdvancedConfig() { this.advancedConfig = Mockito.mock(AdvancedConfig.class); - Mockito.when(mcMMO.p.getAdvancedConfig()).thenReturn(advancedConfig); + when(mcMMO.p.getAdvancedConfig()).thenReturn(advancedConfig); } private void mockGeneralConfig() { generalConfig = Mockito.mock(GeneralConfig.class); - Mockito.when(generalConfig.getTreeFellerThreshold()).thenReturn(100); - Mockito.when(generalConfig.getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, Material.OAK_LOG)).thenReturn(true); - Mockito.when(generalConfig.getLocale()).thenReturn("en_US"); - Mockito.when(mcMMO.p.getGeneralConfig()).thenReturn(generalConfig); + 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 mockExperienceConfig() { experienceConfig = Mockito.mockStatic(ExperienceConfig.class); - Mockito.when(ExperienceConfig.getInstance()).thenReturn(Mockito.mock(ExperienceConfig.class)); + when(ExperienceConfig.getInstance()).thenReturn(Mockito.mock(ExperienceConfig.class)); // Combat - Mockito.when(ExperienceConfig.getInstance().getCombatXP("Cow")).thenReturn(1D); + when(ExperienceConfig.getInstance().getCombatXP("Cow")).thenReturn(1D); } protected void cleanupBaseEnvironment() { From f051edd03d0537c9d6eeaa32b131d67bb3567b3d Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 22 Jan 2024 13:51:15 -0800 Subject: [PATCH 63/75] Tree Feller non-wood drop rate reduced by 90% --- .../skills/woodcutting/WoodcuttingManager.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java index 2c7d9f72cc..dd198131ee 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java @@ -323,11 +323,15 @@ private void dropTreeFellerLootFromBlocks(@NotNull Set treeFellerBlo //Bonus Drops / Harvest lumber checks processBonusDropCheck(blockState); } else if (BlockUtils.isNonWoodPartOfTree(blockState)) { + // 90% of the time do not drop leaf blocks + if (ThreadLocalRandom.current().nextInt(100) > 90) { + Misc.spawnItemsFromCollection(getPlayer(), Misc.getBlockCenter(blockState), block.getDrops(itemStack), ItemSpawnReason.TREE_FELLER_DISPLACED_BLOCK); + } + //Drop displaced non-woodcutting XP blocks if(RankUtils.hasUnlockedSubskill(player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) { if(RankUtils.hasReachedRank(2, player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) { if(mcMMO.p.getAdvancedConfig().isKnockOnWoodXPOrbEnabled()) { - //TODO: Test the results of this RNG, should be 10% if(ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.WOODCUTTING, player, 10)) { int randOrbCount = Math.max(1, Misc.getRandom().nextInt(100)); Misc.spawnExperienceOrb(blockState.getLocation(), randOrbCount); @@ -335,11 +339,6 @@ private void dropTreeFellerLootFromBlocks(@NotNull Set treeFellerBlo } } } - - // 90% of the time do not drop leaf blocks - if (ThreadLocalRandom.current().nextInt(100) > 90) { - Misc.spawnItemsFromCollection(getPlayer(), Misc.getBlockCenter(blockState), block.getDrops(itemStack), ItemSpawnReason.TREE_FELLER_DISPLACED_BLOCK, 1); - } } blockState.setType(Material.AIR); From b3b8a12b6d7fc194d78629e6d4eaeddc2ea4dfeb Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 22 Jan 2024 13:51:23 -0800 Subject: [PATCH 64/75] Crossbow Fixes --- pom.xml | 2 +- .../commands/skills/TridentsCommand.java | 5 +- .../nossr50/datatypes/player/McMMOPlayer.java | 10 ++-- .../nossr50/listeners/EntityListener.java | 37 +++++--------- .../nossr50/skills/crossbows/Crossbows.java | 10 ++-- .../skills/crossbows/CrossbowsManager.java | 15 +++--- .../skills/excavation/ExcavationManager.java | 10 ++-- .../java/com/gmail/nossr50/util/BowType.java | 6 --- .../com/gmail/nossr50/util/ItemUtils.java | 11 ---- .../gmail/nossr50/util/MetadataConstants.java | 1 - .../nossr50/util/skills/CombatUtils.java | 51 ++++++++----------- .../nossr50/util/skills/ProjectileUtils.java | 26 ++++------ src/main/resources/plugin.yml | 4 ++ 13 files changed, 76 insertions(+), 112 deletions(-) delete mode 100644 src/main/java/com/gmail/nossr50/util/BowType.java diff --git a/pom.xml b/pom.xml index 7cc845fe91..3d3839c217 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.2.000-BETA-04-SNAPSHOT + 2.2.000-BETA-07-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java index 63ec410372..7ff5cc5bbe 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java @@ -2,20 +2,19 @@ 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.player.UserManager; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import net.kyori.adventure.text.Component; import org.bukkit.ChatColor; -import org.bukkit.entity.Cat; import org.bukkit.entity.Player; import java.util.ArrayList; import java.util.List; -import static com.gmail.nossr50.datatypes.skills.SubSkillType.*; +import static com.gmail.nossr50.datatypes.skills.SubSkillType.TRIDENTS_IMPALE; +import static com.gmail.nossr50.datatypes.skills.SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK; public class TridentsCommand extends SkillCommand { diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index bfb441c0f3..ed4b4d9b08 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -963,14 +963,14 @@ public void checkAbilityActivation(PrimarySkillType primarySkillType) { /** * Check to see if an ability can be activated. * - * @param bowType The type of bow (crossbow, bow) + * @param isCrossbow true for crossbow, false for bow */ - public void checkAbilityActivationProjectiles(BowType bowType) { - PrimarySkillType primarySkillType = bowType == BowType.CROSSBOW ? PrimarySkillType.CROSSBOWS : PrimarySkillType.ARCHERY; + public void checkAbilityActivationProjectiles(boolean isCrossbow) { + PrimarySkillType primarySkillType = isCrossbow ? PrimarySkillType.CROSSBOWS : PrimarySkillType.ARCHERY; // TODO: Refactor this crappy logic - ToolType tool = bowType == BowType.CROSSBOW ? ToolType.CROSSBOW : ToolType.BOW; - SuperAbilityType superAbilityType = bowType == BowType.CROSSBOW ? SuperAbilityType.SUPER_SHOTGUN : SuperAbilityType.EXPLOSIVE_SHOT; + ToolType tool = isCrossbow ? ToolType.CROSSBOW : ToolType.BOW; + SuperAbilityType superAbilityType = isCrossbow ? SuperAbilityType.SUPER_SHOTGUN : SuperAbilityType.EXPLOSIVE_SHOT; SubSkillType subSkillType = superAbilityType.getSubSkillTypeDefinition(); if (getAbilityMode(superAbilityType) || !superAbilityType.getPermissions(player)) { diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index 0e4d50b51c..f126100196 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -26,7 +26,6 @@ import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.CombatUtils; -import com.gmail.nossr50.util.skills.ProjectileUtils; import com.gmail.nossr50.worldguard.WorldGuardManager; import com.gmail.nossr50.worldguard.WorldGuardUtils; import org.bukkit.ChatColor; @@ -105,7 +104,7 @@ public void onEntityTargetEntity(EntityTargetLivingEntityEvent event) { } } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = false) public void onEntityShootBow(EntityShootBowEvent event) { /* WORLD BLACKLIST CHECK */ if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) @@ -113,18 +112,10 @@ public void onEntityShootBow(EntityShootBowEvent event) { if(event.getEntity() instanceof Player player) { - - /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(player)) - return; - } - Entity projectile = event.getProjectile(); //Should be noted that there are API changes regarding Arrow from 1.13.2 to current versions of the game - if (!(projectile instanceof Arrow)) { + if (!(projectile instanceof Arrow arrow)) { return; } @@ -133,20 +124,16 @@ public void onEntityShootBow(EntityShootBowEvent event) { if (bow == null) return; - // determine if bow or crossbow - BowType bowType = ItemUtils.isCrossbow(bow) ? BowType.CROSSBOW : BowType.BOW; - if (bow.containsEnchantment(Enchantment.ARROW_INFINITE)) { projectile.setMetadata(MetadataConstants.METADATA_KEY_INF_ARROW, MetadataConstants.MCMMO_METADATA_VALUE); } // Set BowType, Force, and Distance metadata - projectile.setMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE, new FixedMetadataValue(pluginRef, bowType)); projectile.setMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, new FixedMetadataValue(pluginRef, Math.min(event.getForce() * mcMMO.p.getAdvancedConfig().getForceMultiplier(), 1.0))); - projectile.setMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, new FixedMetadataValue(pluginRef, projectile.getLocation())); + projectile.setMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, new FixedMetadataValue(pluginRef, arrow.getLocation())); //Cleanup metadata in 1 minute in case normal collection falls through - CombatUtils.delayArrowMetaCleanup((Projectile) projectile); + CombatUtils.delayArrowMetaCleanup(arrow); } } @@ -168,14 +155,14 @@ public void onProjectileLaunch(ProjectileLaunchEvent event) { Projectile projectile = event.getEntity(); EntityType entityType = projectile.getType(); - if(entityType == EntityType.ARROW || entityType == EntityType.SPECTRAL_ARROW) { - CombatUtils.delayArrowMetaCleanup(projectile); //Cleans up metadata 1 minute from now in case other collection methods fall through + if(projectile instanceof Arrow arrow) { + CombatUtils.delayArrowMetaCleanup(arrow); //Cleans up metadata 1 minute from now in case other collection methods fall through if(!projectile.hasMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE)) projectile.setMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, new FixedMetadataValue(pluginRef, 1.0)); if(!projectile.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE)) - projectile.setMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, new FixedMetadataValue(pluginRef, projectile.getLocation())); + projectile.setMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, new FixedMetadataValue(pluginRef, arrow.getLocation())); //Check both hands if(ItemUtils.doesPlayerHaveEnchantmentInHands(player, "piercing")) { @@ -411,8 +398,8 @@ public void onEntityDamageMonitor(EntityDamageByEntityEvent entityDamageEvent) { } } - if(entityDamageEvent.getDamager() instanceof Projectile) { - ProjectileUtils.cleanupProjectileMetadata((Projectile) entityDamageEvent.getDamager()); + if(entityDamageEvent.getDamager() instanceof Arrow arrow) { + CombatUtils.delayArrowMetaCleanup(arrow); } if(entityDamageEvent.getEntity() instanceof Player player && entityDamageEvent.getDamager() instanceof Player) { @@ -1119,6 +1106,10 @@ public void onProjectileHitEvent(ProjectileHitEvent event) { if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) return; - Crossbows.processCrossbows(event, pluginRef); + if(event.getEntity() instanceof Arrow arrow) { + if(arrow.isShotFromCrossbow()) { + Crossbows.processCrossbows(event, pluginRef, arrow); + } + } } } diff --git a/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java b/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java index 33604948ef..b09a1510a0 100644 --- a/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java +++ b/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java @@ -13,14 +13,14 @@ * Util class for crossbows. */ public class Crossbows { - public static void processCrossbows(ProjectileHitEvent event, Plugin pluginRef) { - if(event.getEntity() instanceof Arrow originalArrow && event.getHitBlock() != null && event.getHitBlockFace() != null) { - if (originalArrow.getShooter() instanceof Player) { - McMMOPlayer mmoPlayer = UserManager.getPlayer((Player) originalArrow.getShooter()); + public static void processCrossbows(ProjectileHitEvent event, Plugin pluginRef, Arrow arrow) { + if(event.getHitBlock() != null && event.getHitBlockFace() != null) { + if (arrow.getShooter() instanceof Player) { + McMMOPlayer mmoPlayer = UserManager.getPlayer((Player) arrow.getShooter()); if (mmoPlayer != null) { mmoPlayer.getCrossbowsManager().handleRicochet( pluginRef, - originalArrow, + arrow, getNormal(event.getHitBlockFace())); } } diff --git a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java index a7e9ae508f..91826def07 100644 --- a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java @@ -5,8 +5,6 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.SkillManager; -import com.gmail.nossr50.skills.archery.Archery; -import com.gmail.nossr50.util.BowType; import com.gmail.nossr50.util.MetadataConstants; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.random.ProbabilityUtil; @@ -25,17 +23,20 @@ public CrossbowsManager(McMMOPlayer mmoPlayer) { super(mmoPlayer, PrimarySkillType.CROSSBOWS); } - public void handleRicochet(@NotNull Plugin pluginRef, @NotNull Arrow originalArrow, @NotNull Vector hitBlockNormal) { + public void handleRicochet(@NotNull Plugin pluginRef, @NotNull Arrow arrow, @NotNull Vector hitBlockNormal) { + if(!arrow.isShotFromCrossbow()) + return; + // Check player permission if (!Permissions.trickShot(mmoPlayer.getPlayer())) { return; } // TODO: Add an event for this for plugins to hook into - spawnReflectedArrow(pluginRef, originalArrow, originalArrow.getLocation(), hitBlockNormal); + spawnReflectedArrow(pluginRef, arrow, arrow.getLocation(), hitBlockNormal); } - public void spawnReflectedArrow(@NotNull Plugin pluginRef, @NotNull Arrow originalArrow, + private void spawnReflectedArrow(@NotNull Plugin pluginRef, @NotNull Arrow originalArrow, @NotNull Location origin, @NotNull Vector normal) { int bounceCount = 0; @@ -66,8 +67,6 @@ public void spawnReflectedArrow(@NotNull Plugin pluginRef, @NotNull Arrow origin new FixedMetadataValue(pluginRef, bounceCount + 1)); arrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, new FixedMetadataValue(pluginRef, originalArrowShooter)); - arrow.setMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE, - new FixedMetadataValue(pluginRef, BowType.CROSSBOW)); originalArrow.remove(); } @@ -89,7 +88,7 @@ public double getDamageBonusPercent(Player player) { public double poweredShot(double oldDamage) { if (ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.CROSSBOWS_POWERED_SHOT, getPlayer())) { - return Archery.getSkillShotBonusDamage(getPlayer(), oldDamage); + return getPoweredShotBonusDamage(getPlayer(), oldDamage); } else { return oldDamage; } diff --git a/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java b/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java index bc9120e12f..e3cf20fd3a 100644 --- a/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java +++ b/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java @@ -35,6 +35,7 @@ public ExcavationManager(McMMOPlayer mcMMOPlayer) { * @param blockState The {@link BlockState} to check ability activation for */ public void excavationBlockCheck(BlockState blockState) { + int xp = Excavation.getBlockXP(blockState); requireNonNull(blockState, "excavationBlockCheck: blockState cannot be null"); if (Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.EXCAVATION_ARCHAEOLOGY)) { List treasures = getTreasures(blockState); @@ -51,6 +52,8 @@ public void excavationBlockCheck(BlockState blockState) { } } } + + applyXpGain(xp, XPGainReason.PVE, XPGainSource.SELF); } @VisibleForTesting @@ -61,16 +64,17 @@ public List getTreasures(@NotNull BlockState blockState) { @VisibleForTesting public void processExcavationBonusesOnBlock(BlockState blockState, ExcavationTreasure treasure, Location location) { - int xp = Excavation.getBlockXP(blockState); - //Spawn Vanilla XP orbs if a dice roll succeeds if(ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.EXCAVATION, getPlayer(), getArchaelogyExperienceOrbChance())) { Misc.spawnExperienceOrb(location, getExperienceOrbsReward()); } + int xp = 0; xp += treasure.getXp(); Misc.spawnItem(getPlayer(), location, treasure.getDrop(), ItemSpawnReason.EXCAVATION_TREASURE); - applyXpGain(xp, XPGainReason.PVE, XPGainSource.SELF); + if (xp > 0) { + applyXpGain(xp, XPGainReason.PVE, XPGainSource.SELF); + } } public int getExperienceOrbsReward() { diff --git a/src/main/java/com/gmail/nossr50/util/BowType.java b/src/main/java/com/gmail/nossr50/util/BowType.java deleted file mode 100644 index 5e4d782741..0000000000 --- a/src/main/java/com/gmail/nossr50/util/BowType.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.gmail.nossr50.util; - -public enum BowType { - BOW, - CROSSBOW -} diff --git a/src/main/java/com/gmail/nossr50/util/ItemUtils.java b/src/main/java/com/gmail/nossr50/util/ItemUtils.java index a6ad59a18f..04993eb745 100644 --- a/src/main/java/com/gmail/nossr50/util/ItemUtils.java +++ b/src/main/java/com/gmail/nossr50/util/ItemUtils.java @@ -51,17 +51,6 @@ public static boolean isBowOrCrossbow(@NotNull ItemStack item) { return isBow(item) || isCrossbow(item); } - // TODO: Unit tests - public static BowType getBowType(@NotNull ItemStack item) { - if (isBow(item)) { - return BowType.BOW; - } else if (isCrossbow(item)) { - return BowType.CROSSBOW; - } - - throw new IllegalArgumentException(item + " is not a bow or crossbow"); - } - // TODO: Unit tests public static boolean isTrident(@NotNull ItemStack item) { return mcMMO.getMaterialMapStore().isTrident(item.getType().getKey().getKey()); diff --git a/src/main/java/com/gmail/nossr50/util/MetadataConstants.java b/src/main/java/com/gmail/nossr50/util/MetadataConstants.java index 48aaa8955e..c8fc18a7de 100644 --- a/src/main/java/com/gmail/nossr50/util/MetadataConstants.java +++ b/src/main/java/com/gmail/nossr50/util/MetadataConstants.java @@ -16,7 +16,6 @@ public class MetadataConstants { public static final @NotNull String METADATA_KEY_REPLANT = "mcMMO: Recently Replanted"; public static final @NotNull String METADATA_KEY_SPAWNED_ARROW = "mcMMO: Spawned Arrow"; public static final @NotNull String METADATA_KEY_BOUNCE_COUNT = "mcMMO: Arrow Bounce Count"; - public static final @NotNull String METADATA_KEY_BOW_TYPE = "mcMMO: Bow Type"; public static final @NotNull String METADATA_KEY_EXPLOSION_FROM_RUPTURE = "mcMMO: Rupture Explosion"; public static final @NotNull String METADATA_KEY_FISH_HOOK_REF = "mcMMO: Fish Hook Tracker"; public static final @NotNull String METADATA_KEY_DODGE_TRACKER = "mcMMO: Dodge Tracker"; diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index 485ef96da5..164ebf1221 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -52,8 +52,10 @@ private CombatUtils() {} // TODO: Unit tests public static void processProjectileSkillSuperAbilityActivation(McMMOPlayer mmoPlayer, ItemStack heldItem) { if (heldItem != null && mmoPlayer != null) { - if (ItemUtils.isBowOrCrossbow(heldItem)) - mmoPlayer.checkAbilityActivationProjectiles(ItemUtils.getBowType(heldItem)); + if (ItemUtils.isBowOrCrossbow(heldItem)) { + boolean isCrossbow = ItemUtils.isCrossbow(heldItem); + mmoPlayer.checkAbilityActivationProjectiles(isCrossbow); + } } } @@ -159,14 +161,14 @@ private static void processTridentCombat(@NotNull LivingEntity target, @NotNull } private static void processCrossbowsCombat(@NotNull LivingEntity target, @NotNull Player player, - @NotNull EntityDamageByEntityEvent event, @NotNull Projectile arrow) { + @NotNull EntityDamageByEntityEvent event, @NotNull Arrow arrow) { double initialDamage = event.getDamage(); McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); //Make sure the profiles been loaded if(mcMMOPlayer == null) { - ProjectileUtils.cleanupProjectileMetadata(arrow); + delayArrowMetaCleanup(arrow); return; } @@ -194,7 +196,7 @@ private static void processCrossbowsCombat(@NotNull LivingEntity target, @NotNul "Final Damage: "+boostedDamage); //Clean data - ProjectileUtils.cleanupProjectileMetadata(arrow); + delayArrowMetaCleanup(arrow); } private static void processAxeCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) { @@ -324,14 +326,15 @@ private static void processTamingCombat(@NotNull LivingEntity target, @Nullable } - private static void processArcheryCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event, @NotNull Projectile arrow) { + private static void processArcheryCombat(@NotNull LivingEntity target, @NotNull Player player, + @NotNull EntityDamageByEntityEvent event, @NotNull Arrow arrow) { double initialDamage = event.getDamage(); McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); //Make sure the profiles been loaded if(mcMMOPlayer == null) { - ProjectileUtils.cleanupProjectileMetadata(arrow); + delayArrowMetaCleanup(arrow); return; } @@ -372,7 +375,7 @@ private static void processArcheryCombat(@NotNull LivingEntity target, @NotNull "Initial Damage: "+initialDamage, "Final Damage: "+boostedDamage); //Clean data - ProjectileUtils.cleanupProjectileMetadata(arrow); + delayArrowMetaCleanup(arrow); } /** @@ -489,22 +492,20 @@ else if (entityType == EntityType.WOLF) { } } } - else if (entityType == EntityType.ARROW || entityType == EntityType.SPECTRAL_ARROW) { - Projectile arrow = (Projectile) painSource; + else if (painSource instanceof Arrow arrow) { ProjectileSource projectileSource = arrow.getShooter(); - + boolean isCrossbow = arrow.isShotFromCrossbow(); if (projectileSource instanceof Player player) { - BowType bowType = getBowTypeFromMetadata(arrow); if (!Misc.isNPCEntityExcludingVillagers(player)) { - if(bowType == BowType.BOW && mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.ARCHERY, target)) { + if(!isCrossbow && mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.ARCHERY, target)) { processArcheryCombat(target, player, event, arrow); - } else if(bowType == BowType.CROSSBOW && mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.CROSSBOWS, target)) { + } else if(isCrossbow && mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.CROSSBOWS, target)) { processCrossbowsCombat(target, player, event, arrow); } } else { //Cleanup Arrow - ProjectileUtils.cleanupProjectileMetadata(arrow); + delayArrowMetaCleanup(arrow); } if (target.getType() != EntityType.CREEPER @@ -522,18 +523,6 @@ else if (entityType == EntityType.ARROW || entityType == EntityType.SPECTRAL_ARR } } - private static BowType getBowTypeFromMetadata(Projectile projectile) { - // Return the BowType from the metadata, or default to BOW - if (projectile.hasMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE)) { - List metadataValue = projectile.getMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE); - - if (!metadataValue.isEmpty()) { - return (BowType) metadataValue.get(0).value(); - } - } - throw new IllegalStateException("BowType metadata is empty"); - } - /** * This cleans up names from displaying in chat as hearts * @param entity target entity @@ -728,7 +717,7 @@ public static void applyIgnoreDamageMetadata(@NotNull LivingEntity target) { } public static boolean hasIgnoreDamageMetadata(@NotNull LivingEntity target) { - return target.getMetadata(MetadataConstants.METADATA_KEY_CUSTOM_DAMAGE).size() != 0; + return target.hasMetadata(MetadataConstants.METADATA_KEY_CUSTOM_DAMAGE); } public static void dealNoInvulnerabilityTickDamageRupture(@NotNull LivingEntity target, double damage, Entity attacker, int toolTier) { @@ -1040,9 +1029,9 @@ public static void modifyMoveSpeed(@NotNull LivingEntity livingEntity, double mu /** * Clean up metadata from a projectile after a minute has passed * - * @param entity the projectile + * @param arrow the projectile */ - public static void delayArrowMetaCleanup(@NotNull Projectile entity) { - mcMMO.p.getFoliaLib().getImpl().runLater(() -> ProjectileUtils.cleanupProjectileMetadata(entity), 20*60); + public static void delayArrowMetaCleanup(@NotNull Arrow arrow) { + mcMMO.p.getFoliaLib().getImpl().runLater(() -> ProjectileUtils.cleanupProjectileMetadata(arrow), 20*120); } } diff --git a/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java b/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java index 0ef2ccd465..2c872f4171 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java @@ -3,7 +3,7 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.MetadataConstants; import org.bukkit.block.BlockFace; -import org.bukkit.entity.Projectile; +import org.bukkit.entity.Arrow; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; @@ -23,28 +23,24 @@ public static Vector getNormal(BlockFace blockFace) { /** * Clean up all possible mcMMO related metadata for a projectile * - * @param entity projectile + * @param arrow projectile */ // TODO: Add test - public static void cleanupProjectileMetadata(@NotNull Projectile entity) { - if(entity.hasMetadata(MetadataConstants.METADATA_KEY_INF_ARROW)) { - entity.removeMetadata(MetadataConstants.METADATA_KEY_INF_ARROW, mcMMO.p); + public static void cleanupProjectileMetadata(@NotNull Arrow arrow) { + if(arrow.hasMetadata(MetadataConstants.METADATA_KEY_INF_ARROW)) { + arrow.removeMetadata(MetadataConstants.METADATA_KEY_INF_ARROW, mcMMO.p); } - if(entity.hasMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE)) { - entity.removeMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, mcMMO.p); + if(arrow.hasMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE)) { + arrow.removeMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, mcMMO.p); } - if(entity.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE)) { - entity.removeMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, mcMMO.p); + if(arrow.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE)) { + arrow.removeMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, mcMMO.p); } - if(entity.hasMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE)) { - entity.removeMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE, mcMMO.p); - } - - if(entity.hasMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW)) { - entity.removeMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, mcMMO.p); + if(arrow.hasMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW)) { + arrow.removeMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, mcMMO.p); } } } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 21ba26247d..a4dc5d4b20 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -859,6 +859,8 @@ permissions: mcmmo.commands.alchemy: true mcmmo.commands.archery: true mcmmo.commands.axes: true + mcmmo.commands.crossbows: true + mcmmo.commands.tridents: true mcmmo.commands.excavation: true mcmmo.commands.fishing: true mcmmo.commands.herbalism: true @@ -2212,6 +2214,8 @@ permissions: mcmmo.skills.taming: true mcmmo.skills.unarmed: true mcmmo.skills.woodcutting: true + mcmmo.skills.crossbows: true + mcmmo.skills.tridents: true mcmmo.skills.acrobatics: description: Allows access to the Acrobatics skill children: From 66a4886ee47b98a32c130d6348a1323cb7d212da Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 28 Jan 2024 15:00:53 -0800 Subject: [PATCH 65/75] Crossbow multi-shot arrows that bounce are no longer pickup-able --- pom.xml | 2 +- .../nossr50/listeners/EntityListener.java | 21 +++++++----- .../nossr50/skills/crossbows/Crossbows.java | 31 ++++++++++++----- .../skills/crossbows/CrossbowsManager.java | 26 ++++++++++---- .../gmail/nossr50/util/MetadataConstants.java | 1 + .../nossr50/util/skills/ProjectileUtils.java | 34 +++++++++++++++++++ 6 files changed, 89 insertions(+), 26 deletions(-) diff --git a/pom.xml b/pom.xml index 3d3839c217..5498b9f71f 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.2.000-BETA-07-SNAPSHOT + 2.2.000-BETA-08-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index f126100196..e80225d61e 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -152,17 +152,20 @@ public void onProjectileLaunch(ProjectileLaunchEvent event) { return; } - Projectile projectile = event.getEntity(); - EntityType entityType = projectile.getType(); + if(event.getEntity() instanceof Arrow arrow) { + // Delayed metadata cleanup in case other cleanup hooks fail + CombatUtils.delayArrowMetaCleanup(arrow); - if(projectile instanceof Arrow arrow) { - CombatUtils.delayArrowMetaCleanup(arrow); //Cleans up metadata 1 minute from now in case other collection methods fall through + // If fired from an item with multi-shot, we need to track + if(ItemUtils.doesPlayerHaveEnchantmentInHands(player, "multishot")) { + arrow.setMetadata(MetadataConstants.METADATA_KEY_MULTI_SHOT_ARROW, MetadataConstants.MCMMO_METADATA_VALUE); + } - if(!projectile.hasMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE)) - projectile.setMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, new FixedMetadataValue(pluginRef, 1.0)); + if(!arrow.hasMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE)) + arrow.setMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, new FixedMetadataValue(pluginRef, 1.0)); - if(!projectile.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE)) - projectile.setMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, new FixedMetadataValue(pluginRef, arrow.getLocation())); + if(!arrow.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE)) + arrow.setMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, new FixedMetadataValue(pluginRef, arrow.getLocation())); //Check both hands if(ItemUtils.doesPlayerHaveEnchantmentInHands(player, "piercing")) { @@ -170,7 +173,7 @@ public void onProjectileLaunch(ProjectileLaunchEvent event) { } if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.ARCHERY_ARROW_RETRIEVAL, player)) { - projectile.setMetadata(MetadataConstants.METADATA_KEY_TRACKED_ARROW, MetadataConstants.MCMMO_METADATA_VALUE); + arrow.setMetadata(MetadataConstants.METADATA_KEY_TRACKED_ARROW, MetadataConstants.MCMMO_METADATA_VALUE); } } } diff --git a/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java b/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java index b09a1510a0..216a9485df 100644 --- a/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java +++ b/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java @@ -1,6 +1,7 @@ package com.gmail.nossr50.skills.crossbows; import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.util.MetadataConstants; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.entity.Arrow; import org.bukkit.entity.Player; @@ -13,17 +14,29 @@ * Util class for crossbows. */ public class Crossbows { + /** + * Process events that may happen from a crossbow hitting an entity. + * + * @param event the projectile hit event + * @param pluginRef the plugin ref + * @param arrow the arrow + */ public static void processCrossbows(ProjectileHitEvent event, Plugin pluginRef, Arrow arrow) { + if (arrow.getShooter() instanceof Player) { + McMMOPlayer mmoPlayer = UserManager.getPlayer((Player) arrow.getShooter()); + if (mmoPlayer == null) + return; + + processTrickShot(event, pluginRef, arrow, mmoPlayer); + } + } + + private static void processTrickShot(ProjectileHitEvent event, Plugin pluginRef, Arrow arrow, McMMOPlayer mmoPlayer) { if(event.getHitBlock() != null && event.getHitBlockFace() != null) { - if (arrow.getShooter() instanceof Player) { - McMMOPlayer mmoPlayer = UserManager.getPlayer((Player) arrow.getShooter()); - if (mmoPlayer != null) { - mmoPlayer.getCrossbowsManager().handleRicochet( - pluginRef, - arrow, - getNormal(event.getHitBlockFace())); - } - } + mmoPlayer.getCrossbowsManager().handleRicochet( + pluginRef, + arrow, + getNormal(event.getHitBlockFace())); } } } diff --git a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java index 91826def07..60def74bff 100644 --- a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java @@ -8,8 +8,10 @@ import com.gmail.nossr50.util.MetadataConstants; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.random.ProbabilityUtil; +import com.gmail.nossr50.util.skills.ProjectileUtils; import com.gmail.nossr50.util.skills.RankUtils; import org.bukkit.Location; +import org.bukkit.entity.AbstractArrow; import org.bukkit.entity.Arrow; import org.bukkit.entity.Player; import org.bukkit.metadata.FixedMetadataValue; @@ -18,6 +20,8 @@ import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; +import static com.gmail.nossr50.util.skills.CombatUtils.delayArrowMetaCleanup; + public class CrossbowsManager extends SkillManager { public CrossbowsManager(McMMOPlayer mmoPlayer) { super(mmoPlayer, PrimarySkillType.CROSSBOWS); @@ -52,7 +56,6 @@ private void spawnReflectedArrow(@NotNull Plugin pluginRef, @NotNull Arrow origi final Vector reflectedDirection = arrowInBlockVector.subtract(normal.multiply(2 * arrowInBlockVector.dot(normal))); final Vector inverseNormal = normal.multiply(-1); - // check the angle of the arrow against the inverse normal to see if the angle was too shallow // only checks angle on the first bounce if (bounceCount == 0 && arrowInBlockVector.angle(inverseNormal) < Math.PI / 4) { @@ -60,15 +63,24 @@ private void spawnReflectedArrow(@NotNull Plugin pluginRef, @NotNull Arrow origi } // Spawn new arrow with the reflected direction - Arrow arrow = originalArrow.getWorld().spawnArrow(origin, - reflectedDirection, 1, 1); - arrow.setShooter(originalArrowShooter); - arrow.setMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT, + Arrow spawnedArrow = originalArrow.getWorld().spawnArrow(origin, reflectedDirection, 1, 1); + ProjectileUtils.copyArrowMetadata(pluginRef, originalArrow, spawnedArrow); + originalArrow.remove(); + // copy metadata from old arrow + spawnedArrow.setShooter(originalArrowShooter); + spawnedArrow.setMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT, new FixedMetadataValue(pluginRef, bounceCount + 1)); - arrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, + spawnedArrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, new FixedMetadataValue(pluginRef, originalArrowShooter)); - originalArrow.remove(); + // Don't allow multi-shot or infinite arrows to be picked up + if (spawnedArrow.hasMetadata(MetadataConstants.METADATA_KEY_MULTI_SHOT_ARROW) + || spawnedArrow.hasMetadata(MetadataConstants.METADATA_KEY_INF_ARROW)) { + spawnedArrow.setPickupStatus(AbstractArrow.PickupStatus.DISALLOWED); + } + + // Schedule cleanup of metadata in case metadata cleanup fails + delayArrowMetaCleanup(spawnedArrow); } public int getTrickShotMaxBounceCount() { diff --git a/src/main/java/com/gmail/nossr50/util/MetadataConstants.java b/src/main/java/com/gmail/nossr50/util/MetadataConstants.java index c8fc18a7de..39f9479cea 100644 --- a/src/main/java/com/gmail/nossr50/util/MetadataConstants.java +++ b/src/main/java/com/gmail/nossr50/util/MetadataConstants.java @@ -15,6 +15,7 @@ public class MetadataConstants { */ public static final @NotNull String METADATA_KEY_REPLANT = "mcMMO: Recently Replanted"; public static final @NotNull String METADATA_KEY_SPAWNED_ARROW = "mcMMO: Spawned Arrow"; + public static final @NotNull String METADATA_KEY_MULTI_SHOT_ARROW = "mcMMO: Multi-shot Arrow"; public static final @NotNull String METADATA_KEY_BOUNCE_COUNT = "mcMMO: Arrow Bounce Count"; public static final @NotNull String METADATA_KEY_EXPLOSION_FROM_RUPTURE = "mcMMO: Rupture Explosion"; public static final @NotNull String METADATA_KEY_FISH_HOOK_REF = "mcMMO: Fish Hook Tracker"; diff --git a/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java b/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java index 2c872f4171..6427117ae0 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java @@ -4,6 +4,8 @@ import com.gmail.nossr50.util.MetadataConstants; import org.bukkit.block.BlockFace; import org.bukkit.entity.Arrow; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.plugin.Plugin; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; @@ -42,5 +44,37 @@ public static void cleanupProjectileMetadata(@NotNull Arrow arrow) { if(arrow.hasMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW)) { arrow.removeMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, mcMMO.p); } + + if(arrow.hasMetadata(MetadataConstants.METADATA_KEY_MULTI_SHOT_ARROW)) { + arrow.removeMetadata(MetadataConstants.METADATA_KEY_MULTI_SHOT_ARROW, mcMMO.p); + } + } + + public static void copyArrowMetadata(@NotNull Plugin pluginRef, @NotNull Arrow arrowToCopy, @NotNull Arrow newArrow) { + if(arrowToCopy.hasMetadata(MetadataConstants.METADATA_KEY_INF_ARROW)) { + newArrow.setMetadata(MetadataConstants.METADATA_KEY_INF_ARROW, + arrowToCopy.getMetadata(MetadataConstants.METADATA_KEY_INF_ARROW).get(0)); + } + + if(arrowToCopy.hasMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE)) { + newArrow.setMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE, + new FixedMetadataValue(pluginRef, + arrowToCopy.getMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE).get(0).asDouble())); + } + + if(arrowToCopy.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE)) { + newArrow.setMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE, + arrowToCopy.getMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE).get(0)); + } + + if(arrowToCopy.hasMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW)) { + newArrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, + arrowToCopy.getMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW).get(0)); + } + + if(arrowToCopy.hasMetadata(MetadataConstants.METADATA_KEY_MULTI_SHOT_ARROW)) { + newArrow.setMetadata(MetadataConstants.METADATA_KEY_MULTI_SHOT_ARROW, + arrowToCopy.getMetadata(MetadataConstants.METADATA_KEY_MULTI_SHOT_ARROW).get(0)); + } } } From b0c42f8e44300d357b3bdc6aa65a3d75e5d4e6b7 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sat, 3 Feb 2024 14:55:42 -0800 Subject: [PATCH 66/75] enable super shotgun permission --- src/main/java/com/gmail/nossr50/util/Permissions.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/util/Permissions.java b/src/main/java/com/gmail/nossr50/util/Permissions.java index fbc39f32b1..9a5f1f6c23 100644 --- a/src/main/java/com/gmail/nossr50/util/Permissions.java +++ b/src/main/java/com/gmail/nossr50/util/Permissions.java @@ -177,7 +177,7 @@ public static boolean skillEnabled(Permissible permissible, PrimarySkillType ski public static boolean vanillaXpBoost(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.ability." + skill.toString().toLowerCase(Locale.ENGLISH) + ".vanillaxpboost"); } public static boolean isSubSkillEnabled(Permissible permissible, SubSkillType subSkillType) { // hack to disable supers that aren't coded yet - if(subSkillType == SubSkillType.TRIDENTS_SUPER || subSkillType == SubSkillType.CROSSBOWS_SUPER_SHOTGUN) + if(subSkillType == SubSkillType.TRIDENTS_SUPER) return false; return permissible.hasPermission(subSkillType.getPermissionNodeAddress()); } @@ -238,10 +238,10 @@ public static boolean isSubSkillEnabled(Permissible permissible, SubSkillType su /* WOODCUTTING */ public static boolean treeFeller(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.woodcutting.treefeller"); } + /* CROSSBOWS */ public static boolean superShotgun(Permissible permissible) { - return false; - // return permissible.hasPermission("mcmmo.ability.crossbows.supershotgun"); + return permissible.hasPermission("mcmmo.ability.crossbows.supershotgun"); } public static boolean trickShot(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.crossbows.trickshot"); } public static boolean poweredShot(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.crossbows.poweredshot"); } From 2271bd523653e5db3399c557e9d6151c85268577 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sat, 3 Feb 2024 16:05:53 -0800 Subject: [PATCH 67/75] wip super shotgun --- .../nossr50/datatypes/player/McMMOPlayer.java | 34 ++++++++------- .../nossr50/listeners/PlayerListener.java | 20 +++++++-- .../skills/AlternateFiringSuperSkill.java | 13 ++++++ .../skills/crossbows/CrossbowsManager.java | 41 ++++++++++++++++++- .../nossr50/util/skills/CombatUtils.java | 6 +-- 5 files changed, 92 insertions(+), 22 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/skills/AlternateFiringSuperSkill.java diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index ed4b4d9b08..7abaf9de3e 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -25,6 +25,7 @@ import com.gmail.nossr50.runnables.skills.AbilityCooldownTask; import com.gmail.nossr50.runnables.skills.AbilityDisableTask; import com.gmail.nossr50.runnables.skills.ToolLowerTask; +import com.gmail.nossr50.skills.AlternateFiringSuperSkill; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager; import com.gmail.nossr50.skills.alchemy.AlchemyManager; @@ -960,20 +961,15 @@ public void checkAbilityActivation(PrimarySkillType primarySkillType) { mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(player, new AbilityDisableTask(this, superAbilityType), (long) ticks * Misc.TICK_CONVERSION_FACTOR); } - /** - * Check to see if an ability can be activated. - * - * @param isCrossbow true for crossbow, false for bow - */ - public void checkAbilityActivationProjectiles(boolean isCrossbow) { - PrimarySkillType primarySkillType = isCrossbow ? PrimarySkillType.CROSSBOWS : PrimarySkillType.ARCHERY; + public void checkCrossbowAbilityActivation() { + PrimarySkillType primarySkillType = PrimarySkillType.CROSSBOWS; + ToolType tool = ToolType.CROSSBOW; + SuperAbilityType superAbilityType = SuperAbilityType.SUPER_SHOTGUN; + SubSkillType subSkillType = SubSkillType.CROSSBOWS_SUPER_SHOTGUN; + AlternateFiringSuperSkill skillManager = getCrossbowsManager(); - // TODO: Refactor this crappy logic - ToolType tool = isCrossbow ? ToolType.CROSSBOW : ToolType.BOW; - SuperAbilityType superAbilityType = isCrossbow ? SuperAbilityType.SUPER_SHOTGUN : SuperAbilityType.EXPLOSIVE_SHOT; - SubSkillType subSkillType = superAbilityType.getSubSkillTypeDefinition(); - - if (getAbilityMode(superAbilityType) || !superAbilityType.getPermissions(player)) { + // Check permission + if (!superAbilityType.getPermissions(player)) { return; } @@ -997,6 +993,11 @@ public void checkAbilityActivationProjectiles(boolean isCrossbow) { return; } + // Check if we can fire the ability + if (!skillManager.isReadyToFire()) { + return; + } + if (useChatNotifications()) { NotificationManager.sendPlayerInformation(player, NotificationType.SUPER_ABILITY, superAbilityType.getAbilityOn()); } @@ -1010,8 +1011,9 @@ public void checkAbilityActivationProjectiles(boolean isCrossbow) { // TODO: Fire the ability profile.setAbilityDATS(superAbilityType, System.currentTimeMillis()); - setAbilityMode(superAbilityType, true); setToolPreparationMode(tool, false); + skillManager.resetCharge(); + skillManager.fireSuper(); if(!mcMMO.isServerShutdownExecuted()) { mcMMO.p.getFoliaLib().getImpl().runAtEntityLater( @@ -1021,6 +1023,10 @@ public void checkAbilityActivationProjectiles(boolean isCrossbow) { } } + public void chargeCrossbowSuper() { + getCrossbowsManager().chargeSuper(); + } + public void processAbilityActivation(@NotNull PrimarySkillType primarySkillType) { if (!mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(getPlayer(), primarySkillType)) { return; diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java index f27a69fcc2..dc555eb21b 100644 --- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java @@ -788,6 +788,9 @@ public void onPlayerInteractMonitor(PlayerInteractEvent event) { } McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + if (mcMMOPlayer == null) + return; + ItemStack heldItem = player.getInventory().getItemInMainHand(); //Spam Fishing Detection @@ -825,6 +828,11 @@ public void onPlayerInteractMonitor(PlayerInteractEvent event) { mcMMOPlayer.processAbilityActivation(PrimarySkillType.HERBALISM); } + // Projectile Skills + if (ItemUtils.isCrossbow(heldItem) || ItemUtils.isBow(heldItem)) { + CombatUtils.processProjectileSkillSuperAbilityActivation(mcMMOPlayer, heldItem); + } + mcMMOPlayer.processAbilityActivation(PrimarySkillType.AXES); mcMMOPlayer.processAbilityActivation(PrimarySkillType.EXCAVATION); mcMMOPlayer.processAbilityActivation(PrimarySkillType.MINING); @@ -896,6 +904,11 @@ else if (herbalismManager.canUseShroomThumb(blockState)) { mcMMOPlayer.processAbilityActivation(PrimarySkillType.SWORDS); mcMMOPlayer.processAbilityActivation(PrimarySkillType.UNARMED); mcMMOPlayer.processAbilityActivation(PrimarySkillType.WOODCUTTING); + + // Projectile Skills + if (ItemUtils.isCrossbow(heldItem) || ItemUtils.isBow(heldItem)) { + CombatUtils.processProjectileSkillSuperAbilityActivation(mcMMOPlayer, heldItem); + } } /* ITEM CHECKS */ @@ -916,10 +929,9 @@ else if (herbalismManager.canUseShroomThumb(blockState)) { break; } - // Projectile Skills - // Check if the player is holding a bow or crossbow - if (ItemUtils.isCrossbow(heldItem) || ItemUtils.isBow(heldItem)) { - CombatUtils.processProjectileSkillSuperAbilityActivation(mcMMOPlayer, heldItem); + // Check charge up supers (crossbows, etc...) + if (ItemUtils.isCrossbow(heldItem)) { + mcMMOPlayer.chargeCrossbowSuper(); } /* CALL OF THE WILD CHECKS */ diff --git a/src/main/java/com/gmail/nossr50/skills/AlternateFiringSuperSkill.java b/src/main/java/com/gmail/nossr50/skills/AlternateFiringSuperSkill.java new file mode 100644 index 0000000000..f9691c353b --- /dev/null +++ b/src/main/java/com/gmail/nossr50/skills/AlternateFiringSuperSkill.java @@ -0,0 +1,13 @@ +package com.gmail.nossr50.skills; + +public interface AlternateFiringSuperSkill { + int chargeSuper(); + + void fireSuper(); + + void resetCharge(); + + boolean isReadyToFire(); + + long lastChargeTime(); +} diff --git a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java index 60def74bff..09ddceadbb 100644 --- a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java @@ -4,6 +4,7 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.skills.AlternateFiringSuperSkill; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.MetadataConstants; import com.gmail.nossr50.util.Permissions; @@ -22,11 +23,15 @@ import static com.gmail.nossr50.util.skills.CombatUtils.delayArrowMetaCleanup; -public class CrossbowsManager extends SkillManager { +public class CrossbowsManager extends SkillManager implements AlternateFiringSuperSkill { public CrossbowsManager(McMMOPlayer mmoPlayer) { super(mmoPlayer, PrimarySkillType.CROSSBOWS); } + private long lastChargeTime = 0; + + private int crossbowSuperWindupState = 0; + public void handleRicochet(@NotNull Plugin pluginRef, @NotNull Arrow arrow, @NotNull Vector hitBlockNormal) { if(!arrow.isShotFromCrossbow()) return; @@ -105,4 +110,38 @@ public double poweredShot(double oldDamage) { return oldDamage; } } + + @Override + public int chargeSuper() { + if (lastChargeTime < System.currentTimeMillis() - 2000) { + crossbowSuperWindupState = 0; + } + + if (crossbowSuperWindupState < 3) { + crossbowSuperWindupState++; + } + + lastChargeTime = System.currentTimeMillis(); + return crossbowSuperWindupState; + } + + @Override + public void fireSuper() { + // TODO: Impl + } + + @Override + public void resetCharge() { + crossbowSuperWindupState = 0; + } + + @Override + public boolean isReadyToFire() { + return crossbowSuperWindupState == 3; + } + + @Override + public long lastChargeTime() { + return lastChargeTime; + } } diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index 164ebf1221..d9a42ffcd0 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -51,10 +51,10 @@ private CombatUtils() {} // TODO: Unit tests public static void processProjectileSkillSuperAbilityActivation(McMMOPlayer mmoPlayer, ItemStack heldItem) { + // TODO: Support archery super as well if (heldItem != null && mmoPlayer != null) { - if (ItemUtils.isBowOrCrossbow(heldItem)) { - boolean isCrossbow = ItemUtils.isCrossbow(heldItem); - mmoPlayer.checkAbilityActivationProjectiles(isCrossbow); + if (ItemUtils.isCrossbow(heldItem)) { + mmoPlayer.checkCrossbowAbilityActivation(); } } } From ef3887a72057057b664982702913693134490162 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sat, 30 Mar 2024 04:44:10 -0700 Subject: [PATCH 68/75] fix unit tests --- .../com/gmail/nossr50/party/PartyManager.java | 61 +------ .../gmail/nossr50/MMOMinimalPluginMock.java | 163 ------------------ .../com/gmail/nossr50/MMOTestEnvironment.java | 11 ++ .../gmail/nossr50/party/PartyManagerTest.java | 53 +++--- .../util/random/ProbabilityUtilTest.java | 1 - .../nossr50/util/random/RandomChanceTest.java | 100 ----------- .../nossr50/util/text/TextUtilsTest.java | 2 +- 7 files changed, 41 insertions(+), 350 deletions(-) delete mode 100644 src/test/java/com/gmail/nossr50/MMOMinimalPluginMock.java delete mode 100644 src/test/java/com/gmail/nossr50/util/random/RandomChanceTest.java diff --git a/src/main/java/com/gmail/nossr50/party/PartyManager.java b/src/main/java/com/gmail/nossr50/party/PartyManager.java index 130a9b9968..aae00c9de3 100644 --- a/src/main/java/com/gmail/nossr50/party/PartyManager.java +++ b/src/main/java/com/gmail/nossr50/party/PartyManager.java @@ -55,22 +55,12 @@ public PartyManager(@NotNull mcMMO pluginRef) { * @return true if party is full and cannot be joined */ public boolean isPartyFull(@NotNull Player player, @NotNull Party targetParty) { - requireNonNull(player, "player cannot be null!"); - requireNonNull(targetParty, "targetParty cannot be null!"); return !Permissions.partySizeBypass(player) && pluginRef.getGeneralConfig().getPartyMaxSize() >= 1 && targetParty.getOnlineMembers().size() >= pluginRef.getGeneralConfig().getPartyMaxSize(); } public boolean areAllies(@NotNull Player firstPlayer, @NotNull Player secondPlayer) { - requireNonNull(firstPlayer, "firstPlayer cannot be null!"); - requireNonNull(secondPlayer, "secondPlayer cannot be null!"); - - //Profile not loaded - if (UserManager.getPlayer(firstPlayer) == null) { - return false; - } - - //Profile not loaded - if (UserManager.getPlayer(secondPlayer) == null) { + //Profile is not loaded + if (UserManager.getPlayer(firstPlayer) == null || UserManager.getPlayer(secondPlayer) == null) { return false; } @@ -110,7 +100,6 @@ public boolean areAllies(@NotNull Player firstPlayer, @NotNull Player secondPlay } public @NotNull List getNearVisibleMembers(@NotNull McMMOPlayer mmoPlayer) { - requireNonNull(mmoPlayer, "mmoPlayer cannot be null!"); List nearMembers = new ArrayList<>(); Party party = mmoPlayer.getParty(); @@ -137,7 +126,6 @@ public boolean areAllies(@NotNull Player firstPlayer, @NotNull Player secondPlay * @return all the players in the player's party */ public @NotNull LinkedHashMap getAllMembers(@NotNull Player player) { - requireNonNull(player, "player cannot be null!"); Party party = getParty(player); return party == null ? new LinkedHashMap<>() : party.getMembers(); @@ -150,7 +138,6 @@ public boolean areAllies(@NotNull Player firstPlayer, @NotNull Player secondPlay * @return all online players in this party */ public @NotNull List getOnlineMembers(@NotNull String partyName) { - requireNonNull(partyName, "partyName cannot be null!"); return getOnlineMembers(getParty(partyName)); } @@ -161,7 +148,6 @@ public boolean areAllies(@NotNull Player firstPlayer, @NotNull Player secondPlay * @return all online players in this party */ public @NotNull List getOnlineMembers(@NotNull Player player) { - requireNonNull(player, "player cannot be null!"); return getOnlineMembers(getParty(player)); } @@ -176,7 +162,6 @@ private List getOnlineMembers(@Nullable Party party) { * @return the existing party, null otherwise */ public @Nullable Party getParty(@NotNull String partyName) { - requireNonNull(partyName, "partyName cannot be null!"); for (Party party : parties) { if (party.getName().equalsIgnoreCase(partyName)) { return party; @@ -194,7 +179,6 @@ private List getOnlineMembers(@Nullable Party party) { */ @Deprecated public @Nullable Party getPlayerParty(@NotNull String playerName) { - requireNonNull(playerName, "playerName cannot be null!"); for (Party party : parties) { if (party.getMembers().containsValue(playerName)) { return party; @@ -211,8 +195,6 @@ private List getOnlineMembers(@Nullable Party party) { * @return the existing party, null otherwise */ public @Nullable Party getPlayerParty(@NotNull String playerName, @NotNull UUID uuid) { - requireNonNull(playerName, "playerName cannot be null!"); - requireNonNull(uuid, "uuid cannot be null!"); for (Party party : parties) { LinkedHashMap members = party.getMembers(); if (members.containsKey(uuid) || members.containsValue(playerName)) { @@ -236,8 +218,7 @@ private List getOnlineMembers(@Nullable Party party) { * @return the existing party, null otherwise */ public @Nullable Party getParty(@NotNull Player player) { - requireNonNull(player, "player cannot be null!"); - //Profile not loaded + //Profile is not loaded if (UserManager.getPlayer(player) == null) { return null; } @@ -265,9 +246,6 @@ private List getOnlineMembers(@Nullable Party party) { * @param party The party */ public void removeFromParty(@NotNull OfflinePlayer player, @NotNull Party party) { - requireNonNull(player, "player cannot be null!"); - requireNonNull(party, "party cannot be null!"); - LinkedHashMap members = party.getMembers(); String playerName = player.getName(); @@ -295,7 +273,6 @@ public void removeFromParty(@NotNull OfflinePlayer player, @NotNull Party party) * @param mcMMOPlayer The player to remove */ public void removeFromParty(@NotNull McMMOPlayer mcMMOPlayer) { - requireNonNull(mcMMOPlayer, "mcMMOPlayer cannot be null!"); if (mcMMOPlayer.getParty() == null) { return; } @@ -311,7 +288,6 @@ public void removeFromParty(@NotNull McMMOPlayer mcMMOPlayer) { * @deprecated Use {@link #disbandParty(McMMOPlayer, Party)} */ public void disbandParty(@NotNull Party party) { - requireNonNull(party, "party cannot be null!"); disbandParty(null, party); } @@ -322,7 +298,6 @@ public void disbandParty(@NotNull Party party) { * @param party The party to remove */ public void disbandParty(@Nullable McMMOPlayer mcMMOPlayer, @NotNull Party party) { - requireNonNull(party, "party cannot be null!"); //TODO: Potential issues with unloaded profile? for (final Player member : party.getOnlineMembers()) { //Profile not loaded @@ -352,9 +327,6 @@ public void disbandParty(@Nullable McMMOPlayer mcMMOPlayer, @NotNull Party party * @param password The password for this party, null if there was no password */ public void createParty(@NotNull McMMOPlayer mcMMOPlayer, @NotNull String partyName, @Nullable String password) { - requireNonNull(mcMMOPlayer, "mcMMOPlayer cannot be null!"); - requireNonNull(partyName, "partyName cannot be null!"); - Player player = mcMMOPlayer.getPlayer(); Party party = new Party(new PartyLeader(player.getUniqueId(), player.getName()), partyName.replace(".", ""), password); @@ -407,7 +379,6 @@ public boolean checkPartyPassword(@NotNull Player player, @NotNull Party party, * @param mcMMOPlayer The player to add to the party */ public void joinInvitedParty(@NotNull McMMOPlayer mcMMOPlayer) { - requireNonNull(mcMMOPlayer, "mcMMOPlayer cannot be null!"); Party invite = mcMMOPlayer.getPartyInvite(); // Check if the party still exists, it might have been disbanded @@ -435,7 +406,6 @@ public void joinInvitedParty(@NotNull McMMOPlayer mcMMOPlayer) { * @param mcMMOPlayer The player who accepts the alliance invite */ public void acceptAllianceInvite(@NotNull McMMOPlayer mcMMOPlayer) { - requireNonNull(mcMMOPlayer, "mcMMOPlayer cannot be null!"); Party invite = mcMMOPlayer.getPartyAllianceInvite(); Player player = mcMMOPlayer.getPlayer(); @@ -456,9 +426,6 @@ public void acceptAllianceInvite(@NotNull McMMOPlayer mcMMOPlayer) { } public void createAlliance(@NotNull Party firstParty, @NotNull Party secondParty) { - requireNonNull(firstParty, "firstParty cannot be null!"); - requireNonNull(secondParty, "secondParty cannot be null!"); - firstParty.setAlly(secondParty); secondParty.setAlly(firstParty); @@ -472,10 +439,6 @@ public void createAlliance(@NotNull Party firstParty, @NotNull Party secondParty } public boolean disbandAlliance(@NotNull Player player, @NotNull Party firstParty, @NotNull Party secondParty) { - requireNonNull(player, "player cannot be null!"); - requireNonNull(firstParty, "firstParty cannot be null!"); - requireNonNull(secondParty, "secondParty cannot be null!"); - if (!handlePartyChangeAllianceEvent(player, firstParty.getName(), secondParty.getName(), McMMOPartyAllianceChangeEvent.EventReason.DISBAND_ALLIANCE)) { return false; } @@ -485,8 +448,6 @@ public boolean disbandAlliance(@NotNull Player player, @NotNull Party firstParty } private void disbandAlliance(@NotNull Party firstParty, @NotNull Party secondParty) { - requireNonNull(firstParty, "firstParty cannot be null!"); - requireNonNull(secondParty, "secondParty cannot be null!"); firstParty.setAlly(null); secondParty.setAlly(null); @@ -506,9 +467,6 @@ private void disbandAlliance(@NotNull Party firstParty, @NotNull Party secondPar * @param party The party */ public void addToParty(@NotNull McMMOPlayer mcMMOPlayer, @NotNull Party party) { - requireNonNull(mcMMOPlayer, "mcMMOPlayer cannot be null!"); - requireNonNull(party, "party cannot be null!"); - Player player = mcMMOPlayer.getPlayer(); String playerName = player.getName(); @@ -525,7 +483,6 @@ public void addToParty(@NotNull McMMOPlayer mcMMOPlayer, @NotNull Party party) { * @return the leader of the party */ public @Nullable String getPartyLeaderName(@NotNull String partyName) { - requireNonNull(partyName, "partyName cannot be null!"); Party party = getParty(partyName); return party == null ? null : party.getLeader().getPlayerName(); @@ -538,8 +495,6 @@ public void addToParty(@NotNull McMMOPlayer mcMMOPlayer, @NotNull Party party) { * @param party The party */ public void setPartyLeader(@NotNull UUID uuid, @NotNull Party party) { - requireNonNull(uuid, "uuid cannot be null!"); - requireNonNull(party, "party cannot be null!"); OfflinePlayer player = pluginRef.getServer().getOfflinePlayer(uuid); UUID leaderUniqueId = party.getLeader().getUniqueId(); @@ -564,7 +519,6 @@ public void setPartyLeader(@NotNull UUID uuid, @NotNull Party party) { * @return true if the player can invite */ public boolean canInvite(@NotNull McMMOPlayer mcMMOPlayer) { - requireNonNull(mcMMOPlayer, "mcMMOPlayer cannot be null!"); Party party = mcMMOPlayer.getParty(); return !party.isLocked() || party.getLeader().getUniqueId().equals(mcMMOPlayer.getPlayer().getUniqueId()); @@ -578,9 +532,6 @@ public boolean canInvite(@NotNull McMMOPlayer mcMMOPlayer) { * @return true if a party with that name exists, false otherwise */ public boolean checkPartyExistence(@NotNull Player player, @NotNull String partyName) { - requireNonNull(player, "player cannot be null!"); - requireNonNull(partyName, "partyName cannot be null!"); - if (getParty(partyName) == null) { return false; } @@ -597,9 +548,6 @@ public boolean checkPartyExistence(@NotNull Player player, @NotNull String party * @return true if the party was joined successfully, false otherwise */ public boolean changeOrJoinParty(@NotNull McMMOPlayer mmoPlayer, @NotNull String newPartyName) { - requireNonNull(mmoPlayer, "mmoPlayer cannot be null!"); - requireNonNull(newPartyName, "newPartyName cannot be null!"); - final Player player = mmoPlayer.getPlayer(); if (mmoPlayer.inParty()) { @@ -623,9 +571,6 @@ public boolean changeOrJoinParty(@NotNull McMMOPlayer mmoPlayer, @NotNull String * @return true if they are in the same party, false otherwise */ public boolean inSameParty(@NotNull Player firstPlayer, @NotNull Player secondPlayer) { - requireNonNull(firstPlayer, "firstPlayer cannot be null!"); - requireNonNull(secondPlayer, "secondPlayer cannot be null!"); - //Profile not loaded if (UserManager.getPlayer(firstPlayer) == null) { return false; diff --git a/src/test/java/com/gmail/nossr50/MMOMinimalPluginMock.java b/src/test/java/com/gmail/nossr50/MMOMinimalPluginMock.java deleted file mode 100644 index 1ecfce764f..0000000000 --- a/src/test/java/com/gmail/nossr50/MMOMinimalPluginMock.java +++ /dev/null @@ -1,163 +0,0 @@ -package com.gmail.nossr50; - -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.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 org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.Server; -import org.bukkit.World; -import org.bukkit.entity.Player; -import org.bukkit.plugin.PluginManager; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -import java.util.logging.Logger; - -import static org.mockito.ArgumentMatchers.any; - -public abstract class MMOMinimalPluginMock { - protected MockedStatic mockedMcMMO; - protected MockedStatic mockedChatConfig; - protected MockedStatic experienceConfig; - protected MockedStatic mockedPermissions; - protected MockedStatic mockedRankUtils; - protected MockedStatic mockedUserManager; - protected MockedStatic mockedMisc; - protected MockedStatic mockedEventUtils; - protected TransientEntityTracker transientEntityTracker; - protected AdvancedConfig advancedConfig; - protected GeneralConfig generalConfig; - protected RankConfig rankConfig; - protected Server server; - protected PluginManager pluginManager; - protected World world; - - /* Mocks */ - protected ChunkManager chunkManager; - - protected void mockEnvironment(Logger logger) { - mockedMcMMO = Mockito.mockStatic(mcMMO.class); - mcMMO.p = Mockito.mock(mcMMO.class); - Mockito.when(mcMMO.p.getLogger()).thenReturn(logger); - - // place store - chunkManager = Mockito.mock(ChunkManager.class); - Mockito.when(mcMMO.getPlaceStore()).thenReturn(chunkManager); - - // shut off mod manager for woodcutting - Mockito.when(mcMMO.getModManager()).thenReturn(Mockito.mock(ModManager.class)); - Mockito.when(mcMMO.getModManager().isCustomLog(any())).thenReturn(false); - - // chat config - mockedChatConfig = Mockito.mockStatic(ChatConfig.class); - Mockito.when(ChatConfig.getInstance()).thenReturn(Mockito.mock(ChatConfig.class)); - - // general config - mockGeneralConfig(); - - // rank config - mockRankConfig(); - - // wire advanced config - mockAdvancedConfig(); - - // wire experience config - mockExperienceConfig(); - - this.transientEntityTracker = new TransientEntityTracker(); - Mockito.when(mcMMO.getTransientEntityTracker()).thenReturn(transientEntityTracker); - - mockPermissions(); - - mockedRankUtils = Mockito.mockStatic(RankUtils.class); - - // wire server - this.server = Mockito.mock(Server.class); - Mockito.when(mcMMO.p.getServer()).thenReturn(server); - - // wire plugin manager - this.pluginManager = Mockito.mock(PluginManager.class); - Mockito.when(server.getPluginManager()).thenReturn(pluginManager); - - // wire world - this.world = Mockito.mock(World.class); - - // wire Misc - this.mockedMisc = Mockito.mockStatic(Misc.class); - Mockito.when(Misc.getBlockCenter(any())).thenReturn(new Location(world, 0, 0, 0)); - - // wire user manager - this.mockedUserManager = Mockito.mockStatic(UserManager.class); - } - - private void mockPermissions() { - mockedPermissions = Mockito.mockStatic(Permissions.class); - Mockito.when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); - Mockito.when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn(true); - Mockito.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 = Mockito.mock(RankConfig.class); - } - - private void mockAdvancedConfig() { - this.advancedConfig = Mockito.mock(AdvancedConfig.class); - Mockito.when(mcMMO.p.getAdvancedConfig()).thenReturn(advancedConfig); - } - - private void mockGeneralConfig() { - generalConfig = Mockito.mock(GeneralConfig.class); - Mockito.when(generalConfig.getTreeFellerThreshold()).thenReturn(100); - Mockito.when(generalConfig.getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, Material.OAK_LOG)).thenReturn(true); - Mockito.when(generalConfig.getLocale()).thenReturn("en_US"); - Mockito.when(mcMMO.p.getGeneralConfig()).thenReturn(generalConfig); - } - - private void mockExperienceConfig() { - experienceConfig = Mockito.mockStatic(ExperienceConfig.class); - - Mockito.when(ExperienceConfig.getInstance()).thenReturn(Mockito.mock(ExperienceConfig.class)); - - // Combat - Mockito.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(); - } - } -} diff --git a/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java b/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java index 973cf0f282..d995ed569f 100644 --- a/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java +++ b/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java @@ -6,6 +6,7 @@ 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; @@ -44,6 +45,7 @@ public abstract class MMOTestEnvironment { protected MockedStatic mockedEventUtils; protected TransientEntityTracker transientEntityTracker; protected AdvancedConfig advancedConfig; + protected PartyConfig partyConfig; protected GeneralConfig generalConfig; protected RankConfig rankConfig; protected SkillTools skillTools; @@ -85,6 +87,9 @@ protected void mockBaseEnvironment(Logger logger) throws InvalidSkillException { // general config mockGeneralConfig(); + // party config + mockPartyConfig(); + // rank config mockRankConfig(); @@ -166,6 +171,12 @@ private void mockGeneralConfig() { 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); diff --git a/src/test/java/com/gmail/nossr50/party/PartyManagerTest.java b/src/test/java/com/gmail/nossr50/party/PartyManagerTest.java index bd4e2d629d..25d74515be 100644 --- a/src/test/java/com/gmail/nossr50/party/PartyManagerTest.java +++ b/src/test/java/com/gmail/nossr50/party/PartyManagerTest.java @@ -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 @@ public void createPartyWithoutPasswordShouldSucceed() { @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,29 +69,28 @@ public void createPartyWithPasswordShouldSucceed() { @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); when(player.getUniqueId()).thenReturn(new UUID(0, 0)); // When & Then - assertThrows(NullPointerException.class, + assertThrows(IllegalArgumentException.class, () -> partyManager.createParty(mmoPlayer, null, partyPassword)); } @Test public void createPartyWithoutPlayerShouldFail() { // Given - PartyManager partyManager = new PartyManager(mockMcMMO); + PartyManager partyManager = new PartyManager(mcMMO.p); String partyName = "TestParty"; String partyPassword = "somePassword"; // When & Then - assertThrows(NullPointerException.class, + assertThrows(IllegalArgumentException.class, () -> partyManager.createParty(null, partyName, partyPassword)); } diff --git a/src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java b/src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java index 36419f9e4f..35f134da5c 100644 --- a/src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java +++ b/src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java @@ -16,7 +16,6 @@ import static org.mockito.Mockito.when; class ProbabilityUtilTest { - mcMMO mmoInstance; AdvancedConfig advancedConfig; diff --git a/src/test/java/com/gmail/nossr50/util/random/RandomChanceTest.java b/src/test/java/com/gmail/nossr50/util/random/RandomChanceTest.java deleted file mode 100644 index 982acdc6be..0000000000 --- a/src/test/java/com/gmail/nossr50/util/random/RandomChanceTest.java +++ /dev/null @@ -1,100 +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, PrimarySkillType.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.MINING; -// subSkillType = SubSkillType.MINING_MOTHER_LODE; -// -// //TODO: Likely needs to be changed per skill if more tests were added -// PowerMockito.stub(PowerMockito.method(RandomChanceUtil.class, "getMaximumProbability", subSkillType.getClass())).toReturn(10.0D); -// PowerMockito.stub(PowerMockito.method(RandomChanceUtil.class, "getMaxBonusLevelCap", subSkillType.getClass())).toReturn(10000D); -// -// 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(2150); -// Mockito.when(mmoPlayerLucky.getSkillLevel(primarySkillType)).thenReturn(2150); -// } -// -// @Test -// public void testLuckyChance() { -// System.out.println(testASCIIHeader); -// System.out.println("Testing success odds to fall within expected values..."); -// assertEquals(2.15D, getSuccessChance(mmoPlayerNormal),0.00D); -// assertEquals(2.15D * RandomChanceUtil.LUCKY_MODIFIER, getSuccessChance(mmoPlayerLucky),0.00D); -// } -// -//// @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!"); -//// } -//// } -// -// -// -// -// -// 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); -// } -//} diff --git a/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java b/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java index cefbe70102..c581571791 100644 --- a/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java +++ b/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java @@ -7,7 +7,7 @@ /** * 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. * From bf901a0a34b3dadfb3520a47c37c0c01c3372725 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sat, 30 Mar 2024 05:05:28 -0700 Subject: [PATCH 69/75] remove unimplemented features, fix tests again, and optimize imports --- .../java/com/gmail/nossr50/api/PartyAPI.java | 2 - .../commands/chat/PartyChatCommand.java | 1 - .../commands/party/PartyAcceptCommand.java | 1 - .../party/PartyChangeOwnerCommand.java | 1 - .../commands/party/PartyCreateCommand.java | 1 - .../commands/party/PartyDisbandCommand.java | 1 - .../commands/party/PartyInfoCommand.java | 1 - .../commands/party/PartyInviteCommand.java | 1 - .../commands/party/PartyJoinCommand.java | 1 - .../commands/party/PartyKickCommand.java | 1 - .../commands/party/PartyQuitCommand.java | 1 - .../commands/party/PartyRenameCommand.java | 1 - .../alliance/PartyAllianceAcceptCommand.java | 1 - .../party/alliance/PartyAllianceCommand.java | 1 - .../alliance/PartyAllianceDisbandCommand.java | 1 - .../alliance/PartyAllianceInviteCommand.java | 1 - .../commands/party/teleport/PtpCommand.java | 1 - .../gmail/nossr50/datatypes/party/Party.java | 1 - .../nossr50/datatypes/player/McMMOPlayer.java | 69 ------------------- .../datatypes/skills/SubSkillType.java | 3 - .../datatypes/skills/SuperAbilityType.java | 2 - .../nossr50/listeners/PlayerListener.java | 16 ----- .../com/gmail/nossr50/party/PartyManager.java | 58 +++++++++++++++- .../nossr50/runnables/SaveTimerTask.java | 1 - .../runnables/items/TeleportationWarmup.java | 1 - .../runnables/party/PartyAutoKickTask.java | 1 - .../nossr50/runnables/skills/RuptureTask.java | 1 - .../skills/AlternateFiringSuperSkill.java | 13 ---- .../nossr50/skills/crossbows/Crossbows.java | 1 - .../skills/crossbows/CrossbowsManager.java | 41 +---------- .../com/gmail/nossr50/util/Permissions.java | 11 --- .../nossr50/util/skills/CombatUtils.java | 12 ---- .../gmail/nossr50/util/skills/SkillUtils.java | 8 +-- src/main/resources/advanced.yml | 4 +- .../resources/locale/locale_en_US.properties | 18 +++-- src/main/resources/plugin.yml | 6 -- src/main/resources/skillranks.yml | 15 ---- .../gmail/nossr50/party/PartyManagerTest.java | 4 +- 38 files changed, 73 insertions(+), 231 deletions(-) delete mode 100644 src/main/java/com/gmail/nossr50/skills/AlternateFiringSuperSkill.java diff --git a/src/main/java/com/gmail/nossr50/api/PartyAPI.java b/src/main/java/com/gmail/nossr50/api/PartyAPI.java index ce5efaf6e1..e86bf46195 100644 --- a/src/main/java/com/gmail/nossr50/api/PartyAPI.java +++ b/src/main/java/com/gmail/nossr50/api/PartyAPI.java @@ -5,10 +5,8 @@ import com.gmail.nossr50.datatypes.party.PartyLeader; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; -import jdk.jfr.Experimental; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/gmail/nossr50/commands/chat/PartyChatCommand.java b/src/main/java/com/gmail/nossr50/commands/chat/PartyChatCommand.java index acd7a6168b..cfdbc61d87 100644 --- a/src/main/java/com/gmail/nossr50/commands/chat/PartyChatCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/chat/PartyChatCommand.java @@ -11,7 +11,6 @@ import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.text.StringUtils; import org.bukkit.entity.Player; diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyAcceptCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyAcceptCommand.java index 7febacd11e..3b9d07f628 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyAcceptCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyAcceptCommand.java @@ -3,7 +3,6 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyChangeOwnerCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyChangeOwnerCommand.java index 28d5079f71..29b3d64d11 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyChangeOwnerCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyChangeOwnerCommand.java @@ -3,7 +3,6 @@ import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.OfflinePlayer; diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyCreateCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyCreateCommand.java index 80d4d23ee8..75a7c785c0 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyCreateCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyCreateCommand.java @@ -3,7 +3,6 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyDisbandCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyDisbandCommand.java index 3b0ed16bc8..ac16d357bb 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyDisbandCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyDisbandCommand.java @@ -5,7 +5,6 @@ import com.gmail.nossr50.events.party.McMMOPartyChangeEvent.EventReason; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyInfoCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyInfoCommand.java index c177079267..3e34078e8d 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyInfoCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyInfoCommand.java @@ -6,7 +6,6 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.ChatColor; import org.bukkit.command.Command; diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyInviteCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyInviteCommand.java index 65abe4e823..91d6b39be8 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyInviteCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyInviteCommand.java @@ -4,7 +4,6 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.Command; diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyJoinCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyJoinCommand.java index be170cd4e4..a5474d355b 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyJoinCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyJoinCommand.java @@ -4,7 +4,6 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.Command; diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyKickCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyKickCommand.java index b9218b9806..9ee2de0892 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyKickCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyKickCommand.java @@ -4,7 +4,6 @@ import com.gmail.nossr50.events.party.McMMOPartyChangeEvent.EventReason; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.OfflinePlayer; diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyQuitCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyQuitCommand.java index 920f69ac95..880541adda 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyQuitCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyQuitCommand.java @@ -5,7 +5,6 @@ import com.gmail.nossr50.events.party.McMMOPartyChangeEvent.EventReason; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyRenameCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyRenameCommand.java index c6e55fc4a2..7d2954ad0b 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyRenameCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyRenameCommand.java @@ -5,7 +5,6 @@ import com.gmail.nossr50.events.party.McMMOPartyChangeEvent.EventReason; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; diff --git a/src/main/java/com/gmail/nossr50/commands/party/alliance/PartyAllianceAcceptCommand.java b/src/main/java/com/gmail/nossr50/commands/party/alliance/PartyAllianceAcceptCommand.java index 2e8eed2d51..b4bb002abc 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/alliance/PartyAllianceAcceptCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/alliance/PartyAllianceAcceptCommand.java @@ -3,7 +3,6 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; diff --git a/src/main/java/com/gmail/nossr50/commands/party/alliance/PartyAllianceCommand.java b/src/main/java/com/gmail/nossr50/commands/party/alliance/PartyAllianceCommand.java index 5e47a451cf..e39e7c3e2b 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/alliance/PartyAllianceCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/alliance/PartyAllianceCommand.java @@ -5,7 +5,6 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import com.google.common.collect.ImmutableList; diff --git a/src/main/java/com/gmail/nossr50/commands/party/alliance/PartyAllianceDisbandCommand.java b/src/main/java/com/gmail/nossr50/commands/party/alliance/PartyAllianceDisbandCommand.java index c8f2609e0f..6b5e2dceae 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/alliance/PartyAllianceDisbandCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/alliance/PartyAllianceDisbandCommand.java @@ -4,7 +4,6 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; diff --git a/src/main/java/com/gmail/nossr50/commands/party/alliance/PartyAllianceInviteCommand.java b/src/main/java/com/gmail/nossr50/commands/party/alliance/PartyAllianceInviteCommand.java index 855a525e8a..04d12b649b 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/alliance/PartyAllianceInviteCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/alliance/PartyAllianceInviteCommand.java @@ -4,7 +4,6 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.Command; diff --git a/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpCommand.java b/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpCommand.java index e757688f82..10f0f1d98e 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpCommand.java @@ -7,7 +7,6 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.runnables.items.TeleportationWarmup; import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.Misc; diff --git a/src/main/java/com/gmail/nossr50/datatypes/party/Party.java b/src/main/java/com/gmail/nossr50/datatypes/party/Party.java index 9b684c7420..78ffb99663 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/party/Party.java +++ b/src/main/java/com/gmail/nossr50/datatypes/party/Party.java @@ -6,7 +6,6 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.sounds.SoundManager; diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index c7972ab279..91ec48fb4f 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -20,12 +20,9 @@ import com.gmail.nossr50.events.experience.McMMOPlayerPreXpGainEvent; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.party.ShareHandler; -import com.gmail.nossr50.runnables.skills.AbilityCooldownTask; import com.gmail.nossr50.runnables.skills.AbilityDisableTask; import com.gmail.nossr50.runnables.skills.ToolLowerTask; -import com.gmail.nossr50.skills.AlternateFiringSuperSkill; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager; import com.gmail.nossr50.skills.alchemy.AlchemyManager; @@ -964,72 +961,6 @@ public void checkAbilityActivation(PrimarySkillType primarySkillType) { mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(player, new AbilityDisableTask(this, superAbilityType), (long) ticks * Misc.TICK_CONVERSION_FACTOR); } - public void checkCrossbowAbilityActivation() { - PrimarySkillType primarySkillType = PrimarySkillType.CROSSBOWS; - ToolType tool = ToolType.CROSSBOW; - SuperAbilityType superAbilityType = SuperAbilityType.SUPER_SHOTGUN; - SubSkillType subSkillType = SubSkillType.CROSSBOWS_SUPER_SHOTGUN; - AlternateFiringSuperSkill skillManager = getCrossbowsManager(); - - // Check permission - if (!superAbilityType.getPermissions(player)) { - return; - } - - //TODO: This is hacky and temporary solution until skills are move to the new system - //Potential problems with this include skills with two super abilities (ie mining) - if(!RankUtils.hasUnlockedSubskill(player, subSkillType)) - { - int diff = RankUtils.getSuperAbilityUnlockRequirement(superAbilityType) - getSkillLevel(primarySkillType); - - //Inform the player they are not yet skilled enough - NotificationManager.sendPlayerInformation(player, - NotificationType.ABILITY_COOLDOWN, - "Skills.AbilityGateRequirementFail", - String.valueOf(diff), - mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType)); - return; - } - - // Call the event - if (EventUtils.callPlayerAbilityActivateEvent(player, primarySkillType).isCancelled()) { - return; - } - - // Check if we can fire the ability - if (!skillManager.isReadyToFire()) { - return; - } - - if (useChatNotifications()) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUPER_ABILITY, superAbilityType.getAbilityOn()); - } - - if (mcMMO.p.getAdvancedConfig().sendAbilityNotificationToOtherPlayers()) { - SkillUtils.sendSkillMessage(player, NotificationType.SUPER_ABILITY_ALERT_OTHERS, superAbilityType.getAbilityPlayer()); - } - - //Sounds - SoundManager.worldSendSound(player.getWorld(), player.getLocation(), SoundType.ABILITY_ACTIVATED_GENERIC); - - // TODO: Fire the ability - profile.setAbilityDATS(superAbilityType, System.currentTimeMillis()); - setToolPreparationMode(tool, false); - skillManager.resetCharge(); - skillManager.fireSuper(); - - if(!mcMMO.isServerShutdownExecuted()) { - mcMMO.p.getFoliaLib().getImpl().runAtEntityLater( - player, - new AbilityCooldownTask(this, superAbilityType), - (long) PerksUtils.handleCooldownPerks(player, superAbilityType.getCooldown()) * Misc.TICK_CONVERSION_FACTOR); - } - } - - public void chargeCrossbowSuper() { - getCrossbowsManager().chargeSuper(); - } - public void processAbilityActivation(@NotNull PrimarySkillType primarySkillType) { if (!mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(getPlayer(), primarySkillType)) { return; diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java index b388ecb4ee..e6bcb079f4 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java @@ -22,7 +22,6 @@ public enum SubSkillType { ARCHERY_DAZE, ARCHERY_SKILL_SHOT(20), ARCHERY_ARCHERY_LIMIT_BREAK(10), - ARCHERY_EXPLOSIVE_SHOT(1), /* Axes */ AXES_ARMOR_IMPACT(20), @@ -33,7 +32,6 @@ public enum SubSkillType { AXES_SKULL_SPLITTER(1), /* CROSSBOWS */ - CROSSBOWS_SUPER_SHOTGUN(1), CROSSBOWS_CROSSBOWS_LIMIT_BREAK(10), CROSSBOWS_TRICK_SHOT(3), CROSSBOWS_POWERED_SHOT(20), @@ -101,7 +99,6 @@ public enum SubSkillType { TAMING_THICK_FUR(1), /* Tridents */ - TRIDENTS_SUPER(1), TRIDENTS_IMPALE(10), TRIDENTS_TRIDENTS_LIMIT_BREAK(10), diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java index dab6d948d7..f876ce53ed 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java @@ -112,8 +112,6 @@ public enum SuperAbilityType { TREE_FELLER.subSkillTypeDefinition = SubSkillType.WOODCUTTING_TREE_FELLER; SERRATED_STRIKES.subSkillTypeDefinition = SubSkillType.SWORDS_SERRATED_STRIKES; BLAST_MINING.subSkillTypeDefinition = SubSkillType.MINING_BLAST_MINING; - TRIDENTS_SUPER_ABILITY.subSkillTypeDefinition = SubSkillType.TRIDENTS_SUPER; - SUPER_SHOTGUN.subSkillTypeDefinition = SubSkillType.CROSSBOWS_SUPER_SHOTGUN; } private final String abilityOn; diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java index dc555eb21b..ab1526382b 100644 --- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java @@ -24,7 +24,6 @@ import com.gmail.nossr50.util.*; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; -import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.sounds.SoundManager; @@ -828,11 +827,6 @@ public void onPlayerInteractMonitor(PlayerInteractEvent event) { mcMMOPlayer.processAbilityActivation(PrimarySkillType.HERBALISM); } - // Projectile Skills - if (ItemUtils.isCrossbow(heldItem) || ItemUtils.isBow(heldItem)) { - CombatUtils.processProjectileSkillSuperAbilityActivation(mcMMOPlayer, heldItem); - } - mcMMOPlayer.processAbilityActivation(PrimarySkillType.AXES); mcMMOPlayer.processAbilityActivation(PrimarySkillType.EXCAVATION); mcMMOPlayer.processAbilityActivation(PrimarySkillType.MINING); @@ -904,11 +898,6 @@ else if (herbalismManager.canUseShroomThumb(blockState)) { mcMMOPlayer.processAbilityActivation(PrimarySkillType.SWORDS); mcMMOPlayer.processAbilityActivation(PrimarySkillType.UNARMED); mcMMOPlayer.processAbilityActivation(PrimarySkillType.WOODCUTTING); - - // Projectile Skills - if (ItemUtils.isCrossbow(heldItem) || ItemUtils.isBow(heldItem)) { - CombatUtils.processProjectileSkillSuperAbilityActivation(mcMMOPlayer, heldItem); - } } /* ITEM CHECKS */ @@ -929,11 +918,6 @@ else if (herbalismManager.canUseShroomThumb(blockState)) { break; } - // Check charge up supers (crossbows, etc...) - if (ItemUtils.isCrossbow(heldItem)) { - mcMMOPlayer.chargeCrossbowSuper(); - } - /* CALL OF THE WILD CHECKS */ Material type = heldItem.getType(); TamingManager tamingManager = mcMMOPlayer.getTamingManager(); diff --git a/src/main/java/com/gmail/nossr50/party/PartyManager.java b/src/main/java/com/gmail/nossr50/party/PartyManager.java index aae00c9de3..beff259d20 100644 --- a/src/main/java/com/gmail/nossr50/party/PartyManager.java +++ b/src/main/java/com/gmail/nossr50/party/PartyManager.java @@ -55,12 +55,22 @@ public PartyManager(@NotNull mcMMO pluginRef) { * @return true if party is full and cannot be joined */ public boolean isPartyFull(@NotNull Player player, @NotNull Party targetParty) { + requireNonNull(player, "player cannot be null!"); + requireNonNull(targetParty, "targetParty cannot be null!"); return !Permissions.partySizeBypass(player) && pluginRef.getGeneralConfig().getPartyMaxSize() >= 1 && targetParty.getOnlineMembers().size() >= pluginRef.getGeneralConfig().getPartyMaxSize(); } public boolean areAllies(@NotNull Player firstPlayer, @NotNull Player secondPlayer) { - //Profile is not loaded - if (UserManager.getPlayer(firstPlayer) == null || UserManager.getPlayer(secondPlayer) == null) { + requireNonNull(firstPlayer, "firstPlayer cannot be null!"); + requireNonNull(secondPlayer, "secondPlayer cannot be null!"); + + //Profile not loaded + if (UserManager.getPlayer(firstPlayer) == null) { + return false; + } + + //Profile not loaded + if (UserManager.getPlayer(secondPlayer) == null) { return false; } @@ -100,6 +110,7 @@ public boolean areAllies(@NotNull Player firstPlayer, @NotNull Player secondPlay } public @NotNull List getNearVisibleMembers(@NotNull McMMOPlayer mmoPlayer) { + requireNonNull(mmoPlayer, "mmoPlayer cannot be null!"); List nearMembers = new ArrayList<>(); Party party = mmoPlayer.getParty(); @@ -126,6 +137,7 @@ public boolean areAllies(@NotNull Player firstPlayer, @NotNull Player secondPlay * @return all the players in the player's party */ public @NotNull LinkedHashMap getAllMembers(@NotNull Player player) { + requireNonNull(player, "player cannot be null!"); Party party = getParty(player); return party == null ? new LinkedHashMap<>() : party.getMembers(); @@ -138,6 +150,7 @@ public boolean areAllies(@NotNull Player firstPlayer, @NotNull Player secondPlay * @return all online players in this party */ public @NotNull List getOnlineMembers(@NotNull String partyName) { + requireNonNull(partyName, "partyName cannot be null!"); return getOnlineMembers(getParty(partyName)); } @@ -148,6 +161,7 @@ public boolean areAllies(@NotNull Player firstPlayer, @NotNull Player secondPlay * @return all online players in this party */ public @NotNull List getOnlineMembers(@NotNull Player player) { + requireNonNull(player, "player cannot be null!"); return getOnlineMembers(getParty(player)); } @@ -162,6 +176,7 @@ private List getOnlineMembers(@Nullable Party party) { * @return the existing party, null otherwise */ public @Nullable Party getParty(@NotNull String partyName) { + requireNonNull(partyName, "partyName cannot be null!"); for (Party party : parties) { if (party.getName().equalsIgnoreCase(partyName)) { return party; @@ -179,6 +194,7 @@ private List getOnlineMembers(@Nullable Party party) { */ @Deprecated public @Nullable Party getPlayerParty(@NotNull String playerName) { + requireNonNull(playerName, "playerName cannot be null!"); for (Party party : parties) { if (party.getMembers().containsValue(playerName)) { return party; @@ -195,6 +211,8 @@ private List getOnlineMembers(@Nullable Party party) { * @return the existing party, null otherwise */ public @Nullable Party getPlayerParty(@NotNull String playerName, @NotNull UUID uuid) { + requireNonNull(playerName, "playerName cannot be null!"); + requireNonNull(uuid, "uuid cannot be null!"); for (Party party : parties) { LinkedHashMap members = party.getMembers(); if (members.containsKey(uuid) || members.containsValue(playerName)) { @@ -218,7 +236,8 @@ private List getOnlineMembers(@Nullable Party party) { * @return the existing party, null otherwise */ public @Nullable Party getParty(@NotNull Player player) { - //Profile is not loaded + requireNonNull(player, "player cannot be null!"); + //Profile not loaded if (UserManager.getPlayer(player) == null) { return null; } @@ -246,6 +265,9 @@ private List getOnlineMembers(@Nullable Party party) { * @param party The party */ public void removeFromParty(@NotNull OfflinePlayer player, @NotNull Party party) { + requireNonNull(player, "player cannot be null!"); + requireNonNull(party, "party cannot be null!"); + LinkedHashMap members = party.getMembers(); String playerName = player.getName(); @@ -273,6 +295,7 @@ public void removeFromParty(@NotNull OfflinePlayer player, @NotNull Party party) * @param mcMMOPlayer The player to remove */ public void removeFromParty(@NotNull McMMOPlayer mcMMOPlayer) { + requireNonNull(mcMMOPlayer, "mcMMOPlayer cannot be null!"); if (mcMMOPlayer.getParty() == null) { return; } @@ -288,6 +311,7 @@ public void removeFromParty(@NotNull McMMOPlayer mcMMOPlayer) { * @deprecated Use {@link #disbandParty(McMMOPlayer, Party)} */ public void disbandParty(@NotNull Party party) { + requireNonNull(party, "party cannot be null!"); disbandParty(null, party); } @@ -298,6 +322,7 @@ public void disbandParty(@NotNull Party party) { * @param party The party to remove */ public void disbandParty(@Nullable McMMOPlayer mcMMOPlayer, @NotNull Party party) { + requireNonNull(party, "party cannot be null!"); //TODO: Potential issues with unloaded profile? for (final Player member : party.getOnlineMembers()) { //Profile not loaded @@ -379,6 +404,7 @@ public boolean checkPartyPassword(@NotNull Player player, @NotNull Party party, * @param mcMMOPlayer The player to add to the party */ public void joinInvitedParty(@NotNull McMMOPlayer mcMMOPlayer) { + requireNonNull(mcMMOPlayer, "mcMMOPlayer cannot be null!"); Party invite = mcMMOPlayer.getPartyInvite(); // Check if the party still exists, it might have been disbanded @@ -406,6 +432,7 @@ public void joinInvitedParty(@NotNull McMMOPlayer mcMMOPlayer) { * @param mcMMOPlayer The player who accepts the alliance invite */ public void acceptAllianceInvite(@NotNull McMMOPlayer mcMMOPlayer) { + requireNonNull(mcMMOPlayer, "mcMMOPlayer cannot be null!"); Party invite = mcMMOPlayer.getPartyAllianceInvite(); Player player = mcMMOPlayer.getPlayer(); @@ -426,6 +453,9 @@ public void acceptAllianceInvite(@NotNull McMMOPlayer mcMMOPlayer) { } public void createAlliance(@NotNull Party firstParty, @NotNull Party secondParty) { + requireNonNull(firstParty, "firstParty cannot be null!"); + requireNonNull(secondParty, "secondParty cannot be null!"); + firstParty.setAlly(secondParty); secondParty.setAlly(firstParty); @@ -439,6 +469,10 @@ public void createAlliance(@NotNull Party firstParty, @NotNull Party secondParty } public boolean disbandAlliance(@NotNull Player player, @NotNull Party firstParty, @NotNull Party secondParty) { + requireNonNull(player, "player cannot be null!"); + requireNonNull(firstParty, "firstParty cannot be null!"); + requireNonNull(secondParty, "secondParty cannot be null!"); + if (!handlePartyChangeAllianceEvent(player, firstParty.getName(), secondParty.getName(), McMMOPartyAllianceChangeEvent.EventReason.DISBAND_ALLIANCE)) { return false; } @@ -448,6 +482,8 @@ public boolean disbandAlliance(@NotNull Player player, @NotNull Party firstParty } private void disbandAlliance(@NotNull Party firstParty, @NotNull Party secondParty) { + requireNonNull(firstParty, "firstParty cannot be null!"); + requireNonNull(secondParty, "secondParty cannot be null!"); firstParty.setAlly(null); secondParty.setAlly(null); @@ -467,6 +503,9 @@ private void disbandAlliance(@NotNull Party firstParty, @NotNull Party secondPar * @param party The party */ public void addToParty(@NotNull McMMOPlayer mcMMOPlayer, @NotNull Party party) { + requireNonNull(mcMMOPlayer, "mcMMOPlayer cannot be null!"); + requireNonNull(party, "party cannot be null!"); + Player player = mcMMOPlayer.getPlayer(); String playerName = player.getName(); @@ -483,6 +522,7 @@ public void addToParty(@NotNull McMMOPlayer mcMMOPlayer, @NotNull Party party) { * @return the leader of the party */ public @Nullable String getPartyLeaderName(@NotNull String partyName) { + requireNonNull(partyName, "partyName cannot be null!"); Party party = getParty(partyName); return party == null ? null : party.getLeader().getPlayerName(); @@ -495,6 +535,8 @@ public void addToParty(@NotNull McMMOPlayer mcMMOPlayer, @NotNull Party party) { * @param party The party */ public void setPartyLeader(@NotNull UUID uuid, @NotNull Party party) { + requireNonNull(uuid, "uuid cannot be null!"); + requireNonNull(party, "party cannot be null!"); OfflinePlayer player = pluginRef.getServer().getOfflinePlayer(uuid); UUID leaderUniqueId = party.getLeader().getUniqueId(); @@ -519,6 +561,7 @@ public void setPartyLeader(@NotNull UUID uuid, @NotNull Party party) { * @return true if the player can invite */ public boolean canInvite(@NotNull McMMOPlayer mcMMOPlayer) { + requireNonNull(mcMMOPlayer, "mcMMOPlayer cannot be null!"); Party party = mcMMOPlayer.getParty(); return !party.isLocked() || party.getLeader().getUniqueId().equals(mcMMOPlayer.getPlayer().getUniqueId()); @@ -532,6 +575,9 @@ public boolean canInvite(@NotNull McMMOPlayer mcMMOPlayer) { * @return true if a party with that name exists, false otherwise */ public boolean checkPartyExistence(@NotNull Player player, @NotNull String partyName) { + requireNonNull(player, "player cannot be null!"); + requireNonNull(partyName, "partyName cannot be null!"); + if (getParty(partyName) == null) { return false; } @@ -548,6 +594,9 @@ public boolean checkPartyExistence(@NotNull Player player, @NotNull String party * @return true if the party was joined successfully, false otherwise */ public boolean changeOrJoinParty(@NotNull McMMOPlayer mmoPlayer, @NotNull String newPartyName) { + requireNonNull(mmoPlayer, "mmoPlayer cannot be null!"); + requireNonNull(newPartyName, "newPartyName cannot be null!"); + final Player player = mmoPlayer.getPlayer(); if (mmoPlayer.inParty()) { @@ -571,6 +620,9 @@ public boolean changeOrJoinParty(@NotNull McMMOPlayer mmoPlayer, @NotNull String * @return true if they are in the same party, false otherwise */ public boolean inSameParty(@NotNull Player firstPlayer, @NotNull Player secondPlayer) { + requireNonNull(firstPlayer, "firstPlayer cannot be null!"); + requireNonNull(secondPlayer, "secondPlayer cannot be null!"); + //Profile not loaded if (UserManager.getPlayer(firstPlayer) == null) { return false; diff --git a/src/main/java/com/gmail/nossr50/runnables/SaveTimerTask.java b/src/main/java/com/gmail/nossr50/runnables/SaveTimerTask.java index d9822e1913..613f3ecee6 100644 --- a/src/main/java/com/gmail/nossr50/runnables/SaveTimerTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/SaveTimerTask.java @@ -2,7 +2,6 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.runnables.player.PlayerProfileSaveTask; import com.gmail.nossr50.util.CancellableRunnable; import com.gmail.nossr50.util.LogUtils; diff --git a/src/main/java/com/gmail/nossr50/runnables/items/TeleportationWarmup.java b/src/main/java/com/gmail/nossr50/runnables/items/TeleportationWarmup.java index 7490c4117f..25d809f596 100644 --- a/src/main/java/com/gmail/nossr50/runnables/items/TeleportationWarmup.java +++ b/src/main/java/com/gmail/nossr50/runnables/items/TeleportationWarmup.java @@ -3,7 +3,6 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.CancellableRunnable; import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.Misc; diff --git a/src/main/java/com/gmail/nossr50/runnables/party/PartyAutoKickTask.java b/src/main/java/com/gmail/nossr50/runnables/party/PartyAutoKickTask.java index 2db0c3c27a..1d662dba97 100644 --- a/src/main/java/com/gmail/nossr50/runnables/party/PartyAutoKickTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/party/PartyAutoKickTask.java @@ -2,7 +2,6 @@ import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.CancellableRunnable; import org.bukkit.OfflinePlayer; diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/RuptureTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/RuptureTask.java index f2e9c608f4..432d5a2964 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/RuptureTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/RuptureTask.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.runnables.skills; -import com.gmail.nossr50.datatypes.MobHealthbarType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.events.skills.rupture.McMMOEntityDamageByRuptureEvent; import com.gmail.nossr50.mcMMO; diff --git a/src/main/java/com/gmail/nossr50/skills/AlternateFiringSuperSkill.java b/src/main/java/com/gmail/nossr50/skills/AlternateFiringSuperSkill.java deleted file mode 100644 index f9691c353b..0000000000 --- a/src/main/java/com/gmail/nossr50/skills/AlternateFiringSuperSkill.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.gmail.nossr50.skills; - -public interface AlternateFiringSuperSkill { - int chargeSuper(); - - void fireSuper(); - - void resetCharge(); - - boolean isReadyToFire(); - - long lastChargeTime(); -} diff --git a/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java b/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java index 216a9485df..a64b023aff 100644 --- a/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java +++ b/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.skills.crossbows; import com.gmail.nossr50.datatypes.player.McMMOPlayer; -import com.gmail.nossr50.util.MetadataConstants; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.entity.Arrow; import org.bukkit.entity.Player; diff --git a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java index 09ddceadbb..60def74bff 100644 --- a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java @@ -4,7 +4,6 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.skills.AlternateFiringSuperSkill; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.MetadataConstants; import com.gmail.nossr50.util.Permissions; @@ -23,15 +22,11 @@ import static com.gmail.nossr50.util.skills.CombatUtils.delayArrowMetaCleanup; -public class CrossbowsManager extends SkillManager implements AlternateFiringSuperSkill { +public class CrossbowsManager extends SkillManager { public CrossbowsManager(McMMOPlayer mmoPlayer) { super(mmoPlayer, PrimarySkillType.CROSSBOWS); } - private long lastChargeTime = 0; - - private int crossbowSuperWindupState = 0; - public void handleRicochet(@NotNull Plugin pluginRef, @NotNull Arrow arrow, @NotNull Vector hitBlockNormal) { if(!arrow.isShotFromCrossbow()) return; @@ -110,38 +105,4 @@ public double poweredShot(double oldDamage) { return oldDamage; } } - - @Override - public int chargeSuper() { - if (lastChargeTime < System.currentTimeMillis() - 2000) { - crossbowSuperWindupState = 0; - } - - if (crossbowSuperWindupState < 3) { - crossbowSuperWindupState++; - } - - lastChargeTime = System.currentTimeMillis(); - return crossbowSuperWindupState; - } - - @Override - public void fireSuper() { - // TODO: Impl - } - - @Override - public void resetCharge() { - crossbowSuperWindupState = 0; - } - - @Override - public boolean isReadyToFire() { - return crossbowSuperWindupState == 3; - } - - @Override - public long lastChargeTime() { - return lastChargeTime; - } } diff --git a/src/main/java/com/gmail/nossr50/util/Permissions.java b/src/main/java/com/gmail/nossr50/util/Permissions.java index 9a5f1f6c23..6dcd9b800c 100644 --- a/src/main/java/com/gmail/nossr50/util/Permissions.java +++ b/src/main/java/com/gmail/nossr50/util/Permissions.java @@ -167,18 +167,11 @@ public static boolean customXpBoost(Permissible permissible, PrimarySkillType sk */ public static boolean skillEnabled(Permissible permissible, PrimarySkillType skill) { - // hack to disable tridents for now - if (skill == PrimarySkillType.TRIDENTS) - return false; - return permissible.hasPermission("mcmmo.skills." + skill.toString().toLowerCase(Locale.ENGLISH)); } public static boolean vanillaXpBoost(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.ability." + skill.toString().toLowerCase(Locale.ENGLISH) + ".vanillaxpboost"); } public static boolean isSubSkillEnabled(Permissible permissible, SubSkillType subSkillType) { - // hack to disable supers that aren't coded yet - if(subSkillType == SubSkillType.TRIDENTS_SUPER) - return false; return permissible.hasPermission(subSkillType.getPermissionNodeAddress()); } @@ -293,10 +286,6 @@ private static void addDynamicPermission(String permissionName, PermissionDefaul * @return true if the player has permission and has the skill unlocked */ public static boolean canUseSubSkill(@NotNull Player player, @NotNull SubSkillType subSkillType) { - // Hack to disable tridents for now - if (subSkillType.getParentSkill() == PrimarySkillType.TRIDENTS) - return false; - return isSubSkillEnabled(player, subSkillType) && RankUtils.hasUnlockedSubskill(player, subSkillType); } } diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index 711ef5ab39..a361595e0a 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -10,7 +10,6 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.metadata.MobMetaFlagType; import com.gmail.nossr50.metadata.MobMetadataService; -import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.runnables.skills.AwardCombatXpTask; import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager; import com.gmail.nossr50.skills.archery.ArcheryManager; @@ -46,17 +45,6 @@ private CombatUtils() {} return mcMMO.getMetadataService().getMobMetadataService(); } - // TODO: Unit tests - public static void processProjectileSkillSuperAbilityActivation(McMMOPlayer mmoPlayer, ItemStack heldItem) { - // TODO: Support archery super as well - if (heldItem != null && mmoPlayer != null) { - if (ItemUtils.isCrossbow(heldItem)) { - mmoPlayer.checkCrossbowAbilityActivation(); - } - } - } - - //Likely.. because who knows what plugins are throwing around public static boolean isDamageLikelyFromNormalCombat(@NotNull DamageCause damageCause) { return switch (damageCause) { case ENTITY_ATTACK, ENTITY_SWEEP_ATTACK, PROJECTILE -> true; diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java index e849c7a0fa..2012d60715 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java @@ -362,13 +362,7 @@ public static int getRepairAndSalvageQuantities(Material itemMaterial, Material * @param subSkillType target subskill * @return true if the player has permission and has the skill unlocked */ - public static boolean canUseSubskill(Player player, SubSkillType subSkillType) - { - requireNonNull(subSkillType, "subSkillType cannot be null"); - // hack to disable supers that aren't coded yet - if(subSkillType == SubSkillType.TRIDENTS_SUPER || subSkillType == SubSkillType.CROSSBOWS_SUPER_SHOTGUN) - return false; - + public static boolean canUseSubskill(Player player, @NotNull SubSkillType subSkillType) { return Permissions.isSubSkillEnabled(player, subSkillType) && RankUtils.hasUnlockedSubskill(player, subSkillType); } } diff --git a/src/main/resources/advanced.yml b/src/main/resources/advanced.yml index fb8d739dcf..7d56c4e37a 100644 --- a/src/main/resources/advanced.yml +++ b/src/main/resources/advanced.yml @@ -5,7 +5,7 @@ # For advanced users only! There is no need to change anything here. # # You can customize almost every aspect of every skill here. -# Its mainly here if you've customized the experience formula. +# It's mainly here if you've customized the experience formula. # Configure at what level you get better with certain abilities. # ##### @@ -20,7 +20,7 @@ Feedback: PlayerTips: true SkillCommand: BlankLinesAboveHeader: true - # If sendtitles is true messages will be sent using the title api (BIG TEXT ON SCREEN) + # If sendtitles is true, messages will be sent using the title api (BIG TEXT ON SCREEN) Events: XP: SendTitles: true diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 692914b355..c8ac353155 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -432,9 +432,6 @@ Crossbows.Skills.SSG.Other.On=&a{0}&2 used &Super Shotgun! Crossbows.SubSkill.PoweredShot.Name=Powered Shot Crossbows.SubSkill.PoweredShot.Description=Increases damage done with crossbows Crossbows.SubSkill.PoweredShot.Stat=Powered Shot Bonus Damage -Crossbows.SubSkill.SuperShotgun.Name=Super Shotgun -Crossbows.SubSkill.SuperShotgun.Description=Shoot dozens of arrows at once -Crossbows.SubSkill.SuperShotgun.Stat=Per Projectile damage &a{0} Crossbows.SubSkill.CrossbowsLimitBreak.Name=Crossbows Limit Break Crossbows.SubSkill.CrossbowsLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether it will boost damage in PVE. Crossbows.SubSkill.CrossbowsLimitBreak.Stat=Limit Break Max DMG @@ -451,9 +448,6 @@ Tridents.Ability.Lower=&7You lower your trident. Tridents.Ability.Ready=&3You &6ready&3 your Trident. Tridents.Skills.TA.Refresh=&aYour &eSuper &aability is refreshed! Tridents.Skills.TA.Other.On=&a{0}&2 used Trident &Super! -Tridents.SubSkill.SuperAbility.Name=Tridents Super Ability -Tridents.SubSkill.SuperAbility.Description=N/A -Tridents.SubSkill.SuperAbility.Stat=N/A Tridents.SubSkill.Impale.Name=Impale Tridents.SubSkill.Impale.Description=Increases damage done with tridents Tridents.SubSkill.Impale.Stat=Impale Bonus Damage @@ -462,6 +456,18 @@ Tridents.SubSkill.TridentsLimitBreak.Description=Breaking your limits. Increased Tridents.SubSkill.TridentsLimitBreak.Stat=Limit Break Max DMG Tridents.Listener=Tridents: +#MACES +Maces.SkillName=MACES +Maces.Ability.Lower=&7You lower your mace. +Maces.Ability.Ready=&3You &6ready&3 your Mace. +Maces.Skills.MaceSmash.Refresh=&aYour &eGiga Smash &aability is refreshed! +Maces.Skills.MaceSmash.Other.On=&a{0}&2 used &cGiga Smash! +Maces.SubSkill.GigaSmash.Name=Giga Smash +Maces.SubSkill.MacesLimitBreak.Name=Maces Limit Break +Maces.SubSkill.MacesLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether it will boost damage in PVE. +Maces.SubSkill.MacesLimitBreak.Stat=Limit Break Max DMG +Maces.Listener=Maces: + #SWORDS Swords.Ability.Lower=&7You lower your sword. Swords.Ability.Ready=&3You &6ready&3 your Sword. diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index a4dc5d4b20..198d465fc1 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -338,12 +338,9 @@ permissions: mcmmo.ability.crossbows.all: description: Allows access to all Crossbows abilities children: - mcmmo.ability.crossbows.supershotgun: true mcmmo.ability.crossbows.trickshot: true mcmmo.ability.crossbows.poweredshot: true mcmmo.ability.crossbows.crossbowslimitbreak: true - mcmmo.ability.crossbows.supershotgun: - description: Allows access to the Super Shotgun super ability mcmmo.ability.crossbows.crossbowslimitbreak: description: Adds damage to crossbows mcmmo.ability.crossbows.trickshot: @@ -722,11 +719,8 @@ permissions: mcmmo.ability.tridents.all: description: Allows access to all Trident abilities children: - mcmmo.ability.tridents.superability: true mcmmo.ability.tridents.impale: true mcmmo.ability.tridents.tridentslimitbreak: true - mcmmo.ability.tridents.superability: - description: Allows access to tridents super ability mcmmo.ability.tridents.impale: description: Allows access to tridents Impale ability mcmmo.ability.tridents.tridentslimitbreak: diff --git a/src/main/resources/skillranks.yml b/src/main/resources/skillranks.yml index a41e55fb12..590ddde118 100644 --- a/src/main/resources/skillranks.yml +++ b/src/main/resources/skillranks.yml @@ -31,11 +31,6 @@ Alchemy: Rank_7: 900 Rank_8: 1000 Archery: - ExplosiveShot: - Standard: - Rank_1: 5 - RetroMode: - Rank_1: 50 ArcheryLimitBreak: Standard: Rank_1: 10 @@ -282,11 +277,6 @@ Crossbows: Rank_8: 800 Rank_9: 900 Rank_10: 1000 - SuperShotgun: - Standard: - Rank_1: 5 - RetroMode: - Rank_1: 50 Tridents: TridentsLimitBreak: Standard: @@ -311,11 +301,6 @@ Tridents: Rank_8: 800 Rank_9: 900 Rank_10: 1000 - TridentsSuperAbility: - Standard: - Rank_1: 5 - RetroMode: - Rank_1: 50 Impale: Standard: Rank_1: 5 diff --git a/src/test/java/com/gmail/nossr50/party/PartyManagerTest.java b/src/test/java/com/gmail/nossr50/party/PartyManagerTest.java index 25d74515be..0d8f01ccb6 100644 --- a/src/test/java/com/gmail/nossr50/party/PartyManagerTest.java +++ b/src/test/java/com/gmail/nossr50/party/PartyManagerTest.java @@ -78,7 +78,7 @@ public void createPartyWithoutNameShouldFail() { when(player.getUniqueId()).thenReturn(new UUID(0, 0)); // When & Then - assertThrows(IllegalArgumentException.class, + assertThrows(NullPointerException.class, () -> partyManager.createParty(mmoPlayer, null, partyPassword)); } @@ -90,7 +90,7 @@ public void createPartyWithoutPlayerShouldFail() { String partyPassword = "somePassword"; // When & Then - assertThrows(IllegalArgumentException.class, + assertThrows(NullPointerException.class, () -> partyManager.createParty(null, partyName, partyPassword)); } From 221175d2d35369c7aaf988cabf32201774ae38cc Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sat, 30 Mar 2024 05:08:55 -0700 Subject: [PATCH 70/75] locale changes --- .../gmail/nossr50/commands/skills/CrossbowsCommand.java | 9 --------- src/main/resources/locale/locale_en_US.properties | 2 -- 2 files changed, 11 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java index 97bfcbc644..3b3ff230b9 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java @@ -17,7 +17,6 @@ import static com.gmail.nossr50.datatypes.skills.SubSkillType.*; public class CrossbowsCommand extends SkillCommand { - private boolean canSSG; private boolean canTrickShot; private boolean canPoweredShot; @@ -32,9 +31,6 @@ protected void dataCalculations(Player player, float skillValue) { @Override protected void permissionsCheck(Player player) { -// canSSG = RankUtils.hasUnlockedSubskill(player, CROSSBOWS_SUPER_SHOTGUN) -// && Permissions.superShotgun(player); - canTrickShot = RankUtils.hasUnlockedSubskill(player, CROSSBOWS_TRICK_SHOT) && Permissions.trickShot(player); @@ -58,11 +54,6 @@ protected List statsDisplay(Player player, float skillValue, boolean has messages.add(getStatMessage(ARCHERY_SKILL_SHOT, percent.format(mmoPlayer.getCrossbowsManager().getDamageBonusPercent(player)))); } -// if (canSSG) { -// messages.add("Super Shotgun"); -// //TODO: Implement SSG -// } - if (canTrickShot) { messages.add(getStatMessage(CROSSBOWS_TRICK_SHOT, String.valueOf(mmoPlayer.getCrossbowsManager().getTrickShotMaxBounceCount()))); diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index c8ac353155..9223462fd9 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -446,8 +446,6 @@ Crossbows.Listener=Crossbows: Tridents.SkillName=TRIDENTS Tridents.Ability.Lower=&7You lower your trident. Tridents.Ability.Ready=&3You &6ready&3 your Trident. -Tridents.Skills.TA.Refresh=&aYour &eSuper &aability is refreshed! -Tridents.Skills.TA.Other.On=&a{0}&2 used Trident &Super! Tridents.SubSkill.Impale.Name=Impale Tridents.SubSkill.Impale.Description=Increases damage done with tridents Tridents.SubSkill.Impale.Stat=Impale Bonus Damage From e9407246d70771b7ed2d22098f9332f6071feeb6 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sat, 30 Mar 2024 05:22:28 -0700 Subject: [PATCH 71/75] update note about WIP status on tridents/xbows --- .../gmail/nossr50/commands/skills/CrossbowsCommand.java | 5 ++--- .../com/gmail/nossr50/commands/skills/SkillCommand.java | 6 ------ .../gmail/nossr50/commands/skills/TridentsCommand.java | 9 +-------- src/main/resources/locale/locale_en_US.properties | 2 ++ 4 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java index 3b3ff230b9..6ef04eaaed 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java @@ -47,9 +47,6 @@ protected List statsDisplay(Player player, float skillValue, boolean has return messages; } - messages.add(ChatColor.DARK_AQUA + "Reminder: " + ChatColor.GOLD + "This is a BETA version of mcMMO, please report any bugs you find!"); - messages.add(ChatColor.GOLD + "Crossbows is a " + ChatColor.RED + "WIP" +ChatColor.GOLD + " skill that is still being developed, please leave feedback in our discord!"); - if (canPoweredShot) { messages.add(getStatMessage(ARCHERY_SKILL_SHOT, percent.format(mmoPlayer.getCrossbowsManager().getDamageBonusPercent(player)))); } @@ -64,6 +61,8 @@ protected List statsDisplay(Player player, float skillValue, boolean has String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, CROSSBOWS_CROSSBOWS_LIMIT_BREAK, 1000)))); } + messages.add(ChatColor.GRAY + "The Crossbows skill is a work in progress and is still being developed, feedback would be appreciated in the mcMMO discord server."); + return messages; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java index d48a6608d2..61b2f7ae43 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java @@ -62,12 +62,6 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command return true; } - // Tridents skill is not ready yet - if (skill == PrimarySkillType.TRIDENTS) { - sender.sendMessage(ChatColor.RED + "Tridents will come in a future version!"); - return true; - } - if (args.length == 0) { boolean isLucky = Permissions.lucky(player, skill); boolean hasEndurance = PerksUtils.handleActivationPerks(player, 0, 0) != 0; diff --git a/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java index 7ff5cc5bbe..ff4165659a 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java @@ -37,14 +37,6 @@ protected List statsDisplay(Player player, float skillValue, boolean has return messages; } - messages.add(ChatColor.DARK_AQUA + "Reminder: " + ChatColor.GOLD + "This is a BETA version of mcMMO, please report any bugs you find!"); - messages.add(ChatColor.GOLD + "Tridents is a " + ChatColor.RED + "WIP" +ChatColor.GOLD + " skill that is still being developed, please leave feedback in our discord!"); - -// if (SkillUtils.canUseSubskill(player, TRIDENTS_SUPER)) { -// messages.add("Tridents Super Ability"); -// //TODO: Implement Tridents Super -// } - if(SkillUtils.canUseSubskill(player, TRIDENTS_TRIDENTS_LIMIT_BREAK)) { messages.add(getStatMessage(TRIDENTS_TRIDENTS_LIMIT_BREAK, String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, TRIDENTS_TRIDENTS_LIMIT_BREAK, 1000)))); @@ -55,6 +47,7 @@ protected List statsDisplay(Player player, float skillValue, boolean has String.valueOf(mmoPlayer.getTridentsManager().impaleDamageBonus()))); } + messages.add(ChatColor.GRAY + "The Tridents skill is a work in progress and is still being developed, feedback would be appreciated in the mcMMO discord server."); return messages; } diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 9223462fd9..84316e4c5e 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -440,6 +440,7 @@ Crossbows.SubSkill.TrickShot.Description=Richochet arrows with steep angles Crossbows.SubSkill.TrickShot.Stat=Trick Shot Max Bounces Crossbows.SubSkill.TrickShot.Stat.Extra=Trick Shot Max Bounces: &a{0} Crossbows.SubSkill.TrickShot.Stat.Extra2=Trick Shot Reduced DMG per Bounce: &a{0} +Crossbows.SubSkill.SuperShotgun.Name=Super Shotgun Crossbows.Listener=Crossbows: #TRIDENTS @@ -452,6 +453,7 @@ Tridents.SubSkill.Impale.Stat=Impale Bonus Damage Tridents.SubSkill.TridentsLimitBreak.Name=Tridents Limit Break Tridents.SubSkill.TridentsLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether it will boost damage in PVE. Tridents.SubSkill.TridentsLimitBreak.Stat=Limit Break Max DMG +Tridents.SubSkill.TridentAbility.Name=WIP Tridents.Listener=Tridents: #MACES From 84cb6e3f7b82ca7e9de7292aaace25a1575831dc Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sat, 30 Mar 2024 05:35:02 -0700 Subject: [PATCH 72/75] add metadata cleanup for trick shot --- Changelog.txt | 3 --- .../java/com/gmail/nossr50/util/skills/ProjectileUtils.java | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 928cad658e..6f3911d241 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,9 +1,6 @@ Version 2.2.000 TODO: Add check to archery arrow retrieval to not work for crossbows - TODO: More SQL unit tests - TODO: Test mysql/mariadb changes TODO: Add metadata cleanup unit tests - TODO: Cleanup new arrow metadatas TODO: com/gmail/nossr50/database/FlatFileDatabaseManager.java:109 reporting data entries that need correction on each launch TODO: Add Xbows/Tridents to salvage/repair TODO: Add unit test for combat XP values diff --git a/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java b/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java index 6427117ae0..f64bac7a3e 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java @@ -48,6 +48,10 @@ public static void cleanupProjectileMetadata(@NotNull Arrow arrow) { if(arrow.hasMetadata(MetadataConstants.METADATA_KEY_MULTI_SHOT_ARROW)) { arrow.removeMetadata(MetadataConstants.METADATA_KEY_MULTI_SHOT_ARROW, mcMMO.p); } + + if(arrow.hasMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT)) { + arrow.removeMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT, mcMMO.p); + } } public static void copyArrowMetadata(@NotNull Plugin pluginRef, @NotNull Arrow arrowToCopy, @NotNull Arrow newArrow) { From 6d0fbfd02ed4d0b1697b7282c57621e0fb234e8e Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sat, 30 Mar 2024 05:39:25 -0700 Subject: [PATCH 73/75] updating changelog --- Changelog.txt | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 6f3911d241..0f87aacb1d 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,21 +1,19 @@ Version 2.2.000 - TODO: Add check to archery arrow retrieval to not work for crossbows - TODO: Add metadata cleanup unit tests - TODO: com/gmail/nossr50/database/FlatFileDatabaseManager.java:109 reporting data entries that need correction on each launch - TODO: Add Xbows/Tridents to salvage/repair - TODO: Add unit test for combat XP values - TODO: Add unit test to determine crossbow or bow skill - TODO: Add unit test for trident xp processing - TODO: Add missing entries to changelog - Tree Feller now drops 90% less non-wood blocks (leaves/etc) on average + New Things + 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 + + Config Changes 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 + + Balance Changes + Tree Feller now drops 90% less non-wood blocks (leaves/etc) on average Treasure drop rate from Shake, Fishing, Hylian, and Excavation now benefit from the Luck perk Added 'Send_To_Console' settings to chat.yml to toggle sending party or admin chat messages to console Added a set of "triple drop" sub skills to a few gathering skills, this is meant for "end game" progression Added the end game oriented subskill 'Mother Lode' to Mining Added the end game oriented subskill 'Clean Cuts' to Woodcutting Added the end game oriented subskill 'Verdant Bounty' to Herbalism - Added Crossbows Skill and various sub skills Updated advanced.yml with entries for the new skills (API) 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 Added /mmopower command (aliases /mmopowerlevel /powerlevel) From 39503b70383aa55770d0ce4e1e88c2100347cb35 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sat, 30 Mar 2024 05:44:02 -0700 Subject: [PATCH 74/75] Fix missing verdant bounty stat in herbalism command --- .../java/com/gmail/nossr50/commands/skills/HerbalismCommand.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java index 8bb236d391..8a5ce8d33b 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java @@ -104,6 +104,7 @@ protected void permissionsCheck(Player player) { canGreenThumbBlocks = RankUtils.hasUnlockedSubskill(player, SubSkillType.HERBALISM_GREEN_THUMB) && (Permissions.greenThumbBlock(player, Material.DIRT) || Permissions.greenThumbBlock(player, Material.COBBLESTONE) || Permissions.greenThumbBlock(player, Material.COBBLESTONE_WALL) || Permissions.greenThumbBlock(player, Material.STONE_BRICKS)); canFarmersDiet = Permissions.canUseSubSkill(player, SubSkillType.HERBALISM_FARMERS_DIET); canDoubleDrop = Permissions.canUseSubSkill(player, SubSkillType.HERBALISM_DOUBLE_DROPS) && !mcMMO.p.getGeneralConfig().getDoubleDropsDisabled(skill); + canTripleDrop = Permissions.canUseSubSkill(player, SubSkillType.HERBALISM_VERDANT_BOUNTY) && !mcMMO.p.getGeneralConfig().getDoubleDropsDisabled(skill); canShroomThumb = Permissions.canUseSubSkill(player, SubSkillType.HERBALISM_SHROOM_THUMB); } From 3e7c889f8f5517354aad924d137520fdec303b4f Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sat, 30 Mar 2024 06:03:25 -0700 Subject: [PATCH 75/75] mcMMO 2.2.000-RC1 candidate for release --- Changelog.txt | 65 ++++++++++--------- pom.xml | 2 +- .../commands/skills/PowerLevelCommand.java | 11 +--- 3 files changed, 36 insertions(+), 42 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 0f87aacb1d..f5b1f81afe 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,50 +1,53 @@ Version 2.2.000 - New Things + 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 Changes + 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 - Balance Changes - Tree Feller now drops 90% less non-wood blocks (leaves/etc) on average + 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 - Added 'Send_To_Console' settings to chat.yml to toggle sending party or admin chat messages to console - Added a set of "triple drop" sub skills to a few gathering skills, this is meant for "end game" progression - Added the end game oriented subskill 'Mother Lode' to Mining - Added the end game oriented subskill 'Clean Cuts' to Woodcutting - Added the end game oriented subskill 'Verdant Bounty' to Herbalism Updated advanced.yml with entries for the new skills - (API) 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 - Added /mmopower command (aliases /mmopowerlevel /powerlevel) - Added 'mcmmo.commands.mmopower' permission node + + 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 - Added 'mcmmo.commands.crossbows' permission node - Added 'mcmmo.ability.crossbows.supershotgun' permission node - Added 'mcmmo.ability.crossbows.trickshot' permission node - Added 'mcmmo.ability.crossbows.crossbowslimitbreak' permission node - Added 'mcmmo.commands.mmopower' permission node + + Locale Added locale entries for motherlode, cleancuts, and verdant bounty + + Codebase Major rewrite for how random chance was handled in the code - child.yml is gone now, its better this way + 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: - Crossbows is a WIP skill, and I will add to it in future updates. - Tridents is not ready for this update, so its been disabled for now. - The goal of this update is to provide a small benefit to some skills and a reason to grind past the "maximum", ideally for a long while. - Most skills have an end game oriented sub-skill, these new subskills provide a small benefit 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 end game sub skills unlock at level 1000 for RetroMode (the default setting), and 100 for Standard, you can edit this via skillranks.yml - These new sub skills are meant to provide an "end-game" to skills, a reason to continue leveling a skill past its "max". - This system is brand new, it is entirely possible I will completely change, remove, or add more mastery skills in the future. + One feature of this update is to provide a 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 for Mother Lode, Clean Cuts, Verdant Bounty: - These skills respect double drop settings from config.yml just like the Double Drop skills do - Double Drops and Triple Drops do not stack, mcMMO checks for triple drops first, then double drops - New Power Level Command, for now this skill just shows you your current power level. This might be removed later. - Currently these skills scale up to a maximum 50% chance if a player has 10,000 skill, you can adjust this in advanced.yml + 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 its 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. Version 2.1.231 Fixed a bug preventing parties from being made without passwords (Thanks Momshroom) @@ -2365,7 +2368,7 @@ Version 2.1.26 Notes: The new Limit Break subskills are intended to make Prot IV players less tanky and for you to feel more powerful for having high skill level. - Limit Break has 10 ranks, each rank gives 1 extra RAW damage, this is damage before reductions from armor and enchantments. The net result is you deal about 50% more damage with an end game skill compared to before. + Limit Break has 10 ranks, each rank gives 1 extra RAW damage, this is damage before reductions from armor and enchantments. The net result is you deal about 50% more damage with an endgame skill compared to before. With these new changes, most skills can 2 shot normal diamond armor, and it takes about 5 hits to kill someone in Prot IV Diamond Armor. I'm not sure everyone will like these changes, the net result is players are a lot easier to kill now, whereas before you could take quite a beating before getting killed. I collected several sets of data before making these changes, including damage to player with and without prot 4 diamond armor, damage to those players with and without enchanted weapons, damage with and without leveling your skills, and combinations of the previously mentioned things. diff --git a/pom.xml b/pom.xml index 5498b9f71f..2c5aea101a 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.2.000-BETA-08-SNAPSHOT + 2.2.000-RC1 mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java index 6b99e1fa27..639275b55d 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java @@ -35,15 +35,6 @@ public void processCommand(String[] args) { int powerLevel = mmoPlayer.getPowerLevel(); - //TODO: impl - mmoPlayer.getPlayer().sendMessage(ChatColor.DARK_AQUA + "Your " + ChatColor.GOLD + "[mcMMO]" + ChatColor.DARK_AQUA + " power level is: " + ChatColor.GREEN + powerLevel); //This is not gonna stay, just to show that the command executes in debug - - //Send the players a few blank lines to make finding the top of the skill command easier - if (mcMMO.p.getAdvancedConfig().doesSkillCommandSendBlankLines()) { - for (int i = 0; i < 1; i++) { - player.sendMessage(""); - } - } - + mmoPlayer.getPlayer().sendMessage(ChatColor.DARK_AQUA + "Your " + ChatColor.GOLD + "[mcMMO]" + ChatColor.DARK_AQUA + " power level is: " + ChatColor.GREEN + powerLevel); } }